diff options
Diffstat (limited to 'deps/v8/test/cctest/interpreter/test-interpreter.cc')
-rw-r--r-- | deps/v8/test/cctest/interpreter/test-interpreter.cc | 751 |
1 files changed, 681 insertions, 70 deletions
diff --git a/deps/v8/test/cctest/interpreter/test-interpreter.cc b/deps/v8/test/cctest/interpreter/test-interpreter.cc index d274fa73cb..506cf00cd0 100644 --- a/deps/v8/test/cctest/interpreter/test-interpreter.cc +++ b/deps/v8/test/cctest/interpreter/test-interpreter.cc @@ -2,9 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// TODO(rmcilroy): Remove this define after this flag is turned on globally -#define V8_IMMINENT_DEPRECATION_WARNINGS - #include "src/v8.h" #include "src/execution.h" @@ -67,9 +64,9 @@ class InterpreterTester { source_(source), bytecode_(bytecode), feedback_vector_(feedback_vector) { - i::FLAG_vector_stores = true; i::FLAG_ignition = true; i::FLAG_ignition_fake_try_catch = true; + i::FLAG_ignition_fallback_on_eval_and_catch = false; i::FLAG_always_opt = false; // Set ignition filter flag via SetFlagsFromString to avoid double-free // (or potential leak with StrDup() based on ownership confusion). @@ -344,7 +341,7 @@ TEST(InterpreterLoadLiteral) { TEST(InterpreterLoadStoreRegisters) { HandleAndZoneScope handles; Handle<Object> true_value = handles.main_isolate()->factory()->true_value(); - for (int i = 0; i <= Register::kMaxRegisterIndex; i++) { + for (int i = 0; i <= kMaxInt8; i++) { BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone()); builder.set_locals_count(i + 1); builder.set_context_count(0); @@ -365,6 +362,117 @@ TEST(InterpreterLoadStoreRegisters) { } +TEST(InterpreterExchangeRegisters) { + for (int locals_count = 2; locals_count < 300; locals_count += 126) { + HandleAndZoneScope handles; + for (int exchanges = 1; exchanges < 4; exchanges++) { + BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone()); + builder.set_locals_count(locals_count); + builder.set_context_count(0); + builder.set_parameter_count(0); + + Register r0(0); + Register r1(locals_count - 1); + builder.LoadTrue(); + builder.StoreAccumulatorInRegister(r0); + builder.ExchangeRegisters(r0, r1); + builder.LoadFalse(); + builder.StoreAccumulatorInRegister(r0); + + bool expected = false; + for (int i = 0; i < exchanges; i++) { + builder.ExchangeRegisters(r0, r1); + expected = !expected; + } + builder.LoadAccumulatorWithRegister(r0); + builder.Return(); + Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(); + InterpreterTester tester(handles.main_isolate(), bytecode_array); + auto callable = tester.GetCallable<>(); + Handle<Object> return_val = callable().ToHandleChecked(); + Handle<Object> expected_val = + handles.main_isolate()->factory()->ToBoolean(expected); + CHECK(return_val.is_identical_to(expected_val)); + } + } +} + + +TEST(InterpreterExchangeRegistersWithParameter) { + for (int locals_count = 2; locals_count < 300; locals_count += 126) { + HandleAndZoneScope handles; + for (int exchanges = 1; exchanges < 4; exchanges++) { + BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone()); + builder.set_locals_count(locals_count); + builder.set_context_count(0); + builder.set_parameter_count(3); + + Register r0 = Register::FromParameterIndex(2, 3); + Register r1(locals_count - 1); + builder.LoadTrue(); + builder.StoreAccumulatorInRegister(r0); + builder.ExchangeRegisters(r0, r1); + builder.LoadFalse(); + builder.StoreAccumulatorInRegister(r0); + + bool expected = false; + for (int i = 0; i < exchanges; i++) { + builder.ExchangeRegisters(r0, r1); + expected = !expected; + } + builder.LoadAccumulatorWithRegister(r0); + builder.Return(); + Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(); + InterpreterTester tester(handles.main_isolate(), bytecode_array); + auto callable = tester.GetCallable<>(); + Handle<Object> return_val = callable().ToHandleChecked(); + Handle<Object> expected_val = + handles.main_isolate()->factory()->ToBoolean(expected); + CHECK(return_val.is_identical_to(expected_val)); + } + } +} + + +TEST(InterpreterExchangeWideRegisters) { + for (int locals_count = 3; locals_count < 300; locals_count += 126) { + HandleAndZoneScope handles; + for (int exchanges = 0; exchanges < 7; exchanges++) { + BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone()); + builder.set_locals_count(locals_count); + builder.set_context_count(0); + builder.set_parameter_count(0); + + Register r0(0); + Register r1(locals_count - 1); + Register r2(locals_count - 2); + builder.LoadLiteral(Smi::FromInt(200)); + builder.StoreAccumulatorInRegister(r0); + builder.ExchangeRegisters(r0, r1); + builder.LoadLiteral(Smi::FromInt(100)); + builder.StoreAccumulatorInRegister(r0); + builder.ExchangeRegisters(r0, r2); + builder.LoadLiteral(Smi::FromInt(0)); + builder.StoreAccumulatorInRegister(r0); + for (int i = 0; i < exchanges; i++) { + builder.ExchangeRegisters(r1, r2); + builder.ExchangeRegisters(r0, r1); + } + builder.LoadAccumulatorWithRegister(r0); + builder.Return(); + Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(); + InterpreterTester tester(handles.main_isolate(), bytecode_array); + auto callable = tester.GetCallable<>(); + Handle<Object> return_val = callable().ToHandleChecked(); + Handle<Object> expected_val = + handles.main_isolate()->factory()->NewNumberFromInt(100 * + (exchanges % 3)); + CHECK(return_val.is_identical_to(expected_val)); + } + } +} + + static const Token::Value kShiftOperators[] = { Token::Value::SHL, Token::Value::SAR, Token::Value::SHR}; @@ -778,9 +886,8 @@ TEST(InterpreterLoadNamedProperty) { builder.set_locals_count(0); builder.set_context_count(0); builder.set_parameter_count(1); - size_t name_index = builder.GetConstantPoolEntry(name); - builder.LoadNamedProperty(builder.Parameter(0), name_index, - vector->GetIndex(slot), i::SLOPPY) + builder.LoadNamedProperty(builder.Parameter(0), name, vector->GetIndex(slot), + i::SLOPPY) .Return(); Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(); @@ -880,10 +987,9 @@ TEST(InterpreterStoreNamedProperty) { builder.set_locals_count(0); builder.set_context_count(0); builder.set_parameter_count(1); - size_t name_index = builder.GetConstantPoolEntry(name); builder.LoadLiteral(Smi::FromInt(999)) - .StoreNamedProperty(builder.Parameter(0), name_index, - vector->GetIndex(slot), i::STRICT) + .StoreNamedProperty(builder.Parameter(0), name, vector->GetIndex(slot), + i::STRICT) .Return(); Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(); @@ -995,11 +1101,9 @@ TEST(InterpreterCall) { builder.set_locals_count(1); builder.set_context_count(0); builder.set_parameter_count(1); - size_t name_index = builder.GetConstantPoolEntry(name); - builder.LoadNamedProperty(builder.Parameter(0), name_index, slot_index, - i::SLOPPY) + builder.LoadNamedProperty(builder.Parameter(0), name, slot_index, i::SLOPPY) .StoreAccumulatorInRegister(Register(0)) - .Call(Register(0), builder.Parameter(0), 0) + .Call(Register(0), builder.Parameter(0), 0, 0) .Return(); Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(); @@ -1018,11 +1122,9 @@ TEST(InterpreterCall) { builder.set_locals_count(1); builder.set_context_count(0); builder.set_parameter_count(1); - size_t name_index = builder.GetConstantPoolEntry(name); - builder.LoadNamedProperty(builder.Parameter(0), name_index, slot_index, - i::SLOPPY) + builder.LoadNamedProperty(builder.Parameter(0), name, slot_index, i::SLOPPY) .StoreAccumulatorInRegister(Register(0)) - .Call(Register(0), builder.Parameter(0), 0) + .Call(Register(0), builder.Parameter(0), 0, 0) .Return(); Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(); @@ -1044,9 +1146,7 @@ TEST(InterpreterCall) { builder.set_locals_count(4); builder.set_context_count(0); builder.set_parameter_count(1); - size_t name_index = builder.GetConstantPoolEntry(name); - builder.LoadNamedProperty(builder.Parameter(0), name_index, slot_index, - i::SLOPPY) + builder.LoadNamedProperty(builder.Parameter(0), name, slot_index, i::SLOPPY) .StoreAccumulatorInRegister(Register(0)) .LoadAccumulatorWithRegister(builder.Parameter(0)) .StoreAccumulatorInRegister(Register(1)) @@ -1054,7 +1154,7 @@ TEST(InterpreterCall) { .StoreAccumulatorInRegister(Register(2)) .LoadLiteral(Smi::FromInt(11)) .StoreAccumulatorInRegister(Register(3)) - .Call(Register(0), Register(1), 2) + .Call(Register(0), Register(1), 2, 0) .Return(); Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(); @@ -1075,9 +1175,7 @@ TEST(InterpreterCall) { builder.set_locals_count(12); builder.set_context_count(0); builder.set_parameter_count(1); - size_t name_index = builder.GetConstantPoolEntry(name); - builder.LoadNamedProperty(builder.Parameter(0), name_index, slot_index, - i::SLOPPY) + builder.LoadNamedProperty(builder.Parameter(0), name, slot_index, i::SLOPPY) .StoreAccumulatorInRegister(Register(0)) .LoadAccumulatorWithRegister(builder.Parameter(0)) .StoreAccumulatorInRegister(Register(1)) @@ -1101,7 +1199,7 @@ TEST(InterpreterCall) { .StoreAccumulatorInRegister(Register(10)) .LoadLiteral(factory->NewStringFromAsciiChecked("j")) .StoreAccumulatorInRegister(Register(11)) - .Call(Register(0), Register(1), 10) + .Call(Register(0), Register(1), 10, 0) .Return(); Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(); @@ -1245,8 +1343,8 @@ TEST(InterpreterConditionalJumps2) { static const Token::Value kComparisonTypes[] = { - Token::Value::EQ, Token::Value::NE, Token::Value::EQ_STRICT, - Token::Value::NE_STRICT, Token::Value::LTE, Token::Value::LTE, + Token::Value::EQ, Token::Value::NE, Token::Value::EQ_STRICT, + Token::Value::NE_STRICT, Token::Value::LT, Token::Value::LTE, Token::Value::GT, Token::Value::GTE}; @@ -1566,43 +1664,6 @@ static void LoadAny(BytecodeArrayBuilder* builder, } -TEST(InterpreterToBoolean) { - HandleAndZoneScope handles; - i::Factory* factory = handles.main_isolate()->factory(); - - std::pair<Handle<Object>, bool> object_type_tuples[] = { - std::make_pair(factory->undefined_value(), false), - std::make_pair(factory->null_value(), false), - std::make_pair(factory->false_value(), false), - std::make_pair(factory->true_value(), true), - std::make_pair(factory->NewNumber(9.1), true), - std::make_pair(factory->NewNumberFromInt(0), false), - std::make_pair( - Handle<Object>::cast(factory->NewStringFromStaticChars("hello")), - true), - std::make_pair( - Handle<Object>::cast(factory->NewStringFromStaticChars("")), false), - }; - - for (size_t i = 0; i < arraysize(object_type_tuples); i++) { - BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone()); - Register r0(0); - builder.set_locals_count(0); - builder.set_context_count(0); - builder.set_parameter_count(0); - LoadAny(&builder, factory, object_type_tuples[i].first); - builder.CastAccumulatorToBoolean(); - builder.Return(); - Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(); - InterpreterTester tester(handles.main_isolate(), bytecode_array); - auto callable = tester.GetCallable<>(); - Handle<Object> return_value = callable().ToHandleChecked(); - CHECK(return_value->IsBoolean()); - CHECK_EQ(return_value->BooleanValue(), object_type_tuples[i].second); - } -} - - TEST(InterpreterUnaryNotNonBoolean) { HandleAndZoneScope handles; i::Factory* factory = handles.main_isolate()->factory(); @@ -1883,7 +1944,11 @@ TEST(InterpreterContextVariables) { HandleAndZoneScope handles; i::Isolate* isolate = handles.main_isolate(); - std::pair<const char*, Handle<Object>> context_vars[] = { + std::ostringstream unique_vars; + for (int i = 0; i < 250; i++) { + unique_vars << "var a" << i << " = 0;"; + } + std::pair<std::string, Handle<Object>> context_vars[] = { std::make_pair("var a; (function() { a = 1; })(); return a;", handle(Smi::FromInt(1), isolate)), std::make_pair("var a = 10; (function() { a; })(); return a;", @@ -1898,10 +1963,14 @@ TEST(InterpreterContextVariables) { "{ let b = 20; var c = function() { [a, b] };\n" " return a + b; }", handle(Smi::FromInt(30), isolate)), + std::make_pair("'use strict';" + unique_vars.str() + + "eval(); var b = 100; return b;", + handle(Smi::FromInt(100), isolate)), }; for (size_t i = 0; i < arraysize(context_vars); i++) { - std::string source(InterpreterTester::SourceForBody(context_vars[i].first)); + std::string source( + InterpreterTester::SourceForBody(context_vars[i].first.c_str())); InterpreterTester tester(handles.main_isolate(), source.c_str()); auto callable = tester.GetCallable<>(); @@ -2162,6 +2231,19 @@ TEST(InterpreterCountOperators) { handle(Smi::FromInt(3), isolate)), std::make_pair("var a = 1; (function() { a = 2 })(); return a--;", handle(Smi::FromInt(2), isolate)), + std::make_pair("var i = 5; while(i--) {}; return i;", + handle(Smi::FromInt(-1), isolate)), + std::make_pair("var i = 1; if(i--) { return 1; } else { return 2; };", + handle(Smi::FromInt(1), isolate)), + std::make_pair("var i = -2; do {} while(i++) {}; return i;", + handle(Smi::FromInt(1), isolate)), + std::make_pair("var i = -1; for(; i++; ) {}; return i", + handle(Smi::FromInt(1), isolate)), + std::make_pair("var i = 20; switch(i++) {\n" + " case 20: return 1;\n" + " default: return 2;\n" + "}", + handle(Smi::FromInt(1), isolate)), }; for (size_t i = 0; i < arraysize(count_ops); i++) { @@ -2618,7 +2700,6 @@ TEST(InterpreterBasicLoops) { TEST(InterpreterForIn) { HandleAndZoneScope handles; - // TODO(oth): Add a test here for delete mid-loop when delete is ready. std::pair<const char*, int> for_in_samples[] = { {"function f() {\n" " var r = -1;\n" @@ -2795,7 +2876,27 @@ TEST(InterpreterForIn) { " }\n" " return flags;\n" " }", - 0}}; + 0}, + {"function f() {\n" + " var data = {x:23, y:34};\n" + " var result = 0;\n" + " var o = {};\n" + " var arr = [o];\n" + " for (arr[0].p in data)\n" // This is to test if value is loaded + " result += data[arr[0].p];\n" // back from accumulator before storing + " return result;\n" // named properties. + "}", + 57}, + {"function f() {\n" + " var data = {x:23, y:34};\n" + " var result = 0;\n" + " var o = {};\n" + " var i = 0;\n" + " for (o[i++] in data)\n" // This is to test if value is loaded + " result += data[o[i-1]];\n" // back from accumulator before + " return result;\n" // storing keyed properties. + "}", + 57}}; for (size_t i = 0; i < arraysize(for_in_samples); i++) { InterpreterTester tester(handles.main_isolate(), for_in_samples[i].first); @@ -2951,6 +3052,516 @@ TEST(InterpreterNewTarget) { CHECK(new_target_name->SameValue(*factory->NewStringFromStaticChars("f"))); } + +TEST(InterpreterAssignmentInExpressions) { + HandleAndZoneScope handles; + + std::pair<const char*, int> samples[] = { + {"function f() {\n" + " var x = 7;\n" + " var y = x + (x = 1) + (x = 2);\n" + " return y;\n" + "}", + 10}, + {"function f() {\n" + " var x = 7;\n" + " var y = x + (x = 1) + (x = 2);\n" + " return x;\n" + "}", + 2}, + {"function f() {\n" + " var x = 55;\n" + " x = x + (x = 100) + (x = 101);\n" + " return x;\n" + "}", + 256}, + {"function f() {\n" + " var x = 7;\n" + " return ++x + x + x++;\n" + "}", + 24}, + {"function f() {\n" + " var x = 7;\n" + " var y = 1 + ++x + x + x++;\n" + " return x;\n" + "}", + 9}, + {"function f() {\n" + " var x = 7;\n" + " var y = ++x + x + x++;\n" + " return x;\n" + "}", + 9}, + {"function f() {\n" + " var x = 7, y = 100, z = 1000;\n" + " return x + (x += 3) + y + (y *= 10) + (z *= 7) + z;\n" + "}", + 15117}, + {"function f() {\n" + " var inner = function (x) { return x + (x = 2) + (x = 4) + x; };\n" + " return inner(1);\n" + "}", + 11}, + {"function f() {\n" + " var x = 1, y = 2;\n" + " x = x + (x = 3) + y + (y = 4), y = y + (y = 5) + y + x;\n" + " return x + y;\n" + "}", + 10 + 24}, + {"function f() {\n" + " var x = 0;\n" + " var y = x | (x = 1) | (x = 2);\n" + " return x;\n" + "}", + 2}, + {"function f() {\n" + " var x = 0;\n" + " var y = x || (x = 1);\n" + " return x;\n" + "}", + 1}, + {"function f() {\n" + " var x = 1;\n" + " var y = x && (x = 2) && (x = 3);\n" + " return x;\n" + "}", + 3}, + {"function f() {\n" + " var x = 1;\n" + " var y = x || (x = 2);\n" + " return x;\n" + "}", + 1}, + {"function f() {\n" + " var x = 1;\n" + " x = (x << (x = 3)) | (x = 16);\n" + " return x;\n" + "}", + 24}, + {"function f() {\n" + " var r = 7;\n" + " var s = 11;\n" + " var t = 13;\n" + " var u = r + s + t + (r = 10) + (s = 20) +" + " (t = (r + s)) + r + s + t;\n" + " return r + s + t + u;\n" + "}", + 211}, + {"function f() {\n" + " var r = 7;\n" + " var s = 11;\n" + " var t = 13;\n" + " return r > (3 * s * (s = 1)) ? (t + (t += 1)) : (r + (r = 4));\n" + "}", + 11}, + {"function f() {\n" + " var r = 7;\n" + " var s = 11;\n" + " var t = 13;\n" + " return r > (3 * s * (s = 0)) ? (t + (t += 1)) : (r + (r = 4));\n" + "}", + 27}, + {"function f() {\n" + " var r = 7;\n" + " var s = 11;\n" + " var t = 13;\n" + " return (r + (r = 5)) > s ? r : t;\n" + "}", + 5}, + {"function f(a) {\n" + " return a + (arguments[0] = 10);\n" + "}", + 50}, + {"function f(a) {\n" + " return a + (arguments[0] = 10) + a;\n" + "}", + 60}, + {"function f(a) {\n" + " return a + (arguments[0] = 10) + arguments[0];\n" + "}", + 60}, + }; + + const int arg_value = 40; + for (size_t i = 0; i < arraysize(samples); i++) { + InterpreterTester tester(handles.main_isolate(), samples[i].first); + auto callable = tester.GetCallable<Handle<Object>>(); + Handle<Object> return_val = + callable(handle(Smi::FromInt(arg_value), handles.main_isolate())) + .ToHandleChecked(); + CHECK_EQ(Handle<Smi>::cast(return_val)->value(), samples[i].second); + } +} + + +TEST(InterpreterToName) { + HandleAndZoneScope handles; + i::Isolate* isolate = handles.main_isolate(); + i::Factory* factory = isolate->factory(); + + std::pair<const char*, Handle<Object>> to_name_tests[] = { + {"var a = 'val'; var obj = {[a] : 10}; return obj.val;", + factory->NewNumberFromInt(10)}, + {"var a = 20; var obj = {[a] : 10}; return obj['20'];", + factory->NewNumberFromInt(10)}, + {"var a = 20; var obj = {[a] : 10}; return obj[20];", + factory->NewNumberFromInt(10)}, + {"var a = {val:23}; var obj = {[a] : 10}; return obj[a];", + factory->NewNumberFromInt(10)}, + {"var a = {val:23}; var obj = {[a] : 10};\n" + "return obj['[object Object]'];", + factory->NewNumberFromInt(10)}, + {"var a = {toString : function() { return 'x'}};\n" + "var obj = {[a] : 10};\n" + "return obj.x;", + factory->NewNumberFromInt(10)}, + {"var a = {valueOf : function() { return 'x'}};\n" + "var obj = {[a] : 10};\n" + "return obj.x;", + factory->undefined_value()}, + {"var a = {[Symbol.toPrimitive] : function() { return 'x'}};\n" + "var obj = {[a] : 10};\n" + "return obj.x;", + factory->NewNumberFromInt(10)}, + }; + + for (size_t i = 0; i < arraysize(to_name_tests); i++) { + std::string source( + InterpreterTester::SourceForBody(to_name_tests[i].first)); + InterpreterTester tester(handles.main_isolate(), source.c_str()); + auto callable = tester.GetCallable<>(); + + Handle<i::Object> return_value = callable().ToHandleChecked(); + CHECK(return_value->SameValue(*to_name_tests[i].second)); + } +} + + +TEST(TemporaryRegisterAllocation) { + HandleAndZoneScope handles; + i::Isolate* isolate = handles.main_isolate(); + i::Factory* factory = isolate->factory(); + + std::pair<const char*, Handle<Object>> reg_tests[] = { + {"function add(a, b, c) {" + " return a + b + c;" + "}" + "function f() {" + " var a = 10, b = 10;" + " return add(a, b++, b);" + "}", + factory->NewNumberFromInt(31)}, + {"function add(a, b, c, d) {" + " return a + b + c + d;" + "}" + "function f() {" + " var x = 10, y = 20, z = 30;" + " return x + add(x, (y= x++), x, z);" + "}", + factory->NewNumberFromInt(71)}, + }; + + for (size_t i = 0; i < arraysize(reg_tests); i++) { + InterpreterTester tester(handles.main_isolate(), reg_tests[i].first); + auto callable = tester.GetCallable<>(); + + Handle<i::Object> return_value = callable().ToHandleChecked(); + CHECK(return_value->SameValue(*reg_tests[i].second)); + } +} + + +TEST(InterpreterLookupSlot) { + HandleAndZoneScope handles; + i::Isolate* isolate = handles.main_isolate(); + i::Factory* factory = isolate->factory(); + + // TODO(mythria): Add more tests when we have support for eval/with. + const char* function_prologue = "var f;" + "var x = 1;" + "function f1() {" + " eval(\"function t() {"; + const char* function_epilogue = " }; f = t;\");" + "}" + "f1();"; + + + std::pair<const char*, Handle<Object>> lookup_slot[] = { + {"return x;", handle(Smi::FromInt(1), isolate)}, + {"return typeof x;", factory->NewStringFromStaticChars("number")}, + {"return typeof dummy;", factory->NewStringFromStaticChars("undefined")}, + {"x = 10; return x;", handle(Smi::FromInt(10), isolate)}, + {"'use strict'; x = 20; return x;", handle(Smi::FromInt(20), isolate)}, + }; + + for (size_t i = 0; i < arraysize(lookup_slot); i++) { + std::string script = std::string(function_prologue) + + std::string(lookup_slot[i].first) + + std::string(function_epilogue); + + InterpreterTester tester(handles.main_isolate(), script.c_str(), "t"); + auto callable = tester.GetCallable<>(); + + Handle<i::Object> return_value = callable().ToHandleChecked(); + CHECK(return_value->SameValue(*lookup_slot[i].second)); + } +} + + +TEST(InterpreterCallLookupSlot) { + HandleAndZoneScope handles; + i::Isolate* isolate = handles.main_isolate(); + + std::pair<const char*, Handle<Object>> call_lookup[] = { + {"g = function(){ return 2 }; eval(''); return g();", + handle(Smi::FromInt(2), isolate)}, + {"g = function(){ return 2 }; eval('g = function() {return 3}');\n" + "return g();", + handle(Smi::FromInt(3), isolate)}, + {"g = { x: function(){ return this.y }, y: 20 };\n" + "eval('g = { x: g.x, y: 30 }');\n" + "return g.x();", + handle(Smi::FromInt(30), isolate)}, + }; + + for (size_t i = 0; i < arraysize(call_lookup); i++) { + std::string source(InterpreterTester::SourceForBody(call_lookup[i].first)); + InterpreterTester tester(handles.main_isolate(), source.c_str()); + auto callable = tester.GetCallable<>(); + + Handle<i::Object> return_value = callable().ToHandleChecked(); + CHECK(return_value->SameValue(*call_lookup[i].second)); + } +} + + +TEST(InterpreterLookupSlotWide) { + HandleAndZoneScope handles; + i::Isolate* isolate = handles.main_isolate(); + i::Factory* factory = isolate->factory(); + + const char* function_prologue = + "var f;" + "var x = 1;" + "function f1() {" + " eval(\"function t() {"; + const char* function_epilogue = + " }; f = t;\");" + "}" + "f1();"; + std::ostringstream str; + str << "var y = 2.3;"; + for (int i = 1; i < 256; i++) { + str << "y = " << 2.3 + i << ";"; + } + std::string init_function_body = str.str(); + + std::pair<std::string, Handle<Object>> lookup_slot[] = { + {init_function_body + "return x;", handle(Smi::FromInt(1), isolate)}, + {init_function_body + "return typeof x;", + factory->NewStringFromStaticChars("number")}, + {init_function_body + "return x = 10;", + handle(Smi::FromInt(10), isolate)}, + {"'use strict';" + init_function_body + "x = 20; return x;", + handle(Smi::FromInt(20), isolate)}, + }; + + for (size_t i = 0; i < arraysize(lookup_slot); i++) { + std::string script = std::string(function_prologue) + lookup_slot[i].first + + std::string(function_epilogue); + + InterpreterTester tester(handles.main_isolate(), script.c_str(), "t"); + auto callable = tester.GetCallable<>(); + + Handle<i::Object> return_value = callable().ToHandleChecked(); + CHECK(return_value->SameValue(*lookup_slot[i].second)); + } +} + + +TEST(InterpreterDeleteLookupSlot) { + HandleAndZoneScope handles; + i::Isolate* isolate = handles.main_isolate(); + i::Factory* factory = isolate->factory(); + + // TODO(mythria): Add more tests when we have support for eval/with. + const char* function_prologue = "var f;" + "var x = 1;" + "y = 10;" + "var obj = {val:10};" + "var z = 30;" + "function f1() {" + " var z = 20;" + " eval(\"function t() {"; + const char* function_epilogue = " }; f = t;\");" + "}" + "f1();"; + + + std::pair<const char*, Handle<Object>> delete_lookup_slot[] = { + {"return delete x;", factory->false_value()}, + {"return delete y;", factory->true_value()}, + {"return delete z;", factory->false_value()}, + {"return delete obj.val;", factory->true_value()}, + {"'use strict'; return delete obj.val;", factory->true_value()}, + }; + + for (size_t i = 0; i < arraysize(delete_lookup_slot); i++) { + std::string script = std::string(function_prologue) + + std::string(delete_lookup_slot[i].first) + + std::string(function_epilogue); + + InterpreterTester tester(handles.main_isolate(), script.c_str(), "t"); + auto callable = tester.GetCallable<>(); + + Handle<i::Object> return_value = callable().ToHandleChecked(); + CHECK(return_value->SameValue(*delete_lookup_slot[i].second)); + } +} + + +TEST(JumpWithConstantsAndWideConstants) { + HandleAndZoneScope handles; + auto isolate = handles.main_isolate(); + auto factory = isolate->factory(); + const int kStep = 13; + for (int constants = 3; constants < 256 + 3 * kStep; constants += kStep) { + std::ostringstream filler_os; + // Generate a string that consumes constant pool entries and + // spread out branch distances in script below. + for (int i = 0; i < constants; i++) { + filler_os << "var x_ = 'x_" << i << "';\n"; + } + std::string filler(filler_os.str()); + std::ostringstream script_os; + script_os << "function " << InterpreterTester::function_name() << "(a) {\n"; + script_os << " " << filler; + script_os << " for (var i = a; i < 2; i++) {\n"; + script_os << " " << filler; + script_os << " if (i == 0) { " << filler << "i = 10; continue; }\n"; + script_os << " else if (i == a) { " << filler << "i = 12; break; }\n"; + script_os << " else { " << filler << " }\n"; + script_os << " }\n"; + script_os << " return i;\n"; + script_os << "}\n"; + std::string script(script_os.str()); + for (int a = 0; a < 3; a++) { + InterpreterTester tester(handles.main_isolate(), script.c_str()); + auto callable = tester.GetCallable<Handle<Object>>(); + Handle<Object> return_val = + callable(factory->NewNumberFromInt(a)).ToHandleChecked(); + static const int results[] = {11, 12, 2}; + CHECK_EQ(Handle<Smi>::cast(return_val)->value(), results[a]); + } + } +} + + +TEST(InterpreterEval) { + HandleAndZoneScope handles; + i::Isolate* isolate = handles.main_isolate(); + i::Factory* factory = isolate->factory(); + + std::pair<const char*, Handle<Object>> eval[] = { + {"return eval('1;');", handle(Smi::FromInt(1), isolate)}, + {"return eval('100 * 20;');", handle(Smi::FromInt(2000), isolate)}, + {"var x = 10; return eval('x + 20;');", + handle(Smi::FromInt(30), isolate)}, + {"var x = 10; eval('x = 33;'); return x;", + handle(Smi::FromInt(33), isolate)}, + {"'use strict'; var x = 20; var z = 0;\n" + "eval('var x = 33; z = x;'); return x + z;", + handle(Smi::FromInt(53), isolate)}, + {"eval('var x = 33;'); eval('var y = x + 20'); return x + y;", + handle(Smi::FromInt(86), isolate)}, + {"var x = 1; eval('for(i = 0; i < 10; i++) x = x + 1;'); return x", + handle(Smi::FromInt(11), isolate)}, + {"var x = 10; eval('var x = 20;'); return x;", + handle(Smi::FromInt(20), isolate)}, + {"var x = 1; eval('\"use strict\"; var x = 2;'); return x;", + handle(Smi::FromInt(1), isolate)}, + {"'use strict'; var x = 1; eval('var x = 2;'); return x;", + handle(Smi::FromInt(1), isolate)}, + {"var x = 10; eval('x + 20;'); return typeof x;", + factory->NewStringFromStaticChars("number")}, + {"eval('var y = 10;'); return typeof unallocated;", + factory->NewStringFromStaticChars("undefined")}, + {"'use strict'; eval('var y = 10;'); return typeof unallocated;", + factory->NewStringFromStaticChars("undefined")}, + {"eval('var x = 10;'); return typeof x;", + factory->NewStringFromStaticChars("number")}, + {"var x = {}; eval('var x = 10;'); return typeof x;", + factory->NewStringFromStaticChars("number")}, + {"'use strict'; var x = {}; eval('var x = 10;'); return typeof x;", + factory->NewStringFromStaticChars("object")}, + }; + + for (size_t i = 0; i < arraysize(eval); i++) { + std::string source(InterpreterTester::SourceForBody(eval[i].first)); + InterpreterTester tester(handles.main_isolate(), source.c_str()); + auto callable = tester.GetCallable<>(); + + Handle<i::Object> return_value = callable().ToHandleChecked(); + CHECK(return_value->SameValue(*eval[i].second)); + } +} + + +TEST(InterpreterEvalParams) { + HandleAndZoneScope handles; + i::Isolate* isolate = handles.main_isolate(); + + std::pair<const char*, Handle<Object>> eval_params[] = { + {"var x = 10; return eval('x + p1;');", + handle(Smi::FromInt(30), isolate)}, + {"var x = 10; eval('p1 = x;'); return p1;", + handle(Smi::FromInt(10), isolate)}, + {"var a = 10;" + "function inner() { return eval('a + p1;');}" + "return inner();", + handle(Smi::FromInt(30), isolate)}, + }; + + for (size_t i = 0; i < arraysize(eval_params); i++) { + std::string source = "function " + InterpreterTester::function_name() + + "(p1) {" + eval_params[i].first + "}"; + InterpreterTester tester(handles.main_isolate(), source.c_str()); + auto callable = tester.GetCallable<Handle<Object>>(); + + Handle<i::Object> return_value = + callable(handle(Smi::FromInt(20), isolate)).ToHandleChecked(); + CHECK(return_value->SameValue(*eval_params[i].second)); + } +} + + +TEST(InterpreterEvalGlobal) { + HandleAndZoneScope handles; + i::Isolate* isolate = handles.main_isolate(); + i::Factory* factory = isolate->factory(); + + std::pair<const char*, Handle<Object>> eval_global[] = { + {"function add_global() { eval('function test() { z = 33; }; test()'); };" + "function f() { add_global(); return z; }; f();", + handle(Smi::FromInt(33), isolate)}, + {"function add_global() {\n" + " eval('\"use strict\"; function test() { y = 33; };" + " try { test() } catch(e) {}');\n" + "}\n" + "function f() { add_global(); return typeof y; } f();", + factory->NewStringFromStaticChars("undefined")}, + }; + + for (size_t i = 0; i < arraysize(eval_global); i++) { + InterpreterTester tester(handles.main_isolate(), eval_global[i].first, + "test"); + auto callable = tester.GetCallable<>(); + + Handle<i::Object> return_value = callable().ToHandleChecked(); + CHECK(return_value->SameValue(*eval_global[i].second)); + } +} + } // namespace interpreter } // namespace internal } // namespace v8 |