Line data Source code
1 : // Copyright 2015 the V8 project authors. All rights reserved.
2 : // Use of this source code is governed by a BSD-style license that can be
3 : // found in the LICENSE file.
4 :
5 : #include <tuple>
6 :
7 : #include "src/v8.h"
8 :
9 : #include "src/api-inl.h"
10 : #include "src/base/overflowing-math.h"
11 : #include "src/compiler.h"
12 : #include "src/execution.h"
13 : #include "src/handles.h"
14 : #include "src/hash-seed-inl.h"
15 : #include "src/heap/heap-inl.h"
16 : #include "src/interpreter/bytecode-array-builder.h"
17 : #include "src/interpreter/bytecode-array-iterator.h"
18 : #include "src/interpreter/bytecode-flags.h"
19 : #include "src/interpreter/bytecode-label.h"
20 : #include "src/interpreter/interpreter.h"
21 : #include "src/objects-inl.h"
22 : #include "src/objects/heap-number-inl.h"
23 : #include "src/objects/smi.h"
24 : #include "test/cctest/cctest.h"
25 : #include "test/cctest/interpreter/interpreter-tester.h"
26 : #include "test/cctest/test-feedback-vector.h"
27 :
28 : namespace v8 {
29 : namespace internal {
30 : namespace interpreter {
31 :
32 : static int GetIndex(FeedbackSlot slot) {
33 : return FeedbackVector::GetIndex(slot);
34 : }
35 :
36 : using ToBooleanMode = BytecodeArrayBuilder::ToBooleanMode;
37 :
38 26661 : TEST(InterpreterReturn) {
39 10 : HandleAndZoneScope handles;
40 : Isolate* isolate = handles.main_isolate();
41 : Zone* zone = handles.main_zone();
42 : Handle<Object> undefined_value = isolate->factory()->undefined_value();
43 :
44 10 : BytecodeArrayBuilder builder(zone, 1, 0);
45 5 : builder.Return();
46 5 : Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(isolate);
47 :
48 10 : InterpreterTester tester(isolate, bytecode_array);
49 : auto callable = tester.GetCallable<>();
50 : Handle<Object> return_val = callable().ToHandleChecked();
51 5 : CHECK(return_val.is_identical_to(undefined_value));
52 5 : }
53 :
54 26661 : TEST(InterpreterLoadUndefined) {
55 10 : HandleAndZoneScope handles;
56 : Isolate* isolate = handles.main_isolate();
57 : Zone* zone = handles.main_zone();
58 : Handle<Object> undefined_value = isolate->factory()->undefined_value();
59 :
60 10 : BytecodeArrayBuilder builder(zone, 1, 0);
61 5 : builder.LoadUndefined().Return();
62 5 : Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(isolate);
63 :
64 10 : InterpreterTester tester(isolate, bytecode_array);
65 : auto callable = tester.GetCallable<>();
66 : Handle<Object> return_val = callable().ToHandleChecked();
67 5 : CHECK(return_val.is_identical_to(undefined_value));
68 5 : }
69 :
70 26661 : TEST(InterpreterLoadNull) {
71 10 : HandleAndZoneScope handles;
72 : Isolate* isolate = handles.main_isolate();
73 : Zone* zone = handles.main_zone();
74 : Handle<Object> null_value = isolate->factory()->null_value();
75 :
76 10 : BytecodeArrayBuilder builder(zone, 1, 0);
77 5 : builder.LoadNull().Return();
78 5 : Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(isolate);
79 :
80 10 : InterpreterTester tester(isolate, bytecode_array);
81 : auto callable = tester.GetCallable<>();
82 : Handle<Object> return_val = callable().ToHandleChecked();
83 5 : CHECK(return_val.is_identical_to(null_value));
84 5 : }
85 :
86 26661 : TEST(InterpreterLoadTheHole) {
87 10 : HandleAndZoneScope handles;
88 : Isolate* isolate = handles.main_isolate();
89 : Zone* zone = handles.main_zone();
90 : Handle<Object> the_hole_value = isolate->factory()->the_hole_value();
91 :
92 10 : BytecodeArrayBuilder builder(zone, 1, 0);
93 5 : builder.LoadTheHole().Return();
94 5 : Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(isolate);
95 :
96 10 : InterpreterTester tester(isolate, bytecode_array);
97 : auto callable = tester.GetCallable<>();
98 : Handle<Object> return_val = callable().ToHandleChecked();
99 5 : CHECK(return_val.is_identical_to(the_hole_value));
100 5 : }
101 :
102 26661 : TEST(InterpreterLoadTrue) {
103 10 : HandleAndZoneScope handles;
104 : Isolate* isolate = handles.main_isolate();
105 : Zone* zone = handles.main_zone();
106 : Handle<Object> true_value = isolate->factory()->true_value();
107 :
108 10 : BytecodeArrayBuilder builder(zone, 1, 0);
109 5 : builder.LoadTrue().Return();
110 5 : Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(isolate);
111 :
112 10 : InterpreterTester tester(isolate, bytecode_array);
113 : auto callable = tester.GetCallable<>();
114 : Handle<Object> return_val = callable().ToHandleChecked();
115 5 : CHECK(return_val.is_identical_to(true_value));
116 5 : }
117 :
118 26661 : TEST(InterpreterLoadFalse) {
119 10 : HandleAndZoneScope handles;
120 : Isolate* isolate = handles.main_isolate();
121 : Zone* zone = handles.main_zone();
122 : Handle<Object> false_value = isolate->factory()->false_value();
123 :
124 10 : BytecodeArrayBuilder builder(zone, 1, 0);
125 5 : builder.LoadFalse().Return();
126 5 : Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(isolate);
127 :
128 10 : InterpreterTester tester(isolate, bytecode_array);
129 : auto callable = tester.GetCallable<>();
130 : Handle<Object> return_val = callable().ToHandleChecked();
131 5 : CHECK(return_val.is_identical_to(false_value));
132 5 : }
133 :
134 26661 : TEST(InterpreterLoadLiteral) {
135 10 : HandleAndZoneScope handles;
136 : Isolate* isolate = handles.main_isolate();
137 : Zone* zone = handles.main_zone();
138 :
139 : // Small Smis.
140 2565 : for (int i = -128; i < 128; i++) {
141 2560 : BytecodeArrayBuilder builder(zone, 1, 0);
142 1280 : builder.LoadLiteral(Smi::FromInt(i)).Return();
143 1280 : Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(isolate);
144 :
145 2560 : InterpreterTester tester(isolate, bytecode_array);
146 : auto callable = tester.GetCallable<>();
147 : Handle<Object> return_val = callable().ToHandleChecked();
148 1280 : CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(i));
149 : }
150 :
151 : // Large Smis.
152 : {
153 10 : BytecodeArrayBuilder builder(zone, 1, 0);
154 :
155 5 : builder.LoadLiteral(Smi::FromInt(0x12345678)).Return();
156 5 : Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(isolate);
157 :
158 10 : InterpreterTester tester(isolate, bytecode_array);
159 : auto callable = tester.GetCallable<>();
160 : Handle<Object> return_val = callable().ToHandleChecked();
161 5 : CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(0x12345678));
162 : }
163 :
164 : // Heap numbers.
165 : {
166 : AstValueFactory ast_factory(zone, isolate->ast_string_constants(),
167 5 : HashSeed(isolate));
168 :
169 10 : BytecodeArrayBuilder builder(zone, 1, 0);
170 :
171 5 : builder.LoadLiteral(-2.1e19).Return();
172 :
173 5 : ast_factory.Internalize(isolate);
174 5 : Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(isolate);
175 :
176 10 : InterpreterTester tester(isolate, bytecode_array);
177 : auto callable = tester.GetCallable<>();
178 : Handle<Object> return_val = callable().ToHandleChecked();
179 5 : CHECK_EQ(i::HeapNumber::cast(*return_val)->value(), -2.1e19);
180 : }
181 :
182 : // Strings.
183 : {
184 : AstValueFactory ast_factory(zone, isolate->ast_string_constants(),
185 5 : HashSeed(isolate));
186 :
187 10 : BytecodeArrayBuilder builder(zone, 1, 0);
188 :
189 5 : const AstRawString* raw_string = ast_factory.GetOneByteString("String");
190 5 : builder.LoadLiteral(raw_string).Return();
191 :
192 5 : ast_factory.Internalize(isolate);
193 5 : Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(isolate);
194 :
195 10 : InterpreterTester tester(isolate, bytecode_array);
196 : auto callable = tester.GetCallable<>();
197 : Handle<Object> return_val = callable().ToHandleChecked();
198 5 : CHECK(i::String::cast(*return_val)->Equals(*raw_string->string()));
199 : }
200 5 : }
201 :
202 26661 : TEST(InterpreterLoadStoreRegisters) {
203 10 : HandleAndZoneScope handles;
204 : Isolate* isolate = handles.main_isolate();
205 : Zone* zone = handles.main_zone();
206 : Handle<Object> true_value = isolate->factory()->true_value();
207 1285 : for (int i = 0; i <= kMaxInt8; i++) {
208 1280 : BytecodeArrayBuilder builder(zone, 1, i + 1);
209 :
210 : Register reg(i);
211 640 : builder.LoadTrue()
212 640 : .StoreAccumulatorInRegister(reg)
213 640 : .LoadFalse()
214 640 : .LoadAccumulatorWithRegister(reg)
215 640 : .Return();
216 640 : Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(isolate);
217 :
218 1280 : InterpreterTester tester(isolate, bytecode_array);
219 : auto callable = tester.GetCallable<>();
220 : Handle<Object> return_val = callable().ToHandleChecked();
221 640 : CHECK(return_val.is_identical_to(true_value));
222 : }
223 5 : }
224 :
225 :
226 : static const Token::Value kShiftOperators[] = {
227 : Token::Value::SHL, Token::Value::SAR, Token::Value::SHR};
228 :
229 :
230 : static const Token::Value kArithmeticOperators[] = {
231 : Token::Value::BIT_OR, Token::Value::BIT_XOR, Token::Value::BIT_AND,
232 : Token::Value::SHL, Token::Value::SAR, Token::Value::SHR,
233 : Token::Value::ADD, Token::Value::SUB, Token::Value::MUL,
234 : Token::Value::DIV, Token::Value::MOD};
235 :
236 :
237 5995 : static double BinaryOpC(Token::Value op, double lhs, double rhs) {
238 5995 : switch (op) {
239 : case Token::Value::ADD:
240 470 : return lhs + rhs;
241 : case Token::Value::SUB:
242 470 : return lhs - rhs;
243 : case Token::Value::MUL:
244 470 : return lhs * rhs;
245 : case Token::Value::DIV:
246 470 : return base::Divide(lhs, rhs);
247 : case Token::Value::MOD:
248 470 : return Modulo(lhs, rhs);
249 : case Token::Value::BIT_OR:
250 940 : return (v8::internal::DoubleToInt32(lhs) |
251 940 : v8::internal::DoubleToInt32(rhs));
252 : case Token::Value::BIT_XOR:
253 940 : return (v8::internal::DoubleToInt32(lhs) ^
254 940 : v8::internal::DoubleToInt32(rhs));
255 : case Token::Value::BIT_AND:
256 940 : return (v8::internal::DoubleToInt32(lhs) &
257 940 : v8::internal::DoubleToInt32(rhs));
258 : case Token::Value::SHL: {
259 1490 : return base::ShlWithWraparound(DoubleToInt32(lhs), DoubleToInt32(rhs));
260 : }
261 : case Token::Value::SAR: {
262 745 : int32_t val = v8::internal::DoubleToInt32(lhs);
263 745 : uint32_t count = v8::internal::DoubleToUint32(rhs) & 0x1F;
264 745 : int32_t result = val >> count;
265 745 : return result;
266 : }
267 : case Token::Value::SHR: {
268 : uint32_t val = v8::internal::DoubleToUint32(lhs);
269 745 : uint32_t count = v8::internal::DoubleToUint32(rhs) & 0x1F;
270 745 : uint32_t result = val >> count;
271 745 : return result;
272 : }
273 : default:
274 0 : UNREACHABLE();
275 : }
276 : }
277 :
278 26661 : TEST(InterpreterShiftOpsSmi) {
279 5 : int lhs_inputs[] = {0, -17, -182, 1073741823, -1};
280 5 : int rhs_inputs[] = {5, 2, 1, -1, -2, 0, 31, 32, -32, 64, 37};
281 55 : for (size_t l = 0; l < arraysize(lhs_inputs); l++) {
282 575 : for (size_t r = 0; r < arraysize(rhs_inputs); r++) {
283 1925 : for (size_t o = 0; o < arraysize(kShiftOperators); o++) {
284 1650 : HandleAndZoneScope handles;
285 : Isolate* isolate = handles.main_isolate();
286 : Zone* zone = handles.main_zone();
287 : Factory* factory = isolate->factory();
288 : FeedbackVectorSpec feedback_spec(zone);
289 1650 : BytecodeArrayBuilder builder(zone, 1, 1, &feedback_spec);
290 :
291 : FeedbackSlot slot = feedback_spec.AddBinaryOpICSlot();
292 : Handle<i::FeedbackMetadata> metadata =
293 : NewFeedbackMetadata(isolate, &feedback_spec);
294 :
295 : Register reg(0);
296 825 : int lhs = lhs_inputs[l];
297 825 : int rhs = rhs_inputs[r];
298 825 : builder.LoadLiteral(Smi::FromInt(lhs))
299 825 : .StoreAccumulatorInRegister(reg)
300 825 : .LoadLiteral(Smi::FromInt(rhs))
301 1650 : .BinaryOperation(kShiftOperators[o], reg, GetIndex(slot))
302 825 : .Return();
303 825 : Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(isolate);
304 :
305 1650 : InterpreterTester tester(isolate, bytecode_array, metadata);
306 : auto callable = tester.GetCallable<>();
307 : Handle<Object> return_value = callable().ToHandleChecked();
308 : Handle<Object> expected_value =
309 825 : factory->NewNumber(BinaryOpC(kShiftOperators[o], lhs, rhs));
310 825 : CHECK(return_value->SameValue(*expected_value));
311 : }
312 : }
313 : }
314 5 : }
315 :
316 26661 : TEST(InterpreterBinaryOpsSmi) {
317 5 : int lhs_inputs[] = {3266, 1024, 0, -17, -18000};
318 5 : int rhs_inputs[] = {3266, 5, 4, 3, 2, 1, -1, -2};
319 55 : for (size_t l = 0; l < arraysize(lhs_inputs); l++) {
320 425 : for (size_t r = 0; r < arraysize(rhs_inputs); r++) {
321 4600 : for (size_t o = 0; o < arraysize(kArithmeticOperators); o++) {
322 4400 : HandleAndZoneScope handles;
323 : Isolate* isolate = handles.main_isolate();
324 : Zone* zone = handles.main_zone();
325 : Factory* factory = isolate->factory();
326 : FeedbackVectorSpec feedback_spec(zone);
327 4400 : BytecodeArrayBuilder builder(zone, 1, 1, &feedback_spec);
328 :
329 : FeedbackSlot slot = feedback_spec.AddBinaryOpICSlot();
330 : Handle<i::FeedbackMetadata> metadata =
331 : NewFeedbackMetadata(isolate, &feedback_spec);
332 :
333 : Register reg(0);
334 2200 : int lhs = lhs_inputs[l];
335 2200 : int rhs = rhs_inputs[r];
336 2200 : builder.LoadLiteral(Smi::FromInt(lhs))
337 2200 : .StoreAccumulatorInRegister(reg)
338 2200 : .LoadLiteral(Smi::FromInt(rhs))
339 4400 : .BinaryOperation(kArithmeticOperators[o], reg, GetIndex(slot))
340 2200 : .Return();
341 2200 : Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(isolate);
342 :
343 4400 : InterpreterTester tester(isolate, bytecode_array, metadata);
344 : auto callable = tester.GetCallable<>();
345 : Handle<Object> return_value = callable().ToHandleChecked();
346 : Handle<Object> expected_value =
347 2200 : factory->NewNumber(BinaryOpC(kArithmeticOperators[o], lhs, rhs));
348 2200 : CHECK(return_value->SameValue(*expected_value));
349 : }
350 : }
351 : }
352 5 : }
353 :
354 26661 : TEST(InterpreterBinaryOpsHeapNumber) {
355 5 : double lhs_inputs[] = {3266.101, 1024.12, 0.01, -17.99, -18000.833, 9.1e17};
356 : double rhs_inputs[] = {3266.101, 5.999, 4.778, 3.331, 2.643,
357 5 : 1.1, -1.8, -2.9, 8.3e-27};
358 65 : for (size_t l = 0; l < arraysize(lhs_inputs); l++) {
359 570 : for (size_t r = 0; r < arraysize(rhs_inputs); r++) {
360 6210 : for (size_t o = 0; o < arraysize(kArithmeticOperators); o++) {
361 5940 : HandleAndZoneScope handles;
362 : Isolate* isolate = handles.main_isolate();
363 : Zone* zone = handles.main_zone();
364 : Factory* factory = isolate->factory();
365 : FeedbackVectorSpec feedback_spec(zone);
366 5940 : BytecodeArrayBuilder builder(zone, 1, 1, &feedback_spec);
367 :
368 : FeedbackSlot slot = feedback_spec.AddBinaryOpICSlot();
369 : Handle<i::FeedbackMetadata> metadata =
370 : NewFeedbackMetadata(isolate, &feedback_spec);
371 :
372 : Register reg(0);
373 2970 : double lhs = lhs_inputs[l];
374 2970 : double rhs = rhs_inputs[r];
375 2970 : builder.LoadLiteral(lhs)
376 2970 : .StoreAccumulatorInRegister(reg)
377 2970 : .LoadLiteral(rhs)
378 5940 : .BinaryOperation(kArithmeticOperators[o], reg, GetIndex(slot))
379 2970 : .Return();
380 2970 : Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(isolate);
381 :
382 5940 : InterpreterTester tester(isolate, bytecode_array, metadata);
383 : auto callable = tester.GetCallable<>();
384 : Handle<Object> return_value = callable().ToHandleChecked();
385 : Handle<Object> expected_value =
386 2970 : factory->NewNumber(BinaryOpC(kArithmeticOperators[o], lhs, rhs));
387 2970 : CHECK(return_value->SameValue(*expected_value));
388 : }
389 : }
390 : }
391 5 : }
392 :
393 26661 : TEST(InterpreterBinaryOpsBigInt) {
394 : // This test only checks that the recorded type feedback is kBigInt.
395 : AstBigInt inputs[] = {AstBigInt("1"), AstBigInt("-42"), AstBigInt("0xFFFF")};
396 35 : for (size_t l = 0; l < arraysize(inputs); l++) {
397 105 : for (size_t r = 0; r < arraysize(inputs); r++) {
398 1035 : for (size_t o = 0; o < arraysize(kArithmeticOperators); o++) {
399 : // Skip over unsigned right shift.
400 540 : if (kArithmeticOperators[o] == Token::Value::SHR) continue;
401 :
402 900 : HandleAndZoneScope handles;
403 : Isolate* isolate = handles.main_isolate();
404 : Zone* zone = handles.main_zone();
405 : FeedbackVectorSpec feedback_spec(zone);
406 900 : BytecodeArrayBuilder builder(zone, 1, 1, &feedback_spec);
407 :
408 : FeedbackSlot slot = feedback_spec.AddBinaryOpICSlot();
409 : Handle<i::FeedbackMetadata> metadata =
410 : NewFeedbackMetadata(isolate, &feedback_spec);
411 :
412 : Register reg(0);
413 450 : auto lhs = inputs[l];
414 450 : auto rhs = inputs[r];
415 450 : builder.LoadLiteral(lhs)
416 450 : .StoreAccumulatorInRegister(reg)
417 450 : .LoadLiteral(rhs)
418 900 : .BinaryOperation(kArithmeticOperators[o], reg, GetIndex(slot))
419 450 : .Return();
420 450 : Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(isolate);
421 :
422 900 : InterpreterTester tester(isolate, bytecode_array, metadata);
423 : auto callable = tester.GetCallable<>();
424 : Handle<Object> return_value = callable().ToHandleChecked();
425 450 : CHECK(return_value->IsBigInt());
426 450 : if (tester.HasFeedbackMetadata()) {
427 : MaybeObject feedback = callable.vector()->Get(slot);
428 450 : CHECK(feedback->IsSmi());
429 450 : CHECK_EQ(BinaryOperationFeedback::kBigInt, feedback->ToSmi().value());
430 : }
431 : }
432 : }
433 : }
434 5 : }
435 :
436 : namespace {
437 :
438 : struct LiteralForTest {
439 : enum Type { kString, kHeapNumber, kSmi, kTrue, kFalse, kUndefined, kNull };
440 :
441 : explicit LiteralForTest(const AstRawString* string)
442 90 : : type(kString), string(string) {}
443 95 : explicit LiteralForTest(double number) : type(kHeapNumber), number(number) {}
444 140 : explicit LiteralForTest(int smi) : type(kSmi), smi(smi) {}
445 : explicit LiteralForTest(Type type) : type(type) {}
446 :
447 : Type type;
448 : union {
449 : const AstRawString* string;
450 : double number;
451 : int smi;
452 : };
453 : };
454 :
455 440 : void LoadLiteralForTest(BytecodeArrayBuilder* builder,
456 : const LiteralForTest& value) {
457 440 : switch (value.type) {
458 : case LiteralForTest::kString:
459 100 : builder->LoadLiteral(value.string);
460 100 : return;
461 : case LiteralForTest::kHeapNumber:
462 125 : builder->LoadLiteral(value.number);
463 125 : return;
464 : case LiteralForTest::kSmi:
465 390 : builder->LoadLiteral(Smi::FromInt(value.smi));
466 195 : return;
467 : case LiteralForTest::kTrue:
468 5 : builder->LoadTrue();
469 5 : return;
470 : case LiteralForTest::kFalse:
471 5 : builder->LoadFalse();
472 5 : return;
473 : case LiteralForTest::kUndefined:
474 5 : builder->LoadUndefined();
475 5 : return;
476 : case LiteralForTest::kNull:
477 5 : builder->LoadNull();
478 5 : return;
479 : }
480 0 : UNREACHABLE();
481 : }
482 :
483 : } // anonymous namespace
484 :
485 26661 : TEST(InterpreterStringAdd) {
486 10 : HandleAndZoneScope handles;
487 : Isolate* isolate = handles.main_isolate();
488 : Zone* zone = handles.main_zone();
489 : Factory* factory = isolate->factory();
490 : AstValueFactory ast_factory(zone, isolate->ast_string_constants(),
491 5 : HashSeed(isolate));
492 :
493 : struct TestCase {
494 : const AstRawString* lhs;
495 : LiteralForTest rhs;
496 : Handle<Object> expected_value;
497 : int32_t expected_feedback;
498 : } test_cases[] = {
499 5 : {ast_factory.GetOneByteString("a"),
500 : LiteralForTest(ast_factory.GetOneByteString("b")),
501 : factory->NewStringFromStaticChars("ab"),
502 : BinaryOperationFeedback::kString},
503 5 : {ast_factory.GetOneByteString("aaaaaa"),
504 : LiteralForTest(ast_factory.GetOneByteString("b")),
505 : factory->NewStringFromStaticChars("aaaaaab"),
506 : BinaryOperationFeedback::kString},
507 5 : {ast_factory.GetOneByteString("aaa"),
508 : LiteralForTest(ast_factory.GetOneByteString("bbbbb")),
509 : factory->NewStringFromStaticChars("aaabbbbb"),
510 : BinaryOperationFeedback::kString},
511 5 : {ast_factory.GetOneByteString(""),
512 : LiteralForTest(ast_factory.GetOneByteString("b")),
513 : factory->NewStringFromStaticChars("b"),
514 : BinaryOperationFeedback::kString},
515 5 : {ast_factory.GetOneByteString("a"),
516 : LiteralForTest(ast_factory.GetOneByteString("")),
517 : factory->NewStringFromStaticChars("a"),
518 : BinaryOperationFeedback::kString},
519 5 : {ast_factory.GetOneByteString("1.11"), LiteralForTest(2.5),
520 : factory->NewStringFromStaticChars("1.112.5"),
521 : BinaryOperationFeedback::kAny},
522 5 : {ast_factory.GetOneByteString("-1.11"), LiteralForTest(2.56),
523 : factory->NewStringFromStaticChars("-1.112.56"),
524 : BinaryOperationFeedback::kAny},
525 5 : {ast_factory.GetOneByteString(""), LiteralForTest(2.5),
526 : factory->NewStringFromStaticChars("2.5"), BinaryOperationFeedback::kAny},
527 120 : };
528 :
529 85 : for (size_t i = 0; i < arraysize(test_cases); i++) {
530 : FeedbackVectorSpec feedback_spec(zone);
531 80 : BytecodeArrayBuilder builder(zone, 1, 1, &feedback_spec);
532 : FeedbackSlot slot = feedback_spec.AddBinaryOpICSlot();
533 : Handle<i::FeedbackMetadata> metadata =
534 : NewFeedbackMetadata(isolate, &feedback_spec);
535 :
536 : Register reg(0);
537 40 : builder.LoadLiteral(test_cases[i].lhs).StoreAccumulatorInRegister(reg);
538 40 : LoadLiteralForTest(&builder, test_cases[i].rhs);
539 40 : builder.BinaryOperation(Token::Value::ADD, reg, GetIndex(slot)).Return();
540 40 : ast_factory.Internalize(isolate);
541 40 : Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(isolate);
542 :
543 80 : InterpreterTester tester(isolate, bytecode_array, metadata);
544 : auto callable = tester.GetCallable<>();
545 : Handle<Object> return_value = callable().ToHandleChecked();
546 80 : CHECK(return_value->SameValue(*test_cases[i].expected_value));
547 :
548 40 : if (tester.HasFeedbackMetadata()) {
549 : MaybeObject feedback = callable.vector()->Get(slot);
550 40 : CHECK(feedback->IsSmi());
551 40 : CHECK_EQ(test_cases[i].expected_feedback, feedback->ToSmi().value());
552 : }
553 : }
554 5 : }
555 :
556 26661 : TEST(InterpreterParameter1) {
557 10 : HandleAndZoneScope handles;
558 : Isolate* isolate = handles.main_isolate();
559 : Zone* zone = handles.main_zone();
560 10 : BytecodeArrayBuilder builder(zone, 1, 0);
561 :
562 5 : builder.LoadAccumulatorWithRegister(builder.Receiver()).Return();
563 5 : Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(isolate);
564 :
565 10 : InterpreterTester tester(isolate, bytecode_array);
566 : auto callable = tester.GetCallable<Handle<Object>>();
567 :
568 : // Check for heap objects.
569 : Handle<Object> true_value = isolate->factory()->true_value();
570 10 : Handle<Object> return_val = callable(true_value).ToHandleChecked();
571 5 : CHECK(return_val.is_identical_to(true_value));
572 :
573 : // Check for Smis.
574 10 : return_val = callable(Handle<Smi>(Smi::FromInt(3), handles.main_isolate()))
575 : .ToHandleChecked();
576 5 : CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(3));
577 5 : }
578 :
579 26661 : TEST(InterpreterParameter8) {
580 10 : HandleAndZoneScope handles;
581 : Isolate* isolate = handles.main_isolate();
582 : Zone* zone = handles.main_zone();
583 : AstValueFactory ast_factory(zone, isolate->ast_string_constants(),
584 5 : HashSeed(isolate));
585 : FeedbackVectorSpec feedback_spec(zone);
586 10 : BytecodeArrayBuilder builder(zone, 8, 0, &feedback_spec);
587 :
588 : FeedbackSlot slot = feedback_spec.AddBinaryOpICSlot();
589 : FeedbackSlot slot1 = feedback_spec.AddBinaryOpICSlot();
590 : FeedbackSlot slot2 = feedback_spec.AddBinaryOpICSlot();
591 : FeedbackSlot slot3 = feedback_spec.AddBinaryOpICSlot();
592 : FeedbackSlot slot4 = feedback_spec.AddBinaryOpICSlot();
593 : FeedbackSlot slot5 = feedback_spec.AddBinaryOpICSlot();
594 : FeedbackSlot slot6 = feedback_spec.AddBinaryOpICSlot();
595 :
596 : Handle<i::FeedbackMetadata> metadata =
597 : NewFeedbackMetadata(isolate, &feedback_spec);
598 :
599 5 : builder.LoadAccumulatorWithRegister(builder.Receiver())
600 10 : .BinaryOperation(Token::Value::ADD, builder.Parameter(0), GetIndex(slot))
601 10 : .BinaryOperation(Token::Value::ADD, builder.Parameter(1), GetIndex(slot1))
602 10 : .BinaryOperation(Token::Value::ADD, builder.Parameter(2), GetIndex(slot2))
603 10 : .BinaryOperation(Token::Value::ADD, builder.Parameter(3), GetIndex(slot3))
604 10 : .BinaryOperation(Token::Value::ADD, builder.Parameter(4), GetIndex(slot4))
605 10 : .BinaryOperation(Token::Value::ADD, builder.Parameter(5), GetIndex(slot5))
606 10 : .BinaryOperation(Token::Value::ADD, builder.Parameter(6), GetIndex(slot6))
607 5 : .Return();
608 5 : ast_factory.Internalize(isolate);
609 5 : Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(isolate);
610 :
611 10 : InterpreterTester tester(isolate, bytecode_array, metadata);
612 : typedef Handle<Object> H;
613 : auto callable = tester.GetCallable<H, H, H, H, H, H, H, H>();
614 :
615 : Handle<Smi> arg1 = Handle<Smi>(Smi::FromInt(1), handles.main_isolate());
616 : Handle<Smi> arg2 = Handle<Smi>(Smi::FromInt(2), handles.main_isolate());
617 : Handle<Smi> arg3 = Handle<Smi>(Smi::FromInt(3), handles.main_isolate());
618 : Handle<Smi> arg4 = Handle<Smi>(Smi::FromInt(4), handles.main_isolate());
619 : Handle<Smi> arg5 = Handle<Smi>(Smi::FromInt(5), handles.main_isolate());
620 : Handle<Smi> arg6 = Handle<Smi>(Smi::FromInt(6), handles.main_isolate());
621 : Handle<Smi> arg7 = Handle<Smi>(Smi::FromInt(7), handles.main_isolate());
622 : Handle<Smi> arg8 = Handle<Smi>(Smi::FromInt(8), handles.main_isolate());
623 : // Check for Smis.
624 : Handle<Object> return_val =
625 : callable(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8)
626 : .ToHandleChecked();
627 5 : CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(36));
628 5 : }
629 :
630 26661 : TEST(InterpreterBinaryOpTypeFeedback) {
631 : if (FLAG_lite_mode) return;
632 :
633 10 : HandleAndZoneScope handles;
634 : i::Isolate* isolate = handles.main_isolate();
635 : Zone* zone = handles.main_zone();
636 : AstValueFactory ast_factory(zone, isolate->ast_string_constants(),
637 5 : HashSeed(isolate));
638 :
639 : struct BinaryOpExpectation {
640 : Token::Value op;
641 : LiteralForTest arg1;
642 : LiteralForTest arg2;
643 : Handle<Object> result;
644 : int32_t feedback;
645 : };
646 :
647 : BinaryOpExpectation const kTestCases[] = {
648 : // ADD
649 : {Token::Value::ADD, LiteralForTest(2), LiteralForTest(3),
650 : Handle<Smi>(Smi::FromInt(5), isolate),
651 : BinaryOperationFeedback::kSignedSmall},
652 : {Token::Value::ADD, LiteralForTest(Smi::kMaxValue), LiteralForTest(1),
653 : isolate->factory()->NewHeapNumber(Smi::kMaxValue + 1.0),
654 : BinaryOperationFeedback::kNumber},
655 : {Token::Value::ADD, LiteralForTest(3.1415), LiteralForTest(3),
656 : isolate->factory()->NewHeapNumber(3.1415 + 3),
657 : BinaryOperationFeedback::kNumber},
658 : {Token::Value::ADD, LiteralForTest(3.1415), LiteralForTest(1.4142),
659 : isolate->factory()->NewHeapNumber(3.1415 + 1.4142),
660 : BinaryOperationFeedback::kNumber},
661 : {Token::Value::ADD, LiteralForTest(ast_factory.GetOneByteString("foo")),
662 : LiteralForTest(ast_factory.GetOneByteString("bar")),
663 : isolate->factory()->NewStringFromAsciiChecked("foobar"),
664 : BinaryOperationFeedback::kString},
665 : {Token::Value::ADD, LiteralForTest(2),
666 : LiteralForTest(ast_factory.GetOneByteString("2")),
667 : isolate->factory()->NewStringFromAsciiChecked("22"),
668 : BinaryOperationFeedback::kAny},
669 : // SUB
670 : {Token::Value::SUB, LiteralForTest(2), LiteralForTest(3),
671 : Handle<Smi>(Smi::FromInt(-1), isolate),
672 : BinaryOperationFeedback::kSignedSmall},
673 : {Token::Value::SUB, LiteralForTest(Smi::kMinValue), LiteralForTest(1),
674 : isolate->factory()->NewHeapNumber(Smi::kMinValue - 1.0),
675 : BinaryOperationFeedback::kNumber},
676 : {Token::Value::SUB, LiteralForTest(3.1415), LiteralForTest(3),
677 : isolate->factory()->NewHeapNumber(3.1415 - 3),
678 : BinaryOperationFeedback::kNumber},
679 : {Token::Value::SUB, LiteralForTest(3.1415), LiteralForTest(1.4142),
680 : isolate->factory()->NewHeapNumber(3.1415 - 1.4142),
681 : BinaryOperationFeedback::kNumber},
682 : {Token::Value::SUB, LiteralForTest(2),
683 : LiteralForTest(ast_factory.GetOneByteString("1")),
684 : Handle<Smi>(Smi::FromInt(1), isolate), BinaryOperationFeedback::kAny},
685 : // MUL
686 : {Token::Value::MUL, LiteralForTest(2), LiteralForTest(3),
687 : Handle<Smi>(Smi::FromInt(6), isolate),
688 : BinaryOperationFeedback::kSignedSmall},
689 : {Token::Value::MUL, LiteralForTest(Smi::kMinValue), LiteralForTest(2),
690 : isolate->factory()->NewHeapNumber(Smi::kMinValue * 2.0),
691 : BinaryOperationFeedback::kNumber},
692 : {Token::Value::MUL, LiteralForTest(3.1415), LiteralForTest(3),
693 : isolate->factory()->NewHeapNumber(3 * 3.1415),
694 : BinaryOperationFeedback::kNumber},
695 : {Token::Value::MUL, LiteralForTest(3.1415), LiteralForTest(1.4142),
696 : isolate->factory()->NewHeapNumber(3.1415 * 1.4142),
697 : BinaryOperationFeedback::kNumber},
698 : {Token::Value::MUL, LiteralForTest(2),
699 : LiteralForTest(ast_factory.GetOneByteString("1")),
700 : Handle<Smi>(Smi::FromInt(2), isolate), BinaryOperationFeedback::kAny},
701 : // DIV
702 : {Token::Value::DIV, LiteralForTest(6), LiteralForTest(3),
703 : Handle<Smi>(Smi::FromInt(2), isolate),
704 : BinaryOperationFeedback::kSignedSmall},
705 : {Token::Value::DIV, LiteralForTest(3), LiteralForTest(2),
706 : isolate->factory()->NewHeapNumber(3.0 / 2.0),
707 : BinaryOperationFeedback::kSignedSmallInputs},
708 : {Token::Value::DIV, LiteralForTest(3.1415), LiteralForTest(3),
709 : isolate->factory()->NewHeapNumber(3.1415 / 3),
710 : BinaryOperationFeedback::kNumber},
711 : {Token::Value::DIV, LiteralForTest(3.1415),
712 : LiteralForTest(-std::numeric_limits<double>::infinity()),
713 : isolate->factory()->NewHeapNumber(-0.0),
714 : BinaryOperationFeedback::kNumber},
715 : {Token::Value::DIV, LiteralForTest(2),
716 : LiteralForTest(ast_factory.GetOneByteString("1")),
717 : Handle<Smi>(Smi::FromInt(2), isolate), BinaryOperationFeedback::kAny},
718 : // MOD
719 : {Token::Value::MOD, LiteralForTest(5), LiteralForTest(3),
720 : Handle<Smi>(Smi::FromInt(2), isolate),
721 : BinaryOperationFeedback::kSignedSmall},
722 : {Token::Value::MOD, LiteralForTest(-4), LiteralForTest(2),
723 : isolate->factory()->NewHeapNumber(-0.0),
724 : BinaryOperationFeedback::kNumber},
725 : {Token::Value::MOD, LiteralForTest(3.1415), LiteralForTest(3),
726 : isolate->factory()->NewHeapNumber(fmod(3.1415, 3.0)),
727 : BinaryOperationFeedback::kNumber},
728 : {Token::Value::MOD, LiteralForTest(-3.1415), LiteralForTest(-1.4142),
729 : isolate->factory()->NewHeapNumber(fmod(-3.1415, -1.4142)),
730 : BinaryOperationFeedback::kNumber},
731 : {Token::Value::MOD, LiteralForTest(3),
732 : LiteralForTest(ast_factory.GetOneByteString("-2")),
733 250 : Handle<Smi>(Smi::FromInt(1), isolate), BinaryOperationFeedback::kAny}};
734 :
735 265 : for (const BinaryOpExpectation& test_case : kTestCases) {
736 : i::FeedbackVectorSpec feedback_spec(zone);
737 260 : BytecodeArrayBuilder builder(zone, 1, 1, &feedback_spec);
738 :
739 : i::FeedbackSlot slot0 = feedback_spec.AddBinaryOpICSlot();
740 :
741 : Handle<i::FeedbackMetadata> metadata =
742 : i::NewFeedbackMetadata(isolate, &feedback_spec);
743 :
744 : Register reg(0);
745 130 : LoadLiteralForTest(&builder, test_case.arg1);
746 130 : builder.StoreAccumulatorInRegister(reg);
747 130 : LoadLiteralForTest(&builder, test_case.arg2);
748 130 : builder.BinaryOperation(test_case.op, reg, GetIndex(slot0)).Return();
749 :
750 130 : ast_factory.Internalize(isolate);
751 130 : Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(isolate);
752 :
753 260 : InterpreterTester tester(isolate, bytecode_array, metadata);
754 : auto callable = tester.GetCallable<>();
755 :
756 130 : Handle<Object> return_val = callable().ToHandleChecked();
757 : MaybeObject feedback0 = callable.vector()->Get(slot0);
758 130 : CHECK(feedback0->IsSmi());
759 130 : CHECK_EQ(test_case.feedback, feedback0->ToSmi().value());
760 260 : CHECK(Object::Equals(isolate, test_case.result, return_val).ToChecked());
761 : }
762 : }
763 :
764 26661 : TEST(InterpreterBinaryOpSmiTypeFeedback) {
765 : if (FLAG_lite_mode) return;
766 :
767 10 : HandleAndZoneScope handles;
768 : i::Isolate* isolate = handles.main_isolate();
769 : Zone* zone = handles.main_zone();
770 : AstValueFactory ast_factory(zone, isolate->ast_string_constants(),
771 5 : HashSeed(isolate));
772 :
773 : struct BinaryOpExpectation {
774 : Token::Value op;
775 : LiteralForTest arg1;
776 : int32_t arg2;
777 : Handle<Object> result;
778 : int32_t feedback;
779 : };
780 :
781 : BinaryOpExpectation const kTestCases[] = {
782 : // ADD
783 : {Token::Value::ADD, LiteralForTest(2), 42,
784 : Handle<Smi>(Smi::FromInt(44), isolate),
785 : BinaryOperationFeedback::kSignedSmall},
786 : {Token::Value::ADD, LiteralForTest(2), Smi::kMaxValue,
787 : isolate->factory()->NewHeapNumber(Smi::kMaxValue + 2.0),
788 : BinaryOperationFeedback::kNumber},
789 : {Token::Value::ADD, LiteralForTest(3.1415), 2,
790 : isolate->factory()->NewHeapNumber(3.1415 + 2.0),
791 : BinaryOperationFeedback::kNumber},
792 : {Token::Value::ADD, LiteralForTest(ast_factory.GetOneByteString("2")), 2,
793 : isolate->factory()->NewStringFromAsciiChecked("22"),
794 : BinaryOperationFeedback::kAny},
795 : // SUB
796 : {Token::Value::SUB, LiteralForTest(2), 42,
797 : Handle<Smi>(Smi::FromInt(-40), isolate),
798 : BinaryOperationFeedback::kSignedSmall},
799 : {Token::Value::SUB, LiteralForTest(Smi::kMinValue), 1,
800 : isolate->factory()->NewHeapNumber(Smi::kMinValue - 1.0),
801 : BinaryOperationFeedback::kNumber},
802 : {Token::Value::SUB, LiteralForTest(3.1415), 2,
803 : isolate->factory()->NewHeapNumber(3.1415 - 2.0),
804 : BinaryOperationFeedback::kNumber},
805 : {Token::Value::SUB, LiteralForTest(ast_factory.GetOneByteString("2")), 2,
806 : Handle<Smi>(Smi::zero(), isolate), BinaryOperationFeedback::kAny},
807 : // BIT_OR
808 : {Token::Value::BIT_OR, LiteralForTest(4), 1,
809 : Handle<Smi>(Smi::FromInt(5), isolate),
810 : BinaryOperationFeedback::kSignedSmall},
811 : {Token::Value::BIT_OR, LiteralForTest(3.1415), 8,
812 : Handle<Smi>(Smi::FromInt(11), isolate),
813 : BinaryOperationFeedback::kNumber},
814 : {Token::Value::BIT_OR, LiteralForTest(ast_factory.GetOneByteString("2")),
815 : 1, Handle<Smi>(Smi::FromInt(3), isolate), BinaryOperationFeedback::kAny},
816 : // BIT_AND
817 : {Token::Value::BIT_AND, LiteralForTest(3), 1,
818 : Handle<Smi>(Smi::FromInt(1), isolate),
819 : BinaryOperationFeedback::kSignedSmall},
820 : {Token::Value::BIT_AND, LiteralForTest(3.1415), 2,
821 : Handle<Smi>(Smi::FromInt(2), isolate), BinaryOperationFeedback::kNumber},
822 : {Token::Value::BIT_AND, LiteralForTest(ast_factory.GetOneByteString("2")),
823 : 1, Handle<Smi>(Smi::zero(), isolate), BinaryOperationFeedback::kAny},
824 : // SHL
825 : {Token::Value::SHL, LiteralForTest(3), 1,
826 : Handle<Smi>(Smi::FromInt(6), isolate),
827 : BinaryOperationFeedback::kSignedSmall},
828 : {Token::Value::SHL, LiteralForTest(3.1415), 2,
829 : Handle<Smi>(Smi::FromInt(12), isolate),
830 : BinaryOperationFeedback::kNumber},
831 : {Token::Value::SHL, LiteralForTest(ast_factory.GetOneByteString("2")), 1,
832 : Handle<Smi>(Smi::FromInt(4), isolate), BinaryOperationFeedback::kAny},
833 : // SAR
834 : {Token::Value::SAR, LiteralForTest(3), 1,
835 : Handle<Smi>(Smi::FromInt(1), isolate),
836 : BinaryOperationFeedback::kSignedSmall},
837 : {Token::Value::SAR, LiteralForTest(3.1415), 2,
838 : Handle<Smi>(Smi::zero(), isolate), BinaryOperationFeedback::kNumber},
839 : {Token::Value::SAR, LiteralForTest(ast_factory.GetOneByteString("2")), 1,
840 205 : Handle<Smi>(Smi::FromInt(1), isolate), BinaryOperationFeedback::kAny}};
841 :
842 205 : for (const BinaryOpExpectation& test_case : kTestCases) {
843 : i::FeedbackVectorSpec feedback_spec(zone);
844 200 : BytecodeArrayBuilder builder(zone, 1, 1, &feedback_spec);
845 :
846 : i::FeedbackSlot slot0 = feedback_spec.AddBinaryOpICSlot();
847 :
848 : Handle<i::FeedbackMetadata> metadata =
849 : i::NewFeedbackMetadata(isolate, &feedback_spec);
850 :
851 : Register reg(0);
852 100 : LoadLiteralForTest(&builder, test_case.arg1);
853 100 : builder.StoreAccumulatorInRegister(reg)
854 200 : .LoadLiteral(Smi::FromInt(test_case.arg2))
855 200 : .BinaryOperation(test_case.op, reg, GetIndex(slot0))
856 100 : .Return();
857 :
858 100 : ast_factory.Internalize(isolate);
859 100 : Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(isolate);
860 :
861 200 : InterpreterTester tester(isolate, bytecode_array, metadata);
862 : auto callable = tester.GetCallable<>();
863 :
864 100 : Handle<Object> return_val = callable().ToHandleChecked();
865 : MaybeObject feedback0 = callable.vector()->Get(slot0);
866 100 : CHECK(feedback0->IsSmi());
867 100 : CHECK_EQ(test_case.feedback, feedback0->ToSmi().value());
868 200 : CHECK(Object::Equals(isolate, test_case.result, return_val).ToChecked());
869 : }
870 : }
871 :
872 26661 : TEST(InterpreterUnaryOpFeedback) {
873 : if (FLAG_lite_mode) return;
874 :
875 10 : HandleAndZoneScope handles;
876 : i::Isolate* isolate = handles.main_isolate();
877 : Zone* zone = handles.main_zone();
878 :
879 : Handle<Smi> smi_one = Handle<Smi>(Smi::FromInt(1), isolate);
880 : Handle<Smi> smi_max = Handle<Smi>(Smi::FromInt(Smi::kMaxValue), isolate);
881 : Handle<Smi> smi_min = Handle<Smi>(Smi::FromInt(Smi::kMinValue), isolate);
882 5 : Handle<HeapNumber> number = isolate->factory()->NewHeapNumber(2.1);
883 : Handle<BigInt> bigint =
884 10 : BigInt::FromNumber(isolate, smi_max).ToHandleChecked();
885 5 : Handle<String> str = isolate->factory()->NewStringFromAsciiChecked("42");
886 :
887 : struct TestCase {
888 : Token::Value op;
889 : Handle<Smi> smi_feedback_value;
890 : Handle<Smi> smi_to_number_feedback_value;
891 : Handle<HeapNumber> number_feedback_value;
892 : Handle<BigInt> bigint_feedback_value;
893 : Handle<Object> any_feedback_value;
894 : };
895 : TestCase const kTestCases[] = {
896 : // Testing ADD and BIT_NOT would require generalizing the test setup.
897 : {Token::Value::SUB, smi_one, smi_min, number, bigint, str},
898 : {Token::Value::INC, smi_one, smi_max, number, bigint, str},
899 15 : {Token::Value::DEC, smi_one, smi_min, number, bigint, str}};
900 35 : for (TestCase const& test_case : kTestCases) {
901 : i::FeedbackVectorSpec feedback_spec(zone);
902 30 : BytecodeArrayBuilder builder(zone, 5, 0, &feedback_spec);
903 :
904 : i::FeedbackSlot slot0 = feedback_spec.AddBinaryOpICSlot();
905 : i::FeedbackSlot slot1 = feedback_spec.AddBinaryOpICSlot();
906 : i::FeedbackSlot slot2 = feedback_spec.AddBinaryOpICSlot();
907 : i::FeedbackSlot slot3 = feedback_spec.AddBinaryOpICSlot();
908 : i::FeedbackSlot slot4 = feedback_spec.AddBinaryOpICSlot();
909 :
910 : Handle<i::FeedbackMetadata> metadata =
911 : i::NewFeedbackMetadata(isolate, &feedback_spec);
912 :
913 15 : builder.LoadAccumulatorWithRegister(builder.Receiver())
914 30 : .UnaryOperation(test_case.op, GetIndex(slot0))
915 30 : .LoadAccumulatorWithRegister(builder.Parameter(0))
916 15 : .UnaryOperation(test_case.op, GetIndex(slot1))
917 30 : .LoadAccumulatorWithRegister(builder.Parameter(1))
918 15 : .UnaryOperation(test_case.op, GetIndex(slot2))
919 30 : .LoadAccumulatorWithRegister(builder.Parameter(2))
920 15 : .UnaryOperation(test_case.op, GetIndex(slot3))
921 30 : .LoadAccumulatorWithRegister(builder.Parameter(3))
922 30 : .UnaryOperation(test_case.op, GetIndex(slot4))
923 15 : .Return();
924 :
925 15 : Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(isolate);
926 :
927 30 : InterpreterTester tester(isolate, bytecode_array, metadata);
928 : typedef Handle<Object> H;
929 : auto callable = tester.GetCallable<H, H, H, H, H>();
930 :
931 : Handle<Object> return_val =
932 : callable(test_case.smi_feedback_value,
933 : test_case.smi_to_number_feedback_value,
934 : test_case.number_feedback_value,
935 : test_case.bigint_feedback_value, test_case.any_feedback_value)
936 : .ToHandleChecked();
937 : USE(return_val);
938 : MaybeObject feedback0 = callable.vector()->Get(slot0);
939 15 : CHECK(feedback0->IsSmi());
940 15 : CHECK_EQ(BinaryOperationFeedback::kSignedSmall, feedback0->ToSmi().value());
941 :
942 : MaybeObject feedback1 = callable.vector()->Get(slot1);
943 15 : CHECK(feedback1->IsSmi());
944 15 : CHECK_EQ(BinaryOperationFeedback::kNumber, feedback1->ToSmi().value());
945 :
946 : MaybeObject feedback2 = callable.vector()->Get(slot2);
947 15 : CHECK(feedback2->IsSmi());
948 15 : CHECK_EQ(BinaryOperationFeedback::kNumber, feedback2->ToSmi().value());
949 :
950 : MaybeObject feedback3 = callable.vector()->Get(slot3);
951 15 : CHECK(feedback3->IsSmi());
952 15 : CHECK_EQ(BinaryOperationFeedback::kBigInt, feedback3->ToSmi().value());
953 :
954 : MaybeObject feedback4 = callable.vector()->Get(slot4);
955 15 : CHECK(feedback4->IsSmi());
956 15 : CHECK_EQ(BinaryOperationFeedback::kAny, feedback4->ToSmi().value());
957 : }
958 : }
959 :
960 26661 : TEST(InterpreterBitwiseTypeFeedback) {
961 : if (FLAG_lite_mode) return;
962 :
963 10 : HandleAndZoneScope handles;
964 : i::Isolate* isolate = handles.main_isolate();
965 : Zone* zone = handles.main_zone();
966 : const Token::Value kBitwiseBinaryOperators[] = {
967 : Token::Value::BIT_OR, Token::Value::BIT_XOR, Token::Value::BIT_AND,
968 5 : Token::Value::SHL, Token::Value::SHR, Token::Value::SAR};
969 :
970 65 : for (Token::Value op : kBitwiseBinaryOperators) {
971 : i::FeedbackVectorSpec feedback_spec(zone);
972 60 : BytecodeArrayBuilder builder(zone, 4, 0, &feedback_spec);
973 :
974 : i::FeedbackSlot slot0 = feedback_spec.AddBinaryOpICSlot();
975 : i::FeedbackSlot slot1 = feedback_spec.AddBinaryOpICSlot();
976 : i::FeedbackSlot slot2 = feedback_spec.AddBinaryOpICSlot();
977 :
978 : Handle<i::FeedbackMetadata> metadata =
979 : i::NewFeedbackMetadata(isolate, &feedback_spec);
980 :
981 30 : builder.LoadAccumulatorWithRegister(builder.Receiver())
982 60 : .BinaryOperation(op, builder.Parameter(0), GetIndex(slot0))
983 60 : .BinaryOperation(op, builder.Parameter(1), GetIndex(slot1))
984 60 : .BinaryOperation(op, builder.Parameter(2), GetIndex(slot2))
985 30 : .Return();
986 :
987 30 : Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(isolate);
988 :
989 60 : InterpreterTester tester(isolate, bytecode_array, metadata);
990 : typedef Handle<Object> H;
991 : auto callable = tester.GetCallable<H, H, H, H>();
992 :
993 : Handle<Smi> arg1 = Handle<Smi>(Smi::FromInt(2), isolate);
994 : Handle<Smi> arg2 = Handle<Smi>(Smi::FromInt(2), isolate);
995 30 : Handle<HeapNumber> arg3 = isolate->factory()->NewHeapNumber(2.2);
996 30 : Handle<String> arg4 = isolate->factory()->NewStringFromAsciiChecked("2");
997 :
998 : Handle<Object> return_val =
999 : callable(arg1, arg2, arg3, arg4).ToHandleChecked();
1000 : USE(return_val);
1001 : MaybeObject feedback0 = callable.vector()->Get(slot0);
1002 30 : CHECK(feedback0->IsSmi());
1003 30 : CHECK_EQ(BinaryOperationFeedback::kSignedSmall, feedback0->ToSmi().value());
1004 :
1005 : MaybeObject feedback1 = callable.vector()->Get(slot1);
1006 30 : CHECK(feedback1->IsSmi());
1007 30 : CHECK_EQ(BinaryOperationFeedback::kNumber, feedback1->ToSmi().value());
1008 :
1009 : MaybeObject feedback2 = callable.vector()->Get(slot2);
1010 30 : CHECK(feedback2->IsSmi());
1011 30 : CHECK_EQ(BinaryOperationFeedback::kAny, feedback2->ToSmi().value());
1012 : }
1013 : }
1014 :
1015 26661 : TEST(InterpreterParameter1Assign) {
1016 10 : HandleAndZoneScope handles;
1017 : Isolate* isolate = handles.main_isolate();
1018 : Zone* zone = handles.main_zone();
1019 10 : BytecodeArrayBuilder builder(zone, 1, 0);
1020 :
1021 5 : builder.LoadLiteral(Smi::FromInt(5))
1022 10 : .StoreAccumulatorInRegister(builder.Receiver())
1023 10 : .LoadAccumulatorWithRegister(builder.Receiver())
1024 5 : .Return();
1025 5 : Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(isolate);
1026 :
1027 10 : InterpreterTester tester(isolate, bytecode_array);
1028 : auto callable = tester.GetCallable<Handle<Object>>();
1029 :
1030 : Handle<Object> return_val =
1031 10 : callable(Handle<Smi>(Smi::FromInt(3), handles.main_isolate()))
1032 : .ToHandleChecked();
1033 5 : CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(5));
1034 5 : }
1035 :
1036 26661 : TEST(InterpreterLoadGlobal) {
1037 10 : HandleAndZoneScope handles;
1038 : Isolate* isolate = handles.main_isolate();
1039 :
1040 : // Test loading a global.
1041 : std::string source(
1042 : "var global = 321;\n"
1043 15 : "function " + InterpreterTester::function_name() + "() {\n"
1044 : " return global;\n"
1045 5 : "}");
1046 10 : InterpreterTester tester(isolate, source.c_str());
1047 : auto callable = tester.GetCallable<>();
1048 :
1049 : Handle<Object> return_val = callable().ToHandleChecked();
1050 5 : CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(321));
1051 5 : }
1052 :
1053 26661 : TEST(InterpreterStoreGlobal) {
1054 10 : HandleAndZoneScope handles;
1055 : Isolate* isolate = handles.main_isolate();
1056 : Factory* factory = isolate->factory();
1057 :
1058 : // Test storing to a global.
1059 : std::string source(
1060 : "var global = 321;\n"
1061 15 : "function " + InterpreterTester::function_name() + "() {\n"
1062 : " global = 999;\n"
1063 5 : "}");
1064 10 : InterpreterTester tester(isolate, source.c_str());
1065 : auto callable = tester.GetCallable<>();
1066 :
1067 : callable().ToHandleChecked();
1068 5 : Handle<i::String> name = factory->InternalizeUtf8String("global");
1069 : Handle<i::Object> global_obj =
1070 15 : Object::GetProperty(isolate, isolate->global_object(), name)
1071 : .ToHandleChecked();
1072 5 : CHECK_EQ(Smi::cast(*global_obj), Smi::FromInt(999));
1073 5 : }
1074 :
1075 26661 : TEST(InterpreterCallGlobal) {
1076 10 : HandleAndZoneScope handles;
1077 : Isolate* isolate = handles.main_isolate();
1078 :
1079 : // Test calling a global function.
1080 : std::string source(
1081 : "function g_add(a, b) { return a + b; }\n"
1082 15 : "function " + InterpreterTester::function_name() + "() {\n"
1083 : " return g_add(5, 10);\n"
1084 5 : "}");
1085 10 : InterpreterTester tester(isolate, source.c_str());
1086 : auto callable = tester.GetCallable<>();
1087 :
1088 : Handle<Object> return_val = callable().ToHandleChecked();
1089 5 : CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(15));
1090 5 : }
1091 :
1092 26661 : TEST(InterpreterLoadUnallocated) {
1093 10 : HandleAndZoneScope handles;
1094 : Isolate* isolate = handles.main_isolate();
1095 :
1096 : // Test loading an unallocated global.
1097 : std::string source(
1098 : "unallocated = 123;\n"
1099 15 : "function " + InterpreterTester::function_name() + "() {\n"
1100 : " return unallocated;\n"
1101 5 : "}");
1102 10 : InterpreterTester tester(isolate, source.c_str());
1103 : auto callable = tester.GetCallable<>();
1104 :
1105 : Handle<Object> return_val = callable().ToHandleChecked();
1106 5 : CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(123));
1107 5 : }
1108 :
1109 26661 : TEST(InterpreterStoreUnallocated) {
1110 10 : HandleAndZoneScope handles;
1111 : Isolate* isolate = handles.main_isolate();
1112 : Factory* factory = isolate->factory();
1113 :
1114 : // Test storing to an unallocated global.
1115 : std::string source(
1116 : "unallocated = 321;\n"
1117 15 : "function " + InterpreterTester::function_name() + "() {\n"
1118 : " unallocated = 999;\n"
1119 5 : "}");
1120 10 : InterpreterTester tester(isolate, source.c_str());
1121 : auto callable = tester.GetCallable<>();
1122 :
1123 : callable().ToHandleChecked();
1124 5 : Handle<i::String> name = factory->InternalizeUtf8String("unallocated");
1125 : Handle<i::Object> global_obj =
1126 15 : Object::GetProperty(isolate, isolate->global_object(), name)
1127 : .ToHandleChecked();
1128 5 : CHECK_EQ(Smi::cast(*global_obj), Smi::FromInt(999));
1129 5 : }
1130 :
1131 26661 : TEST(InterpreterLoadNamedProperty) {
1132 10 : HandleAndZoneScope handles;
1133 : Isolate* isolate = handles.main_isolate();
1134 : Zone* zone = handles.main_zone();
1135 : AstValueFactory ast_factory(zone, isolate->ast_string_constants(),
1136 5 : HashSeed(isolate));
1137 :
1138 : FeedbackVectorSpec feedback_spec(zone);
1139 : FeedbackSlot slot = feedback_spec.AddLoadICSlot();
1140 :
1141 : Handle<i::FeedbackMetadata> metadata =
1142 : NewFeedbackMetadata(isolate, &feedback_spec);
1143 :
1144 5 : const AstRawString* name = ast_factory.GetOneByteString("val");
1145 :
1146 10 : BytecodeArrayBuilder builder(zone, 1, 0, &feedback_spec);
1147 :
1148 5 : builder.LoadNamedProperty(builder.Receiver(), name, GetIndex(slot)).Return();
1149 5 : ast_factory.Internalize(isolate);
1150 5 : Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(isolate);
1151 :
1152 10 : InterpreterTester tester(isolate, bytecode_array, metadata);
1153 : auto callable = tester.GetCallable<Handle<Object>>();
1154 :
1155 5 : Handle<Object> object = InterpreterTester::NewObject("({ val : 123 })");
1156 : // Test IC miss.
1157 10 : Handle<Object> return_val = callable(object).ToHandleChecked();
1158 5 : CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(123));
1159 :
1160 : // Test transition to monomorphic IC.
1161 10 : return_val = callable(object).ToHandleChecked();
1162 5 : CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(123));
1163 :
1164 : // Test transition to polymorphic IC.
1165 : Handle<Object> object2 =
1166 5 : InterpreterTester::NewObject("({ val : 456, other : 123 })");
1167 10 : return_val = callable(object2).ToHandleChecked();
1168 5 : CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(456));
1169 :
1170 : // Test transition to megamorphic IC.
1171 : Handle<Object> object3 =
1172 5 : InterpreterTester::NewObject("({ val : 789, val2 : 123 })");
1173 10 : callable(object3).ToHandleChecked();
1174 : Handle<Object> object4 =
1175 5 : InterpreterTester::NewObject("({ val : 789, val3 : 123 })");
1176 10 : callable(object4).ToHandleChecked();
1177 : Handle<Object> object5 =
1178 5 : InterpreterTester::NewObject("({ val : 789, val4 : 123 })");
1179 10 : return_val = callable(object5).ToHandleChecked();
1180 5 : CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(789));
1181 5 : }
1182 :
1183 26661 : TEST(InterpreterLoadKeyedProperty) {
1184 10 : HandleAndZoneScope handles;
1185 : Isolate* isolate = handles.main_isolate();
1186 : Zone* zone = handles.main_zone();
1187 : AstValueFactory ast_factory(zone, isolate->ast_string_constants(),
1188 5 : HashSeed(isolate));
1189 :
1190 : FeedbackVectorSpec feedback_spec(zone);
1191 : FeedbackSlot slot = feedback_spec.AddKeyedLoadICSlot();
1192 :
1193 : Handle<i::FeedbackMetadata> metadata =
1194 : NewFeedbackMetadata(isolate, &feedback_spec);
1195 :
1196 5 : const AstRawString* key = ast_factory.GetOneByteString("key");
1197 :
1198 10 : BytecodeArrayBuilder builder(zone, 1, 1, &feedback_spec);
1199 :
1200 5 : builder.LoadLiteral(key)
1201 10 : .LoadKeyedProperty(builder.Receiver(), GetIndex(slot))
1202 5 : .Return();
1203 5 : ast_factory.Internalize(isolate);
1204 5 : Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(isolate);
1205 :
1206 10 : InterpreterTester tester(isolate, bytecode_array, metadata);
1207 : auto callable = tester.GetCallable<Handle<Object>>();
1208 :
1209 5 : Handle<Object> object = InterpreterTester::NewObject("({ key : 123 })");
1210 : // Test IC miss.
1211 10 : Handle<Object> return_val = callable(object).ToHandleChecked();
1212 5 : CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(123));
1213 :
1214 : // Test transition to monomorphic IC.
1215 10 : return_val = callable(object).ToHandleChecked();
1216 5 : CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(123));
1217 :
1218 : // Test transition to megamorphic IC.
1219 : Handle<Object> object3 =
1220 5 : InterpreterTester::NewObject("({ key : 789, val2 : 123 })");
1221 10 : return_val = callable(object3).ToHandleChecked();
1222 5 : CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(789));
1223 5 : }
1224 :
1225 26661 : TEST(InterpreterStoreNamedProperty) {
1226 10 : HandleAndZoneScope handles;
1227 : Isolate* isolate = handles.main_isolate();
1228 : Zone* zone = handles.main_zone();
1229 : AstValueFactory ast_factory(zone, isolate->ast_string_constants(),
1230 5 : HashSeed(isolate));
1231 :
1232 : FeedbackVectorSpec feedback_spec(zone);
1233 : FeedbackSlot slot = feedback_spec.AddStoreICSlot(LanguageMode::kStrict);
1234 :
1235 : Handle<i::FeedbackMetadata> metadata =
1236 : NewFeedbackMetadata(isolate, &feedback_spec);
1237 :
1238 5 : const AstRawString* name = ast_factory.GetOneByteString("val");
1239 :
1240 10 : BytecodeArrayBuilder builder(zone, 1, 0, &feedback_spec);
1241 :
1242 5 : builder.LoadLiteral(Smi::FromInt(999))
1243 : .StoreNamedProperty(builder.Receiver(), name, GetIndex(slot),
1244 10 : LanguageMode::kStrict)
1245 5 : .Return();
1246 5 : ast_factory.Internalize(isolate);
1247 5 : Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(isolate);
1248 :
1249 10 : InterpreterTester tester(isolate, bytecode_array, metadata);
1250 : auto callable = tester.GetCallable<Handle<Object>>();
1251 5 : Handle<Object> object = InterpreterTester::NewObject("({ val : 123 })");
1252 : // Test IC miss.
1253 : Handle<Object> result;
1254 10 : callable(object).ToHandleChecked();
1255 10 : CHECK(Runtime::GetObjectProperty(isolate, object, name->string())
1256 : .ToHandle(&result));
1257 5 : CHECK_EQ(Smi::cast(*result), Smi::FromInt(999));
1258 :
1259 : // Test transition to monomorphic IC.
1260 10 : callable(object).ToHandleChecked();
1261 10 : CHECK(Runtime::GetObjectProperty(isolate, object, name->string())
1262 : .ToHandle(&result));
1263 5 : CHECK_EQ(Smi::cast(*result), Smi::FromInt(999));
1264 :
1265 : // Test transition to polymorphic IC.
1266 : Handle<Object> object2 =
1267 5 : InterpreterTester::NewObject("({ val : 456, other : 123 })");
1268 10 : callable(object2).ToHandleChecked();
1269 10 : CHECK(Runtime::GetObjectProperty(isolate, object2, name->string())
1270 : .ToHandle(&result));
1271 5 : CHECK_EQ(Smi::cast(*result), Smi::FromInt(999));
1272 :
1273 : // Test transition to megamorphic IC.
1274 : Handle<Object> object3 =
1275 5 : InterpreterTester::NewObject("({ val : 789, val2 : 123 })");
1276 10 : callable(object3).ToHandleChecked();
1277 : Handle<Object> object4 =
1278 5 : InterpreterTester::NewObject("({ val : 789, val3 : 123 })");
1279 10 : callable(object4).ToHandleChecked();
1280 : Handle<Object> object5 =
1281 5 : InterpreterTester::NewObject("({ val : 789, val4 : 123 })");
1282 10 : callable(object5).ToHandleChecked();
1283 10 : CHECK(Runtime::GetObjectProperty(isolate, object5, name->string())
1284 : .ToHandle(&result));
1285 5 : CHECK_EQ(Smi::cast(*result), Smi::FromInt(999));
1286 5 : }
1287 :
1288 26661 : TEST(InterpreterStoreKeyedProperty) {
1289 10 : HandleAndZoneScope handles;
1290 : Isolate* isolate = handles.main_isolate();
1291 : Zone* zone = handles.main_zone();
1292 : AstValueFactory ast_factory(zone, isolate->ast_string_constants(),
1293 5 : HashSeed(isolate));
1294 :
1295 : FeedbackVectorSpec feedback_spec(zone);
1296 : FeedbackSlot slot = feedback_spec.AddKeyedStoreICSlot(LanguageMode::kSloppy);
1297 :
1298 : Handle<i::FeedbackMetadata> metadata =
1299 : NewFeedbackMetadata(isolate, &feedback_spec);
1300 :
1301 5 : const AstRawString* name = ast_factory.GetOneByteString("val");
1302 :
1303 10 : BytecodeArrayBuilder builder(zone, 1, 1, &feedback_spec);
1304 :
1305 5 : builder.LoadLiteral(name)
1306 10 : .StoreAccumulatorInRegister(Register(0))
1307 5 : .LoadLiteral(Smi::FromInt(999))
1308 : .StoreKeyedProperty(builder.Receiver(), Register(0), GetIndex(slot),
1309 15 : i::LanguageMode::kSloppy)
1310 5 : .Return();
1311 5 : ast_factory.Internalize(isolate);
1312 5 : Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(isolate);
1313 :
1314 10 : InterpreterTester tester(isolate, bytecode_array, metadata);
1315 : auto callable = tester.GetCallable<Handle<Object>>();
1316 5 : Handle<Object> object = InterpreterTester::NewObject("({ val : 123 })");
1317 : // Test IC miss.
1318 : Handle<Object> result;
1319 10 : callable(object).ToHandleChecked();
1320 10 : CHECK(Runtime::GetObjectProperty(isolate, object, name->string())
1321 : .ToHandle(&result));
1322 5 : CHECK_EQ(Smi::cast(*result), Smi::FromInt(999));
1323 :
1324 : // Test transition to monomorphic IC.
1325 10 : callable(object).ToHandleChecked();
1326 10 : CHECK(Runtime::GetObjectProperty(isolate, object, name->string())
1327 : .ToHandle(&result));
1328 5 : CHECK_EQ(Smi::cast(*result), Smi::FromInt(999));
1329 :
1330 : // Test transition to megamorphic IC.
1331 : Handle<Object> object2 =
1332 5 : InterpreterTester::NewObject("({ val : 456, other : 123 })");
1333 10 : callable(object2).ToHandleChecked();
1334 10 : CHECK(Runtime::GetObjectProperty(isolate, object2, name->string())
1335 : .ToHandle(&result));
1336 5 : CHECK_EQ(Smi::cast(*result), Smi::FromInt(999));
1337 5 : }
1338 :
1339 26661 : TEST(InterpreterCall) {
1340 10 : HandleAndZoneScope handles;
1341 : Isolate* isolate = handles.main_isolate();
1342 : Zone* zone = handles.main_zone();
1343 : Factory* factory = isolate->factory();
1344 : AstValueFactory ast_factory(zone, isolate->ast_string_constants(),
1345 5 : HashSeed(isolate));
1346 :
1347 : FeedbackVectorSpec feedback_spec(zone);
1348 : FeedbackSlot slot = feedback_spec.AddLoadICSlot();
1349 : FeedbackSlot call_slot = feedback_spec.AddCallICSlot();
1350 :
1351 : Handle<i::FeedbackMetadata> metadata =
1352 : NewFeedbackMetadata(isolate, &feedback_spec);
1353 : int slot_index = GetIndex(slot);
1354 : int call_slot_index = -1;
1355 : call_slot_index = GetIndex(call_slot);
1356 :
1357 5 : const AstRawString* name = ast_factory.GetOneByteString("func");
1358 :
1359 : // Check with no args.
1360 : {
1361 10 : BytecodeArrayBuilder builder(zone, 1, 1, &feedback_spec);
1362 5 : Register reg = builder.register_allocator()->NewRegister();
1363 5 : RegisterList args = builder.register_allocator()->NewRegisterList(1);
1364 5 : builder.LoadNamedProperty(builder.Receiver(), name, slot_index)
1365 5 : .StoreAccumulatorInRegister(reg)
1366 10 : .MoveRegister(builder.Receiver(), args[0]);
1367 :
1368 5 : builder.CallProperty(reg, args, call_slot_index);
1369 :
1370 5 : builder.Return();
1371 5 : ast_factory.Internalize(isolate);
1372 5 : Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(isolate);
1373 :
1374 10 : InterpreterTester tester(isolate, bytecode_array, metadata);
1375 : auto callable = tester.GetCallable<Handle<Object>>();
1376 :
1377 : Handle<Object> object = InterpreterTester::NewObject(
1378 5 : "new (function Obj() { this.func = function() { return 0x265; }})()");
1379 10 : Handle<Object> return_val = callable(object).ToHandleChecked();
1380 5 : CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(0x265));
1381 : }
1382 :
1383 : // Check that receiver is passed properly.
1384 : {
1385 10 : BytecodeArrayBuilder builder(zone, 1, 1, &feedback_spec);
1386 5 : Register reg = builder.register_allocator()->NewRegister();
1387 5 : RegisterList args = builder.register_allocator()->NewRegisterList(1);
1388 5 : builder.LoadNamedProperty(builder.Receiver(), name, slot_index)
1389 5 : .StoreAccumulatorInRegister(reg)
1390 10 : .MoveRegister(builder.Receiver(), args[0]);
1391 5 : builder.CallProperty(reg, args, call_slot_index);
1392 5 : builder.Return();
1393 5 : ast_factory.Internalize(isolate);
1394 5 : Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(isolate);
1395 :
1396 10 : InterpreterTester tester(isolate, bytecode_array, metadata);
1397 : auto callable = tester.GetCallable<Handle<Object>>();
1398 :
1399 : Handle<Object> object = InterpreterTester::NewObject(
1400 : "new (function Obj() {"
1401 : " this.val = 1234;"
1402 : " this.func = function() { return this.val; };"
1403 5 : "})()");
1404 10 : Handle<Object> return_val = callable(object).ToHandleChecked();
1405 5 : CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(1234));
1406 : }
1407 :
1408 : // Check with two parameters (+ receiver).
1409 : {
1410 10 : BytecodeArrayBuilder builder(zone, 1, 4, &feedback_spec);
1411 5 : Register reg = builder.register_allocator()->NewRegister();
1412 5 : RegisterList args = builder.register_allocator()->NewRegisterList(3);
1413 :
1414 5 : builder.LoadNamedProperty(builder.Receiver(), name, slot_index)
1415 5 : .StoreAccumulatorInRegister(reg)
1416 10 : .LoadAccumulatorWithRegister(builder.Receiver())
1417 5 : .StoreAccumulatorInRegister(args[0])
1418 5 : .LoadLiteral(Smi::FromInt(51))
1419 5 : .StoreAccumulatorInRegister(args[1])
1420 5 : .LoadLiteral(Smi::FromInt(11))
1421 5 : .StoreAccumulatorInRegister(args[2]);
1422 :
1423 5 : builder.CallProperty(reg, args, call_slot_index);
1424 :
1425 5 : builder.Return();
1426 :
1427 5 : ast_factory.Internalize(isolate);
1428 5 : Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(isolate);
1429 :
1430 10 : InterpreterTester tester(isolate, bytecode_array, metadata);
1431 : auto callable = tester.GetCallable<Handle<Object>>();
1432 :
1433 : Handle<Object> object = InterpreterTester::NewObject(
1434 : "new (function Obj() { "
1435 : " this.func = function(a, b) { return a - b; }"
1436 5 : "})()");
1437 10 : Handle<Object> return_val = callable(object).ToHandleChecked();
1438 10 : CHECK(return_val->SameValue(Smi::FromInt(40)));
1439 : }
1440 :
1441 : // Check with 10 parameters (+ receiver).
1442 : {
1443 10 : BytecodeArrayBuilder builder(zone, 1, 12, &feedback_spec);
1444 5 : Register reg = builder.register_allocator()->NewRegister();
1445 5 : RegisterList args = builder.register_allocator()->NewRegisterList(11);
1446 :
1447 5 : builder.LoadNamedProperty(builder.Receiver(), name, slot_index)
1448 5 : .StoreAccumulatorInRegister(reg)
1449 10 : .LoadAccumulatorWithRegister(builder.Receiver())
1450 5 : .StoreAccumulatorInRegister(args[0])
1451 10 : .LoadLiteral(ast_factory.GetOneByteString("a"))
1452 5 : .StoreAccumulatorInRegister(args[1])
1453 10 : .LoadLiteral(ast_factory.GetOneByteString("b"))
1454 5 : .StoreAccumulatorInRegister(args[2])
1455 10 : .LoadLiteral(ast_factory.GetOneByteString("c"))
1456 5 : .StoreAccumulatorInRegister(args[3])
1457 10 : .LoadLiteral(ast_factory.GetOneByteString("d"))
1458 5 : .StoreAccumulatorInRegister(args[4])
1459 10 : .LoadLiteral(ast_factory.GetOneByteString("e"))
1460 5 : .StoreAccumulatorInRegister(args[5])
1461 10 : .LoadLiteral(ast_factory.GetOneByteString("f"))
1462 5 : .StoreAccumulatorInRegister(args[6])
1463 10 : .LoadLiteral(ast_factory.GetOneByteString("g"))
1464 5 : .StoreAccumulatorInRegister(args[7])
1465 10 : .LoadLiteral(ast_factory.GetOneByteString("h"))
1466 5 : .StoreAccumulatorInRegister(args[8])
1467 10 : .LoadLiteral(ast_factory.GetOneByteString("i"))
1468 5 : .StoreAccumulatorInRegister(args[9])
1469 10 : .LoadLiteral(ast_factory.GetOneByteString("j"))
1470 5 : .StoreAccumulatorInRegister(args[10]);
1471 :
1472 5 : builder.CallProperty(reg, args, call_slot_index);
1473 :
1474 5 : builder.Return();
1475 :
1476 5 : ast_factory.Internalize(isolate);
1477 5 : Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(isolate);
1478 :
1479 10 : InterpreterTester tester(isolate, bytecode_array, metadata);
1480 : auto callable = tester.GetCallable<Handle<Object>>();
1481 :
1482 : Handle<Object> object = InterpreterTester::NewObject(
1483 : "new (function Obj() { "
1484 : " this.prefix = \"prefix_\";"
1485 : " this.func = function(a, b, c, d, e, f, g, h, i, j) {"
1486 : " return this.prefix + a + b + c + d + e + f + g + h + i + j;"
1487 : " }"
1488 5 : "})()");
1489 10 : Handle<Object> return_val = callable(object).ToHandleChecked();
1490 : Handle<i::String> expected =
1491 5 : factory->NewStringFromAsciiChecked("prefix_abcdefghij");
1492 5 : CHECK(i::String::cast(*return_val)->Equals(*expected));
1493 : }
1494 5 : }
1495 :
1496 15 : static BytecodeArrayBuilder& SetRegister(BytecodeArrayBuilder& builder,
1497 : Register reg, int value,
1498 : Register scratch) {
1499 15 : return builder.StoreAccumulatorInRegister(scratch)
1500 15 : .LoadLiteral(Smi::FromInt(value))
1501 15 : .StoreAccumulatorInRegister(reg)
1502 15 : .LoadAccumulatorWithRegister(scratch);
1503 : }
1504 :
1505 65 : static BytecodeArrayBuilder& IncrementRegister(BytecodeArrayBuilder& builder,
1506 : Register reg, int value,
1507 : Register scratch,
1508 : int slot_index) {
1509 65 : return builder.StoreAccumulatorInRegister(scratch)
1510 65 : .LoadLiteral(Smi::FromInt(value))
1511 65 : .BinaryOperation(Token::Value::ADD, reg, slot_index)
1512 65 : .StoreAccumulatorInRegister(reg)
1513 65 : .LoadAccumulatorWithRegister(scratch);
1514 : }
1515 :
1516 26661 : TEST(InterpreterJumps) {
1517 10 : HandleAndZoneScope handles;
1518 : Isolate* isolate = handles.main_isolate();
1519 : Zone* zone = handles.main_zone();
1520 : FeedbackVectorSpec feedback_spec(zone);
1521 10 : BytecodeArrayBuilder builder(zone, 1, 2, &feedback_spec);
1522 :
1523 : FeedbackSlot slot = feedback_spec.AddBinaryOpICSlot();
1524 : FeedbackSlot slot1 = feedback_spec.AddBinaryOpICSlot();
1525 : FeedbackSlot slot2 = feedback_spec.AddBinaryOpICSlot();
1526 :
1527 : Handle<i::FeedbackMetadata> metadata =
1528 : NewFeedbackMetadata(isolate, &feedback_spec);
1529 :
1530 : Register reg(0), scratch(1);
1531 : BytecodeLoopHeader loop_header;
1532 25 : BytecodeLabel label[2];
1533 :
1534 5 : builder.LoadLiteral(Smi::zero())
1535 5 : .StoreAccumulatorInRegister(reg)
1536 5 : .Jump(&label[0]);
1537 5 : SetRegister(builder, reg, 1024, scratch).Bind(&loop_header);
1538 5 : IncrementRegister(builder, reg, 1, scratch, GetIndex(slot)).Jump(&label[1]);
1539 5 : SetRegister(builder, reg, 2048, scratch).Bind(&label[0]);
1540 5 : IncrementRegister(builder, reg, 2, scratch, GetIndex(slot1))
1541 5 : .JumpLoop(&loop_header, 0);
1542 5 : SetRegister(builder, reg, 4096, scratch).Bind(&label[1]);
1543 5 : IncrementRegister(builder, reg, 4, scratch, GetIndex(slot2))
1544 5 : .LoadAccumulatorWithRegister(reg)
1545 5 : .Return();
1546 :
1547 5 : Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(isolate);
1548 10 : InterpreterTester tester(isolate, bytecode_array, metadata);
1549 : auto callable = tester.GetCallable<>();
1550 : Handle<Object> return_value = callable().ToHandleChecked();
1551 5 : CHECK_EQ(Smi::ToInt(*return_value), 7);
1552 5 : }
1553 :
1554 26661 : TEST(InterpreterConditionalJumps) {
1555 10 : HandleAndZoneScope handles;
1556 : Isolate* isolate = handles.main_isolate();
1557 : Zone* zone = handles.main_zone();
1558 : FeedbackVectorSpec feedback_spec(zone);
1559 10 : BytecodeArrayBuilder builder(zone, 1, 2, &feedback_spec);
1560 :
1561 : FeedbackSlot slot = feedback_spec.AddBinaryOpICSlot();
1562 : FeedbackSlot slot1 = feedback_spec.AddBinaryOpICSlot();
1563 : FeedbackSlot slot2 = feedback_spec.AddBinaryOpICSlot();
1564 : FeedbackSlot slot3 = feedback_spec.AddBinaryOpICSlot();
1565 : FeedbackSlot slot4 = feedback_spec.AddBinaryOpICSlot();
1566 :
1567 : Handle<i::FeedbackMetadata> metadata =
1568 : NewFeedbackMetadata(isolate, &feedback_spec);
1569 :
1570 : Register reg(0), scratch(1);
1571 25 : BytecodeLabel label[2];
1572 : BytecodeLabel done, done1;
1573 :
1574 5 : builder.LoadLiteral(Smi::zero())
1575 5 : .StoreAccumulatorInRegister(reg)
1576 5 : .LoadFalse()
1577 5 : .JumpIfFalse(ToBooleanMode::kAlreadyBoolean, &label[0]);
1578 5 : IncrementRegister(builder, reg, 1024, scratch, GetIndex(slot))
1579 5 : .Bind(&label[0])
1580 5 : .LoadTrue()
1581 5 : .JumpIfFalse(ToBooleanMode::kAlreadyBoolean, &done);
1582 5 : IncrementRegister(builder, reg, 1, scratch, GetIndex(slot1))
1583 5 : .LoadTrue()
1584 5 : .JumpIfTrue(ToBooleanMode::kAlreadyBoolean, &label[1]);
1585 5 : IncrementRegister(builder, reg, 2048, scratch, GetIndex(slot2))
1586 5 : .Bind(&label[1]);
1587 5 : IncrementRegister(builder, reg, 2, scratch, GetIndex(slot3))
1588 5 : .LoadFalse()
1589 5 : .JumpIfTrue(ToBooleanMode::kAlreadyBoolean, &done1);
1590 5 : IncrementRegister(builder, reg, 4, scratch, GetIndex(slot4))
1591 5 : .LoadAccumulatorWithRegister(reg)
1592 5 : .Bind(&done)
1593 5 : .Bind(&done1)
1594 5 : .Return();
1595 :
1596 5 : Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(isolate);
1597 10 : InterpreterTester tester(isolate, bytecode_array, metadata);
1598 : auto callable = tester.GetCallable<>();
1599 : Handle<Object> return_value = callable().ToHandleChecked();
1600 5 : CHECK_EQ(Smi::ToInt(*return_value), 7);
1601 5 : }
1602 :
1603 26661 : TEST(InterpreterConditionalJumps2) {
1604 : // TODO(oth): Add tests for all conditional jumps near and far.
1605 10 : HandleAndZoneScope handles;
1606 : Isolate* isolate = handles.main_isolate();
1607 : Zone* zone = handles.main_zone();
1608 : FeedbackVectorSpec feedback_spec(zone);
1609 10 : BytecodeArrayBuilder builder(zone, 1, 2, &feedback_spec);
1610 :
1611 : FeedbackSlot slot = feedback_spec.AddBinaryOpICSlot();
1612 : FeedbackSlot slot1 = feedback_spec.AddBinaryOpICSlot();
1613 : FeedbackSlot slot2 = feedback_spec.AddBinaryOpICSlot();
1614 : FeedbackSlot slot3 = feedback_spec.AddBinaryOpICSlot();
1615 : FeedbackSlot slot4 = feedback_spec.AddBinaryOpICSlot();
1616 :
1617 : Handle<i::FeedbackMetadata> metadata =
1618 : NewFeedbackMetadata(isolate, &feedback_spec);
1619 :
1620 : Register reg(0), scratch(1);
1621 25 : BytecodeLabel label[2];
1622 : BytecodeLabel done, done1;
1623 :
1624 5 : builder.LoadLiteral(Smi::zero())
1625 5 : .StoreAccumulatorInRegister(reg)
1626 5 : .LoadFalse()
1627 5 : .JumpIfFalse(ToBooleanMode::kAlreadyBoolean, &label[0]);
1628 5 : IncrementRegister(builder, reg, 1024, scratch, GetIndex(slot))
1629 5 : .Bind(&label[0])
1630 5 : .LoadTrue()
1631 5 : .JumpIfFalse(ToBooleanMode::kAlreadyBoolean, &done);
1632 5 : IncrementRegister(builder, reg, 1, scratch, GetIndex(slot1))
1633 5 : .LoadTrue()
1634 5 : .JumpIfTrue(ToBooleanMode::kAlreadyBoolean, &label[1]);
1635 5 : IncrementRegister(builder, reg, 2048, scratch, GetIndex(slot2))
1636 5 : .Bind(&label[1]);
1637 5 : IncrementRegister(builder, reg, 2, scratch, GetIndex(slot3))
1638 5 : .LoadFalse()
1639 5 : .JumpIfTrue(ToBooleanMode::kAlreadyBoolean, &done1);
1640 5 : IncrementRegister(builder, reg, 4, scratch, GetIndex(slot4))
1641 5 : .LoadAccumulatorWithRegister(reg)
1642 5 : .Bind(&done)
1643 5 : .Bind(&done1)
1644 5 : .Return();
1645 :
1646 5 : Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(isolate);
1647 10 : InterpreterTester tester(isolate, bytecode_array, metadata);
1648 : auto callable = tester.GetCallable<>();
1649 : Handle<Object> return_value = callable().ToHandleChecked();
1650 5 : CHECK_EQ(Smi::ToInt(*return_value), 7);
1651 5 : }
1652 :
1653 26661 : TEST(InterpreterJumpConstantWith16BitOperand) {
1654 10 : HandleAndZoneScope handles;
1655 : Isolate* isolate = handles.main_isolate();
1656 : Zone* zone = handles.main_zone();
1657 : AstValueFactory ast_factory(zone, isolate->ast_string_constants(),
1658 5 : HashSeed(isolate));
1659 : FeedbackVectorSpec feedback_spec(zone);
1660 10 : BytecodeArrayBuilder builder(zone, 1, 257, &feedback_spec);
1661 :
1662 : FeedbackSlot slot = feedback_spec.AddBinaryOpICSlot();
1663 : Handle<i::FeedbackMetadata> metadata =
1664 : NewFeedbackMetadata(isolate, &feedback_spec);
1665 :
1666 : Register reg(0), scratch(256);
1667 : BytecodeLabel done, fake;
1668 :
1669 5 : builder.LoadLiteral(Smi::zero());
1670 5 : builder.StoreAccumulatorInRegister(reg);
1671 : // Conditional jump to the fake label, to force both basic blocks to be live.
1672 5 : builder.JumpIfTrue(ToBooleanMode::kConvertToBoolean, &fake);
1673 : // Consume all 8-bit operands
1674 2565 : for (int i = 1; i <= 256; i++) {
1675 1280 : builder.LoadLiteral(i + 0.5);
1676 1280 : builder.BinaryOperation(Token::Value::ADD, reg, GetIndex(slot));
1677 1280 : builder.StoreAccumulatorInRegister(reg);
1678 : }
1679 5 : builder.Jump(&done);
1680 :
1681 : // Emit more than 16-bit immediate operands worth of code to jump over.
1682 5 : builder.Bind(&fake);
1683 66005 : for (int i = 0; i < 6600; i++) {
1684 33000 : builder.LoadLiteral(Smi::zero()); // 1-byte
1685 : builder.BinaryOperation(Token::Value::ADD, scratch,
1686 33000 : GetIndex(slot)); // 6-bytes
1687 33000 : builder.StoreAccumulatorInRegister(scratch); // 4-bytes
1688 33000 : builder.MoveRegister(scratch, reg); // 6-bytes
1689 : }
1690 5 : builder.Bind(&done);
1691 5 : builder.LoadAccumulatorWithRegister(reg);
1692 5 : builder.Return();
1693 :
1694 5 : ast_factory.Internalize(isolate);
1695 5 : Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(isolate);
1696 5 : BytecodeArrayIterator iterator(bytecode_array);
1697 :
1698 : bool found_16bit_constant_jump = false;
1699 7715 : while (!iterator.done()) {
1700 3860 : if (iterator.current_bytecode() == Bytecode::kJumpConstant &&
1701 : iterator.current_operand_scale() == OperandScale::kDouble) {
1702 : found_16bit_constant_jump = true;
1703 : break;
1704 : }
1705 3855 : iterator.Advance();
1706 : }
1707 5 : CHECK(found_16bit_constant_jump);
1708 :
1709 10 : InterpreterTester tester(isolate, bytecode_array, metadata);
1710 : auto callable = tester.GetCallable<>();
1711 : Handle<Object> return_value = callable().ToHandleChecked();
1712 5 : CHECK_EQ(Handle<HeapNumber>::cast(return_value)->value(),
1713 : 256.0 / 2 * (1.5 + 256.5));
1714 5 : }
1715 :
1716 26661 : TEST(InterpreterJumpWith32BitOperand) {
1717 10 : HandleAndZoneScope handles;
1718 : Isolate* isolate = handles.main_isolate();
1719 : Zone* zone = handles.main_zone();
1720 : AstValueFactory ast_factory(zone, isolate->ast_string_constants(),
1721 5 : HashSeed(isolate));
1722 10 : BytecodeArrayBuilder builder(zone, 1, 1);
1723 : Register reg(0);
1724 : BytecodeLabel done;
1725 :
1726 5 : builder.LoadLiteral(Smi::zero());
1727 5 : builder.StoreAccumulatorInRegister(reg);
1728 : // Consume all 16-bit constant pool entries. Make sure to use doubles so that
1729 : // the jump can't re-use an integer.
1730 655365 : for (int i = 1; i <= 65536; i++) {
1731 327680 : builder.LoadLiteral(i + 0.5);
1732 : }
1733 5 : builder.Jump(&done);
1734 5 : builder.LoadLiteral(Smi::zero());
1735 5 : builder.Bind(&done);
1736 5 : builder.Return();
1737 :
1738 5 : ast_factory.Internalize(isolate);
1739 5 : Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(isolate);
1740 :
1741 5 : BytecodeArrayIterator iterator(bytecode_array);
1742 :
1743 : bool found_32bit_jump = false;
1744 35 : while (!iterator.done()) {
1745 20 : if (iterator.current_bytecode() == Bytecode::kJump &&
1746 : iterator.current_operand_scale() == OperandScale::kQuadruple) {
1747 : found_32bit_jump = true;
1748 : break;
1749 : }
1750 15 : iterator.Advance();
1751 : }
1752 5 : CHECK(found_32bit_jump);
1753 :
1754 10 : InterpreterTester tester(isolate, bytecode_array);
1755 : auto callable = tester.GetCallable<>();
1756 : Handle<Object> return_value = callable().ToHandleChecked();
1757 5 : CHECK_EQ(Handle<HeapNumber>::cast(return_value)->value(), 65536.5);
1758 5 : }
1759 :
1760 : static const Token::Value kComparisonTypes[] = {
1761 : Token::Value::EQ, Token::Value::EQ_STRICT, Token::Value::LT,
1762 : Token::Value::LTE, Token::Value::GT, Token::Value::GTE};
1763 :
1764 : template <typename T>
1765 10480 : bool CompareC(Token::Value op, T lhs, T rhs, bool types_differed = false) {
1766 10480 : switch (op) {
1767 : case Token::Value::EQ:
1768 1655 : return lhs == rhs;
1769 : case Token::Value::NE:
1770 0 : return lhs != rhs;
1771 : case Token::Value::EQ_STRICT:
1772 1655 : return (lhs == rhs) && !types_differed;
1773 : case Token::Value::NE_STRICT:
1774 550 : return (lhs != rhs) || types_differed;
1775 : case Token::Value::LT:
1776 1655 : return lhs < rhs;
1777 : case Token::Value::LTE:
1778 1655 : return lhs <= rhs;
1779 : case Token::Value::GT:
1780 1655 : return lhs > rhs;
1781 : case Token::Value::GTE:
1782 1655 : return lhs >= rhs;
1783 : default:
1784 0 : UNREACHABLE();
1785 : }
1786 : }
1787 :
1788 26661 : TEST(InterpreterSmiComparisons) {
1789 : // NB Constants cover 31-bit space.
1790 : int inputs[] = {v8::internal::kMinInt / 2,
1791 : v8::internal::kMinInt / 4,
1792 : -108733832,
1793 : -999,
1794 : -42,
1795 : -2,
1796 : -1,
1797 : 0,
1798 : +1,
1799 : +2,
1800 : 42,
1801 : 12345678,
1802 : v8::internal::kMaxInt / 4,
1803 5 : v8::internal::kMaxInt / 2};
1804 :
1805 65 : for (size_t c = 0; c < arraysize(kComparisonTypes); c++) {
1806 30 : Token::Value comparison = kComparisonTypes[c];
1807 870 : for (size_t i = 0; i < arraysize(inputs); i++) {
1808 12180 : for (size_t j = 0; j < arraysize(inputs); j++) {
1809 11760 : HandleAndZoneScope handles;
1810 : Isolate* isolate = handles.main_isolate();
1811 : Zone* zone = handles.main_zone();
1812 : FeedbackVectorSpec feedback_spec(zone);
1813 11760 : BytecodeArrayBuilder builder(zone, 1, 1, &feedback_spec);
1814 :
1815 : FeedbackSlot slot = feedback_spec.AddCompareICSlot();
1816 : Handle<i::FeedbackMetadata> metadata =
1817 : NewFeedbackMetadata(isolate, &feedback_spec);
1818 :
1819 : Register r0(0);
1820 11760 : builder.LoadLiteral(Smi::FromInt(inputs[i]))
1821 5880 : .StoreAccumulatorInRegister(r0)
1822 11760 : .LoadLiteral(Smi::FromInt(inputs[j]))
1823 11760 : .CompareOperation(comparison, r0, GetIndex(slot))
1824 5880 : .Return();
1825 :
1826 5880 : Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(isolate);
1827 11760 : InterpreterTester tester(isolate, bytecode_array, metadata);
1828 : auto callable = tester.GetCallable<>();
1829 : Handle<Object> return_value = callable().ToHandleChecked();
1830 5880 : CHECK(return_value->IsBoolean());
1831 11760 : CHECK_EQ(return_value->BooleanValue(isolate),
1832 : CompareC(comparison, inputs[i], inputs[j]));
1833 5880 : if (tester.HasFeedbackMetadata()) {
1834 : MaybeObject feedback = callable.vector()->Get(slot);
1835 5880 : CHECK(feedback->IsSmi());
1836 5880 : CHECK_EQ(CompareOperationFeedback::kSignedSmall,
1837 : feedback->ToSmi().value());
1838 : }
1839 : }
1840 : }
1841 : }
1842 5 : }
1843 :
1844 26661 : TEST(InterpreterHeapNumberComparisons) {
1845 : double inputs[] = {std::numeric_limits<double>::min(),
1846 : std::numeric_limits<double>::max(),
1847 : -0.001,
1848 : 0.01,
1849 : 0.1000001,
1850 : 1e99,
1851 5 : -1e-99};
1852 65 : for (size_t c = 0; c < arraysize(kComparisonTypes); c++) {
1853 30 : Token::Value comparison = kComparisonTypes[c];
1854 450 : for (size_t i = 0; i < arraysize(inputs); i++) {
1855 3150 : for (size_t j = 0; j < arraysize(inputs); j++) {
1856 2940 : HandleAndZoneScope handles;
1857 : Isolate* isolate = handles.main_isolate();
1858 : Zone* zone = handles.main_zone();
1859 : AstValueFactory ast_factory(zone, isolate->ast_string_constants(),
1860 1470 : HashSeed(isolate));
1861 :
1862 : FeedbackVectorSpec feedback_spec(zone);
1863 2940 : BytecodeArrayBuilder builder(zone, 1, 1, &feedback_spec);
1864 :
1865 : FeedbackSlot slot = feedback_spec.AddCompareICSlot();
1866 : Handle<i::FeedbackMetadata> metadata =
1867 : NewFeedbackMetadata(isolate, &feedback_spec);
1868 :
1869 : Register r0(0);
1870 1470 : builder.LoadLiteral(inputs[i])
1871 1470 : .StoreAccumulatorInRegister(r0)
1872 2940 : .LoadLiteral(inputs[j])
1873 2940 : .CompareOperation(comparison, r0, GetIndex(slot))
1874 1470 : .Return();
1875 :
1876 1470 : ast_factory.Internalize(isolate);
1877 1470 : Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(isolate);
1878 2940 : InterpreterTester tester(isolate, bytecode_array, metadata);
1879 : auto callable = tester.GetCallable<>();
1880 : Handle<Object> return_value = callable().ToHandleChecked();
1881 1470 : CHECK(return_value->IsBoolean());
1882 2940 : CHECK_EQ(return_value->BooleanValue(isolate),
1883 : CompareC(comparison, inputs[i], inputs[j]));
1884 1470 : if (tester.HasFeedbackMetadata()) {
1885 : MaybeObject feedback = callable.vector()->Get(slot);
1886 1470 : CHECK(feedback->IsSmi());
1887 1470 : CHECK_EQ(CompareOperationFeedback::kNumber,
1888 : feedback->ToSmi().value());
1889 : }
1890 : }
1891 : }
1892 : }
1893 5 : }
1894 :
1895 26661 : TEST(InterpreterBigIntComparisons) {
1896 : // This test only checks that the recorded type feedback is kBigInt.
1897 : AstBigInt inputs[] = {AstBigInt("0"), AstBigInt("-42"),
1898 : AstBigInt("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF")};
1899 65 : for (size_t c = 0; c < arraysize(kComparisonTypes); c++) {
1900 30 : Token::Value comparison = kComparisonTypes[c];
1901 210 : for (size_t i = 0; i < arraysize(inputs); i++) {
1902 630 : for (size_t j = 0; j < arraysize(inputs); j++) {
1903 540 : HandleAndZoneScope handles;
1904 : Isolate* isolate = handles.main_isolate();
1905 : Zone* zone = handles.main_zone();
1906 : AstValueFactory ast_factory(zone, isolate->ast_string_constants(),
1907 270 : HashSeed(isolate));
1908 :
1909 : FeedbackVectorSpec feedback_spec(zone);
1910 540 : BytecodeArrayBuilder builder(zone, 1, 1, &feedback_spec);
1911 :
1912 : FeedbackSlot slot = feedback_spec.AddCompareICSlot();
1913 : Handle<i::FeedbackMetadata> metadata =
1914 : NewFeedbackMetadata(isolate, &feedback_spec);
1915 :
1916 : Register r0(0);
1917 270 : builder.LoadLiteral(inputs[i])
1918 270 : .StoreAccumulatorInRegister(r0)
1919 270 : .LoadLiteral(inputs[j])
1920 540 : .CompareOperation(comparison, r0, GetIndex(slot))
1921 270 : .Return();
1922 :
1923 270 : ast_factory.Internalize(isolate);
1924 270 : Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(isolate);
1925 540 : InterpreterTester tester(isolate, bytecode_array, metadata);
1926 : auto callable = tester.GetCallable<>();
1927 : Handle<Object> return_value = callable().ToHandleChecked();
1928 270 : CHECK(return_value->IsBoolean());
1929 270 : if (tester.HasFeedbackMetadata()) {
1930 : MaybeObject feedback = callable.vector()->Get(slot);
1931 270 : CHECK(feedback->IsSmi());
1932 270 : CHECK_EQ(CompareOperationFeedback::kBigInt,
1933 : feedback->ToSmi().value());
1934 : }
1935 : }
1936 : }
1937 : }
1938 5 : }
1939 :
1940 26661 : TEST(InterpreterStringComparisons) {
1941 10 : HandleAndZoneScope handles;
1942 : Isolate* isolate = handles.main_isolate();
1943 : Zone* zone = handles.main_zone();
1944 :
1945 40 : std::string inputs[] = {"A", "abc", "z", "", "Foo!", "Foo"};
1946 :
1947 65 : for (size_t c = 0; c < arraysize(kComparisonTypes); c++) {
1948 30 : Token::Value comparison = kComparisonTypes[c];
1949 390 : for (size_t i = 0; i < arraysize(inputs); i++) {
1950 2340 : for (size_t j = 0; j < arraysize(inputs); j++) {
1951 : AstValueFactory ast_factory(zone, isolate->ast_string_constants(),
1952 1080 : HashSeed(isolate));
1953 :
1954 2160 : CanonicalHandleScope canonical(isolate);
1955 1080 : const char* lhs = inputs[i].c_str();
1956 1080 : const char* rhs = inputs[j].c_str();
1957 :
1958 : FeedbackVectorSpec feedback_spec(zone);
1959 : FeedbackSlot slot = feedback_spec.AddCompareICSlot();
1960 : Handle<i::FeedbackMetadata> metadata =
1961 : NewFeedbackMetadata(isolate, &feedback_spec);
1962 :
1963 2160 : BytecodeArrayBuilder builder(zone, 1, 1, &feedback_spec);
1964 : Register r0(0);
1965 1080 : builder.LoadLiteral(ast_factory.GetOneByteString(lhs))
1966 1080 : .StoreAccumulatorInRegister(r0)
1967 2160 : .LoadLiteral(ast_factory.GetOneByteString(rhs))
1968 2160 : .CompareOperation(comparison, r0, GetIndex(slot))
1969 1080 : .Return();
1970 :
1971 1080 : ast_factory.Internalize(isolate);
1972 1080 : Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(isolate);
1973 2160 : InterpreterTester tester(isolate, bytecode_array, metadata);
1974 : auto callable = tester.GetCallable<>();
1975 : Handle<Object> return_value = callable().ToHandleChecked();
1976 1080 : CHECK(return_value->IsBoolean());
1977 4320 : CHECK_EQ(return_value->BooleanValue(isolate),
1978 : CompareC(comparison, inputs[i], inputs[j]));
1979 1080 : if (tester.HasFeedbackMetadata()) {
1980 : MaybeObject feedback = callable.vector()->Get(slot);
1981 1080 : CHECK(feedback->IsSmi());
1982 : int const expected_feedback =
1983 : Token::IsOrderedRelationalCompareOp(comparison)
1984 : ? CompareOperationFeedback::kString
1985 1080 : : CompareOperationFeedback::kInternalizedString;
1986 1080 : CHECK_EQ(expected_feedback, feedback->ToSmi().value());
1987 : }
1988 : }
1989 : }
1990 : }
1991 5 : }
1992 :
1993 750 : static void LoadStringAndAddSpace(BytecodeArrayBuilder* builder,
1994 : AstValueFactory* ast_factory,
1995 : const char* cstr,
1996 : FeedbackSlot string_add_slot) {
1997 750 : Register string_reg = builder->register_allocator()->NewRegister();
1998 :
1999 : (*builder)
2000 750 : .LoadLiteral(ast_factory->GetOneByteString(cstr))
2001 750 : .StoreAccumulatorInRegister(string_reg)
2002 1500 : .LoadLiteral(ast_factory->GetOneByteString(" "))
2003 : .BinaryOperation(Token::Value::ADD, string_reg,
2004 750 : GetIndex(string_add_slot));
2005 750 : }
2006 :
2007 26661 : TEST(InterpreterMixedComparisons) {
2008 : // This test compares a HeapNumber with a String. The latter is
2009 : // convertible to a HeapNumber so comparison will be between numeric
2010 : // values except for the strict comparisons where no conversion is
2011 : // performed.
2012 5 : const char* inputs[] = {"-1.77", "-40.333", "0.01", "55.77e50", "2.01"};
2013 :
2014 : enum WhichSideString { kLhsIsString, kRhsIsString };
2015 :
2016 : enum StringType { kInternalizedStringConstant, kComputedString };
2017 :
2018 65 : for (size_t c = 0; c < arraysize(kComparisonTypes); c++) {
2019 30 : Token::Value comparison = kComparisonTypes[c];
2020 330 : for (size_t i = 0; i < arraysize(inputs); i++) {
2021 1650 : for (size_t j = 0; j < arraysize(inputs); j++) {
2022 : // We test the case where either the lhs or the rhs is a string...
2023 3750 : for (WhichSideString which_side : {kLhsIsString, kRhsIsString}) {
2024 : // ... and the case when the string is internalized or computed.
2025 4500 : for (StringType string_type :
2026 2250 : {kInternalizedStringConstant, kComputedString}) {
2027 2250 : const char* lhs_cstr = inputs[i];
2028 2250 : const char* rhs_cstr = inputs[j];
2029 2250 : double lhs = StringToDouble(lhs_cstr, ConversionFlags::NO_FLAGS);
2030 2250 : double rhs = StringToDouble(rhs_cstr, ConversionFlags::NO_FLAGS);
2031 3750 : HandleAndZoneScope handles;
2032 : Isolate* isolate = handles.main_isolate();
2033 : Zone* zone = handles.main_zone();
2034 : AstValueFactory ast_factory(zone, isolate->ast_string_constants(),
2035 2250 : HashSeed(isolate));
2036 : FeedbackVectorSpec feedback_spec(zone);
2037 3750 : BytecodeArrayBuilder builder(zone, 1, 0, &feedback_spec);
2038 :
2039 2250 : FeedbackSlot string_add_slot = feedback_spec.AddBinaryOpICSlot();
2040 : FeedbackSlot slot = feedback_spec.AddCompareICSlot();
2041 : Handle<i::FeedbackMetadata> metadata =
2042 : NewFeedbackMetadata(isolate, &feedback_spec);
2043 :
2044 : // lhs is in a register, rhs is in the accumulator.
2045 2250 : Register lhs_reg = builder.register_allocator()->NewRegister();
2046 :
2047 2250 : if (which_side == kRhsIsString) {
2048 : // Comparison with HeapNumber on the lhs and String on the rhs.
2049 :
2050 750 : builder.LoadLiteral(lhs).StoreAccumulatorInRegister(lhs_reg);
2051 :
2052 750 : if (string_type == kInternalizedStringConstant) {
2053 : // rhs string is internalized.
2054 750 : builder.LoadLiteral(ast_factory.GetOneByteString(rhs_cstr));
2055 : } else {
2056 0 : CHECK_EQ(string_type, kComputedString);
2057 : // rhs string is not internalized (append a space to the end).
2058 : LoadStringAndAddSpace(&builder, &ast_factory, rhs_cstr,
2059 0 : string_add_slot);
2060 : }
2061 750 : break;
2062 : } else {
2063 1500 : CHECK_EQ(which_side, kLhsIsString);
2064 : // Comparison with String on the lhs and HeapNumber on the rhs.
2065 :
2066 1500 : if (string_type == kInternalizedStringConstant) {
2067 : // lhs string is internalized
2068 750 : builder.LoadLiteral(ast_factory.GetOneByteString(lhs_cstr));
2069 : } else {
2070 750 : CHECK_EQ(string_type, kComputedString);
2071 : // lhs string is not internalized (append a space to the end).
2072 : LoadStringAndAddSpace(&builder, &ast_factory, lhs_cstr,
2073 750 : string_add_slot);
2074 : }
2075 1500 : builder.StoreAccumulatorInRegister(lhs_reg);
2076 :
2077 1500 : builder.LoadLiteral(rhs);
2078 : }
2079 :
2080 1500 : builder.CompareOperation(comparison, lhs_reg, GetIndex(slot))
2081 1500 : .Return();
2082 :
2083 1500 : ast_factory.Internalize(isolate);
2084 : Handle<BytecodeArray> bytecode_array =
2085 1500 : builder.ToBytecodeArray(isolate);
2086 3000 : InterpreterTester tester(isolate, bytecode_array, metadata);
2087 : auto callable = tester.GetCallable<>();
2088 : Handle<Object> return_value = callable().ToHandleChecked();
2089 1500 : CHECK(return_value->IsBoolean());
2090 3000 : CHECK_EQ(return_value->BooleanValue(isolate),
2091 : CompareC(comparison, lhs, rhs, true));
2092 1500 : if (tester.HasFeedbackMetadata()) {
2093 : MaybeObject feedback = callable.vector()->Get(slot);
2094 1500 : CHECK(feedback->IsSmi());
2095 : // Comparison with a number and string collects kAny feedback.
2096 1500 : CHECK_EQ(CompareOperationFeedback::kAny,
2097 : feedback->ToSmi().value());
2098 : }
2099 : }
2100 : }
2101 : }
2102 : }
2103 : }
2104 5 : }
2105 :
2106 26661 : TEST(InterpreterStrictNotEqual) {
2107 10 : HandleAndZoneScope handles;
2108 : Isolate* isolate = handles.main_isolate();
2109 : Factory* factory = isolate->factory();
2110 : const char* code_snippet =
2111 : "function f(lhs, rhs) {\n"
2112 : " return lhs !== rhs;\n"
2113 : "}\n"
2114 : "f(0, 0);\n";
2115 10 : InterpreterTester tester(isolate, code_snippet);
2116 : auto callable = tester.GetCallable<Handle<Object>, Handle<Object>>();
2117 :
2118 : // Test passing different types.
2119 5 : const char* inputs[] = {"-1.77", "-40.333", "0.01", "55.77e5", "2.01"};
2120 55 : for (size_t i = 0; i < arraysize(inputs); i++) {
2121 275 : for (size_t j = 0; j < arraysize(inputs); j++) {
2122 125 : double lhs = StringToDouble(inputs[i], ConversionFlags::NO_FLAGS);
2123 125 : double rhs = StringToDouble(inputs[j], ConversionFlags::NO_FLAGS);
2124 125 : Handle<Object> lhs_obj = factory->NewNumber(lhs);
2125 125 : Handle<Object> rhs_obj = factory->NewStringFromAsciiChecked(inputs[j]);
2126 :
2127 : Handle<Object> return_value =
2128 250 : callable(lhs_obj, rhs_obj).ToHandleChecked();
2129 125 : CHECK(return_value->IsBoolean());
2130 250 : CHECK_EQ(return_value->BooleanValue(isolate),
2131 : CompareC(Token::Value::NE_STRICT, lhs, rhs, true));
2132 : }
2133 : }
2134 :
2135 : // Test passing string types.
2136 5 : const char* inputs_str[] = {"A", "abc", "z", "", "Foo!", "Foo"};
2137 65 : for (size_t i = 0; i < arraysize(inputs_str); i++) {
2138 390 : for (size_t j = 0; j < arraysize(inputs_str); j++) {
2139 : Handle<Object> lhs_obj =
2140 180 : factory->NewStringFromAsciiChecked(inputs_str[i]);
2141 : Handle<Object> rhs_obj =
2142 180 : factory->NewStringFromAsciiChecked(inputs_str[j]);
2143 :
2144 : Handle<Object> return_value =
2145 360 : callable(lhs_obj, rhs_obj).ToHandleChecked();
2146 180 : CHECK(return_value->IsBoolean());
2147 360 : CHECK_EQ(return_value->BooleanValue(isolate),
2148 : CompareC(Token::Value::NE_STRICT, inputs_str[i], inputs_str[j]));
2149 : }
2150 : }
2151 :
2152 : // Test passing doubles.
2153 : double inputs_number[] = {std::numeric_limits<double>::min(),
2154 : std::numeric_limits<double>::max(),
2155 : -0.001,
2156 : 0.01,
2157 : 0.1000001,
2158 : 1e99,
2159 5 : -1e-99};
2160 75 : for (size_t i = 0; i < arraysize(inputs_number); i++) {
2161 525 : for (size_t j = 0; j < arraysize(inputs_number); j++) {
2162 245 : Handle<Object> lhs_obj = factory->NewNumber(inputs_number[i]);
2163 245 : Handle<Object> rhs_obj = factory->NewNumber(inputs_number[j]);
2164 :
2165 : Handle<Object> return_value =
2166 490 : callable(lhs_obj, rhs_obj).ToHandleChecked();
2167 245 : CHECK(return_value->IsBoolean());
2168 490 : CHECK_EQ(return_value->BooleanValue(isolate),
2169 : CompareC(Token::Value::NE_STRICT, inputs_number[i],
2170 : inputs_number[j]));
2171 : }
2172 : }
2173 5 : }
2174 :
2175 26661 : TEST(InterpreterCompareTypeOf) {
2176 : typedef TestTypeOfFlags::LiteralFlag LiteralFlag;
2177 10 : HandleAndZoneScope handles;
2178 : Isolate* isolate = handles.main_isolate();
2179 : Factory* factory = isolate->factory();
2180 : Zone* zone = handles.main_zone();
2181 : std::pair<Handle<Object>, LiteralFlag> inputs[] = {
2182 : {handle(Smi::FromInt(24), isolate), LiteralFlag::kNumber},
2183 10 : {factory->NewNumber(2.5), LiteralFlag::kNumber},
2184 10 : {factory->NewStringFromAsciiChecked("foo"), LiteralFlag::kString},
2185 : {factory
2186 10 : ->NewConsString(factory->NewStringFromAsciiChecked("foo"),
2187 5 : factory->NewStringFromAsciiChecked("bar"))
2188 : .ToHandleChecked(),
2189 : LiteralFlag::kString},
2190 : {factory->prototype_string(), LiteralFlag::kString},
2191 10 : {factory->NewSymbol(), LiteralFlag::kSymbol},
2192 : {factory->true_value(), LiteralFlag::kBoolean},
2193 : {factory->false_value(), LiteralFlag::kBoolean},
2194 : {factory->undefined_value(), LiteralFlag::kUndefined},
2195 10 : {InterpreterTester::NewObject(
2196 : "(function() { return function() {}; })();"),
2197 : LiteralFlag::kFunction},
2198 10 : {InterpreterTester::NewObject("new Object();"), LiteralFlag::kObject},
2199 : {factory->null_value(), LiteralFlag::kObject},
2200 : };
2201 : const LiteralFlag kLiterals[] = {
2202 : #define LITERAL_FLAG(name, _) LiteralFlag::k##name,
2203 : TYPEOF_LITERAL_LIST(LITERAL_FLAG)
2204 : #undef LITERAL_FLAG
2205 5 : };
2206 :
2207 95 : for (size_t l = 0; l < arraysize(kLiterals); l++) {
2208 45 : LiteralFlag literal_flag = kLiterals[l];
2209 50 : if (literal_flag == LiteralFlag::kOther) continue;
2210 :
2211 80 : BytecodeArrayBuilder builder(zone, 1, 0);
2212 40 : builder.LoadAccumulatorWithRegister(builder.Receiver())
2213 40 : .CompareTypeOf(kLiterals[l])
2214 40 : .Return();
2215 40 : Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(isolate);
2216 80 : InterpreterTester tester(isolate, bytecode_array);
2217 : auto callable = tester.GetCallable<Handle<Object>>();
2218 :
2219 1000 : for (size_t i = 0; i < arraysize(inputs); i++) {
2220 960 : Handle<Object> return_value = callable(inputs[i].first).ToHandleChecked();
2221 480 : CHECK(return_value->IsBoolean());
2222 960 : CHECK_EQ(return_value->BooleanValue(isolate),
2223 : inputs[i].second == literal_flag);
2224 : }
2225 : }
2226 5 : }
2227 :
2228 26661 : TEST(InterpreterInstanceOf) {
2229 10 : HandleAndZoneScope handles;
2230 : Isolate* isolate = handles.main_isolate();
2231 : Zone* zone = handles.main_zone();
2232 : Factory* factory = isolate->factory();
2233 5 : Handle<i::String> name = factory->NewStringFromAsciiChecked("cons");
2234 5 : Handle<i::JSFunction> func = factory->NewFunctionForTest(name);
2235 5 : Handle<i::JSObject> instance = factory->NewJSObject(func);
2236 5 : Handle<i::Object> other = factory->NewNumber(3.3333);
2237 5 : Handle<i::Object> cases[] = {Handle<i::Object>::cast(instance), other};
2238 25 : for (size_t i = 0; i < arraysize(cases); i++) {
2239 10 : bool expected_value = (i == 0);
2240 : FeedbackVectorSpec feedback_spec(zone);
2241 20 : BytecodeArrayBuilder builder(zone, 1, 1, &feedback_spec);
2242 :
2243 : Register r0(0);
2244 10 : size_t case_entry = builder.AllocateDeferredConstantPoolEntry();
2245 10 : builder.SetDeferredConstantPoolEntry(case_entry, cases[i]);
2246 10 : builder.LoadConstantPoolEntry(case_entry).StoreAccumulatorInRegister(r0);
2247 :
2248 : FeedbackSlot slot = feedback_spec.AddInstanceOfSlot();
2249 : Handle<i::FeedbackMetadata> metadata =
2250 : NewFeedbackMetadata(isolate, &feedback_spec);
2251 :
2252 10 : size_t func_entry = builder.AllocateDeferredConstantPoolEntry();
2253 10 : builder.SetDeferredConstantPoolEntry(func_entry, func);
2254 10 : builder.LoadConstantPoolEntry(func_entry)
2255 10 : .CompareOperation(Token::Value::INSTANCEOF, r0, GetIndex(slot))
2256 10 : .Return();
2257 :
2258 10 : Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(isolate);
2259 20 : InterpreterTester tester(isolate, bytecode_array, metadata);
2260 : auto callable = tester.GetCallable<>();
2261 : Handle<Object> return_value = callable().ToHandleChecked();
2262 10 : CHECK(return_value->IsBoolean());
2263 10 : CHECK_EQ(return_value->BooleanValue(isolate), expected_value);
2264 : }
2265 5 : }
2266 :
2267 26661 : TEST(InterpreterTestIn) {
2268 10 : HandleAndZoneScope handles;
2269 : Isolate* isolate = handles.main_isolate();
2270 : Zone* zone = handles.main_zone();
2271 : Factory* factory = isolate->factory();
2272 : AstValueFactory ast_factory(zone, isolate->ast_string_constants(),
2273 5 : HashSeed(isolate));
2274 : // Allocate an array
2275 : Handle<i::JSArray> array =
2276 : factory->NewJSArray(0, i::ElementsKind::PACKED_SMI_ELEMENTS);
2277 : // Check for these properties on the array object
2278 5 : const char* properties[] = {"length", "fuzzle", "x", "0"};
2279 45 : for (size_t i = 0; i < arraysize(properties); i++) {
2280 20 : bool expected_value = (i == 0);
2281 : FeedbackVectorSpec feedback_spec(zone);
2282 40 : BytecodeArrayBuilder builder(zone, 1, 1, &feedback_spec);
2283 :
2284 : Register r0(0);
2285 20 : builder.LoadLiteral(ast_factory.GetOneByteString(properties[i]))
2286 20 : .StoreAccumulatorInRegister(r0);
2287 :
2288 : FeedbackSlot slot = feedback_spec.AddKeyedHasICSlot();
2289 : Handle<i::FeedbackMetadata> metadata =
2290 : NewFeedbackMetadata(isolate, &feedback_spec);
2291 :
2292 20 : size_t array_entry = builder.AllocateDeferredConstantPoolEntry();
2293 20 : builder.SetDeferredConstantPoolEntry(array_entry, array);
2294 20 : builder.LoadConstantPoolEntry(array_entry)
2295 20 : .CompareOperation(Token::Value::IN, r0, GetIndex(slot))
2296 20 : .Return();
2297 :
2298 20 : ast_factory.Internalize(isolate);
2299 20 : Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(isolate);
2300 40 : InterpreterTester tester(isolate, bytecode_array, metadata);
2301 : auto callable = tester.GetCallable<>();
2302 : Handle<Object> return_value = callable().ToHandleChecked();
2303 20 : CHECK(return_value->IsBoolean());
2304 20 : CHECK_EQ(return_value->BooleanValue(isolate), expected_value);
2305 : }
2306 5 : }
2307 :
2308 26661 : TEST(InterpreterUnaryNot) {
2309 10 : HandleAndZoneScope handles;
2310 : Isolate* isolate = handles.main_isolate();
2311 : Zone* zone = handles.main_zone();
2312 95 : for (size_t i = 1; i < 10; i++) {
2313 45 : bool expected_value = ((i & 1) == 1);
2314 90 : BytecodeArrayBuilder builder(zone, 1, 0);
2315 :
2316 : Register r0(0);
2317 45 : builder.LoadFalse();
2318 495 : for (size_t j = 0; j < i; j++) {
2319 225 : builder.LogicalNot(ToBooleanMode::kAlreadyBoolean);
2320 : }
2321 45 : builder.Return();
2322 45 : Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(isolate);
2323 90 : InterpreterTester tester(isolate, bytecode_array);
2324 : auto callable = tester.GetCallable<>();
2325 : Handle<Object> return_value = callable().ToHandleChecked();
2326 45 : CHECK(return_value->IsBoolean());
2327 45 : CHECK_EQ(return_value->BooleanValue(isolate), expected_value);
2328 : }
2329 5 : }
2330 :
2331 26661 : TEST(InterpreterUnaryNotNonBoolean) {
2332 10 : HandleAndZoneScope handles;
2333 : Isolate* isolate = handles.main_isolate();
2334 : Zone* zone = handles.main_zone();
2335 : AstValueFactory ast_factory(zone, isolate->ast_string_constants(),
2336 5 : HashSeed(isolate));
2337 :
2338 : std::pair<LiteralForTest, bool> object_type_tuples[] = {
2339 : std::make_pair(LiteralForTest(LiteralForTest::kUndefined), true),
2340 : std::make_pair(LiteralForTest(LiteralForTest::kNull), true),
2341 : std::make_pair(LiteralForTest(LiteralForTest::kFalse), true),
2342 : std::make_pair(LiteralForTest(LiteralForTest::kTrue), false),
2343 : std::make_pair(LiteralForTest(9.1), false),
2344 : std::make_pair(LiteralForTest(0), true),
2345 : std::make_pair(LiteralForTest(ast_factory.GetOneByteString("hello")),
2346 5 : false),
2347 5 : std::make_pair(LiteralForTest(ast_factory.GetOneByteString("")), true),
2348 : };
2349 :
2350 85 : for (size_t i = 0; i < arraysize(object_type_tuples); i++) {
2351 80 : BytecodeArrayBuilder builder(zone, 1, 0);
2352 :
2353 : Register r0(0);
2354 40 : LoadLiteralForTest(&builder, object_type_tuples[i].first);
2355 40 : builder.LogicalNot(ToBooleanMode::kConvertToBoolean).Return();
2356 40 : ast_factory.Internalize(isolate);
2357 40 : Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(isolate);
2358 80 : InterpreterTester tester(isolate, bytecode_array);
2359 : auto callable = tester.GetCallable<>();
2360 : Handle<Object> return_value = callable().ToHandleChecked();
2361 40 : CHECK(return_value->IsBoolean());
2362 80 : CHECK_EQ(return_value->BooleanValue(isolate), object_type_tuples[i].second);
2363 : }
2364 5 : }
2365 :
2366 26661 : TEST(InterpreterTypeof) {
2367 10 : HandleAndZoneScope handles;
2368 : Isolate* isolate = handles.main_isolate();
2369 :
2370 : std::pair<const char*, const char*> typeof_vals[] = {
2371 : std::make_pair("return typeof undefined;", "undefined"),
2372 : std::make_pair("return typeof null;", "object"),
2373 : std::make_pair("return typeof true;", "boolean"),
2374 : std::make_pair("return typeof false;", "boolean"),
2375 : std::make_pair("return typeof 9.1;", "number"),
2376 : std::make_pair("return typeof 7771;", "number"),
2377 : std::make_pair("return typeof 'hello';", "string"),
2378 : std::make_pair("return typeof global_unallocated;", "undefined"),
2379 5 : };
2380 :
2381 85 : for (size_t i = 0; i < arraysize(typeof_vals); i++) {
2382 40 : std::string source(InterpreterTester::SourceForBody(typeof_vals[i].first));
2383 80 : InterpreterTester tester(isolate, source.c_str());
2384 :
2385 : auto callable = tester.GetCallable<>();
2386 : Handle<v8::internal::String> return_value =
2387 : Handle<v8::internal::String>::cast(callable().ToHandleChecked());
2388 40 : auto actual = return_value->ToCString();
2389 80 : CHECK_EQ(strcmp(&actual[0], typeof_vals[i].second), 0);
2390 : }
2391 5 : }
2392 :
2393 26661 : TEST(InterpreterCallRuntime) {
2394 10 : HandleAndZoneScope handles;
2395 : Isolate* isolate = handles.main_isolate();
2396 : Zone* zone = handles.main_zone();
2397 :
2398 10 : BytecodeArrayBuilder builder(zone, 1, 2);
2399 5 : RegisterList args = builder.register_allocator()->NewRegisterList(2);
2400 :
2401 5 : builder.LoadLiteral(Smi::FromInt(15))
2402 5 : .StoreAccumulatorInRegister(args[0])
2403 5 : .LoadLiteral(Smi::FromInt(40))
2404 5 : .StoreAccumulatorInRegister(args[1])
2405 5 : .CallRuntime(Runtime::kAdd, args)
2406 5 : .Return();
2407 5 : Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(isolate);
2408 :
2409 10 : InterpreterTester tester(isolate, bytecode_array);
2410 : auto callable = tester.GetCallable<>();
2411 :
2412 : Handle<Object> return_val = callable().ToHandleChecked();
2413 5 : CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(55));
2414 5 : }
2415 :
2416 26661 : TEST(InterpreterInvokeIntrinsic) {
2417 10 : HandleAndZoneScope handles;
2418 : Isolate* isolate = handles.main_isolate();
2419 : Zone* zone = handles.main_zone();
2420 :
2421 10 : BytecodeArrayBuilder builder(zone, 1, 2);
2422 :
2423 5 : builder.LoadLiteral(Smi::FromInt(15))
2424 10 : .StoreAccumulatorInRegister(Register(0))
2425 10 : .CallRuntime(Runtime::kInlineIsArray, Register(0))
2426 5 : .Return();
2427 5 : Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(isolate);
2428 :
2429 10 : InterpreterTester tester(isolate, bytecode_array);
2430 : auto callable = tester.GetCallable<>();
2431 :
2432 : Handle<Object> return_val = callable().ToHandleChecked();
2433 5 : CHECK(return_val->IsBoolean());
2434 5 : CHECK_EQ(return_val->BooleanValue(isolate), false);
2435 5 : }
2436 :
2437 26661 : TEST(InterpreterFunctionLiteral) {
2438 10 : HandleAndZoneScope handles;
2439 : Isolate* isolate = handles.main_isolate();
2440 :
2441 : // Test calling a function literal.
2442 : std::string source(
2443 15 : "function " + InterpreterTester::function_name() + "(a) {\n"
2444 : " return (function(x){ return x + 2; })(a);\n"
2445 5 : "}");
2446 10 : InterpreterTester tester(isolate, source.c_str());
2447 : auto callable = tester.GetCallable<Handle<Object>>();
2448 :
2449 10 : Handle<i::Object> return_val = callable(
2450 5 : Handle<Smi>(Smi::FromInt(3), handles.main_isolate())).ToHandleChecked();
2451 5 : CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(5));
2452 5 : }
2453 :
2454 26661 : TEST(InterpreterRegExpLiterals) {
2455 10 : HandleAndZoneScope handles;
2456 : Isolate* isolate = handles.main_isolate();
2457 : Factory* factory = isolate->factory();
2458 :
2459 : std::pair<const char*, Handle<Object>> literals[] = {
2460 : std::make_pair("return /abd/.exec('cccabbdd');\n",
2461 : factory->null_value()),
2462 : std::make_pair("return /ab+d/.exec('cccabbdd')[0];\n",
2463 10 : factory->NewStringFromStaticChars("abbd")),
2464 : std::make_pair("return /AbC/i.exec('ssaBC')[0];\n",
2465 10 : factory->NewStringFromStaticChars("aBC")),
2466 : std::make_pair("return 'ssaBC'.match(/AbC/i)[0];\n",
2467 10 : factory->NewStringFromStaticChars("aBC")),
2468 : std::make_pair("return 'ssaBCtAbC'.match(/(AbC)/gi)[1];\n",
2469 10 : factory->NewStringFromStaticChars("AbC")),
2470 : };
2471 :
2472 55 : for (size_t i = 0; i < arraysize(literals); i++) {
2473 25 : std::string source(InterpreterTester::SourceForBody(literals[i].first));
2474 50 : InterpreterTester tester(isolate, source.c_str());
2475 : auto callable = tester.GetCallable<>();
2476 :
2477 : Handle<i::Object> return_value = callable().ToHandleChecked();
2478 50 : CHECK(return_value->SameValue(*literals[i].second));
2479 : }
2480 5 : }
2481 :
2482 26661 : TEST(InterpreterArrayLiterals) {
2483 10 : HandleAndZoneScope handles;
2484 : Isolate* isolate = handles.main_isolate();
2485 : Factory* factory = isolate->factory();
2486 :
2487 : std::pair<const char*, Handle<Object>> literals[] = {
2488 : std::make_pair("return [][0];\n",
2489 : factory->undefined_value()),
2490 : std::make_pair("return [1, 3, 2][1];\n",
2491 : handle(Smi::FromInt(3), isolate)),
2492 : std::make_pair("return ['a', 'b', 'c'][2];\n",
2493 10 : factory->NewStringFromStaticChars("c")),
2494 : std::make_pair("var a = 100; return [a, a + 1, a + 2, a + 3][2];\n",
2495 : handle(Smi::FromInt(102), isolate)),
2496 : std::make_pair("return [[1, 2, 3], ['a', 'b', 'c']][1][0];\n",
2497 10 : factory->NewStringFromStaticChars("a")),
2498 : std::make_pair("var t = 't'; return [[t, t + 'est'], [1 + t]][0][1];\n",
2499 10 : factory->NewStringFromStaticChars("test"))
2500 : };
2501 :
2502 65 : for (size_t i = 0; i < arraysize(literals); i++) {
2503 30 : std::string source(InterpreterTester::SourceForBody(literals[i].first));
2504 60 : InterpreterTester tester(isolate, source.c_str());
2505 : auto callable = tester.GetCallable<>();
2506 :
2507 : Handle<i::Object> return_value = callable().ToHandleChecked();
2508 60 : CHECK(return_value->SameValue(*literals[i].second));
2509 : }
2510 5 : }
2511 :
2512 26661 : TEST(InterpreterObjectLiterals) {
2513 10 : HandleAndZoneScope handles;
2514 : Isolate* isolate = handles.main_isolate();
2515 : Factory* factory = isolate->factory();
2516 :
2517 : std::pair<const char*, Handle<Object>> literals[] = {
2518 : std::make_pair("return { }.name;",
2519 : factory->undefined_value()),
2520 : std::make_pair("return { name: 'string', val: 9.2 }.name;",
2521 10 : factory->NewStringFromStaticChars("string")),
2522 : std::make_pair("var a = 15; return { name: 'string', val: a }.val;",
2523 : handle(Smi::FromInt(15), isolate)),
2524 : std::make_pair("var a = 5; return { val: a, val: a + 1 }.val;",
2525 : handle(Smi::FromInt(6), isolate)),
2526 : std::make_pair("return { func: function() { return 'test' } }.func();",
2527 10 : factory->NewStringFromStaticChars("test")),
2528 : std::make_pair("return { func(a) { return a + 'st'; } }.func('te');",
2529 10 : factory->NewStringFromStaticChars("test")),
2530 : std::make_pair("return { get a() { return 22; } }.a;",
2531 : handle(Smi::FromInt(22), isolate)),
2532 : std::make_pair("var a = { get b() { return this.x + 't'; },\n"
2533 : " set b(val) { this.x = val + 's' } };\n"
2534 : "a.b = 'te';\n"
2535 : "return a.b;",
2536 10 : factory->NewStringFromStaticChars("test")),
2537 : std::make_pair("var a = 123; return { 1: a }[1];",
2538 : handle(Smi::FromInt(123), isolate)),
2539 : std::make_pair("return Object.getPrototypeOf({ __proto__: null });",
2540 : factory->null_value()),
2541 : std::make_pair("var a = 'test'; return { [a]: 1 }.test;",
2542 : handle(Smi::FromInt(1), isolate)),
2543 : std::make_pair("var a = 'test'; return { b: a, [a]: a + 'ing' }['test']",
2544 10 : factory->NewStringFromStaticChars("testing")),
2545 : std::make_pair("var a = 'proto_str';\n"
2546 : "var b = { [a]: 1, __proto__: { var : a } };\n"
2547 : "return Object.getPrototypeOf(b).var",
2548 10 : factory->NewStringFromStaticChars("proto_str")),
2549 : std::make_pair("var n = 'name';\n"
2550 : "return { [n]: 'val', get a() { return 987 } }['a'];",
2551 : handle(Smi::FromInt(987), isolate)),
2552 : };
2553 :
2554 145 : for (size_t i = 0; i < arraysize(literals); i++) {
2555 70 : std::string source(InterpreterTester::SourceForBody(literals[i].first));
2556 140 : InterpreterTester tester(isolate, source.c_str());
2557 : auto callable = tester.GetCallable<>();
2558 :
2559 : Handle<i::Object> return_value = callable().ToHandleChecked();
2560 140 : CHECK(return_value->SameValue(*literals[i].second));
2561 : }
2562 5 : }
2563 :
2564 26661 : TEST(InterpreterConstruct) {
2565 10 : HandleAndZoneScope handles;
2566 : Isolate* isolate = handles.main_isolate();
2567 :
2568 : std::string source(
2569 : "function counter() { this.count = 0; }\n"
2570 10 : "function " +
2571 10 : InterpreterTester::function_name() +
2572 : "() {\n"
2573 : " var c = new counter();\n"
2574 : " return c.count;\n"
2575 5 : "}");
2576 10 : InterpreterTester tester(isolate, source.c_str());
2577 : auto callable = tester.GetCallable<>();
2578 :
2579 : Handle<Object> return_val = callable().ToHandleChecked();
2580 5 : CHECK_EQ(Smi::cast(*return_val), Smi::kZero);
2581 5 : }
2582 :
2583 26661 : TEST(InterpreterConstructWithArgument) {
2584 10 : HandleAndZoneScope handles;
2585 : Isolate* isolate = handles.main_isolate();
2586 :
2587 : std::string source(
2588 : "function counter(arg0) { this.count = 17; this.x = arg0; }\n"
2589 10 : "function " +
2590 10 : InterpreterTester::function_name() +
2591 : "() {\n"
2592 : " var c = new counter(3);\n"
2593 : " return c.x;\n"
2594 5 : "}");
2595 10 : InterpreterTester tester(isolate, source.c_str());
2596 : auto callable = tester.GetCallable<>();
2597 :
2598 : Handle<Object> return_val = callable().ToHandleChecked();
2599 5 : CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(3));
2600 5 : }
2601 :
2602 26661 : TEST(InterpreterConstructWithArguments) {
2603 10 : HandleAndZoneScope handles;
2604 : Isolate* isolate = handles.main_isolate();
2605 :
2606 : std::string source(
2607 : "function counter(arg0, arg1) {\n"
2608 : " this.count = 7; this.x = arg0; this.y = arg1;\n"
2609 : "}\n"
2610 10 : "function " +
2611 10 : InterpreterTester::function_name() +
2612 : "() {\n"
2613 : " var c = new counter(3, 5);\n"
2614 : " return c.count + c.x + c.y;\n"
2615 5 : "}");
2616 10 : InterpreterTester tester(isolate, source.c_str());
2617 : auto callable = tester.GetCallable<>();
2618 :
2619 : Handle<Object> return_val = callable().ToHandleChecked();
2620 5 : CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(15));
2621 5 : }
2622 :
2623 26661 : TEST(InterpreterContextVariables) {
2624 10 : HandleAndZoneScope handles;
2625 : Isolate* isolate = handles.main_isolate();
2626 :
2627 10 : std::ostringstream unique_vars;
2628 2505 : for (int i = 0; i < 250; i++) {
2629 1250 : unique_vars << "var a" << i << " = 0;";
2630 : }
2631 : std::pair<std::string, Handle<Object>> context_vars[] = {
2632 : std::make_pair("var a; (function() { a = 1; })(); return a;",
2633 : handle(Smi::FromInt(1), isolate)),
2634 : std::make_pair("var a = 10; (function() { a; })(); return a;",
2635 : handle(Smi::FromInt(10), isolate)),
2636 : std::make_pair("var a = 20; var b = 30;\n"
2637 : "return (function() { return a + b; })();",
2638 : handle(Smi::FromInt(50), isolate)),
2639 : std::make_pair("'use strict'; let a = 1;\n"
2640 : "{ let b = 2; return (function() { return a + b; })(); }",
2641 : handle(Smi::FromInt(3), isolate)),
2642 : std::make_pair("'use strict'; let a = 10;\n"
2643 : "{ let b = 20; var c = function() { [a, b] };\n"
2644 : " return a + b; }",
2645 : handle(Smi::FromInt(30), isolate)),
2646 25 : std::make_pair("'use strict';" + unique_vars.str() +
2647 : "eval(); var b = 100; return b;",
2648 : handle(Smi::FromInt(100), isolate)),
2649 35 : };
2650 :
2651 65 : for (size_t i = 0; i < arraysize(context_vars); i++) {
2652 : std::string source(
2653 30 : InterpreterTester::SourceForBody(context_vars[i].first.c_str()));
2654 60 : InterpreterTester tester(isolate, source.c_str());
2655 : auto callable = tester.GetCallable<>();
2656 :
2657 : Handle<i::Object> return_value = callable().ToHandleChecked();
2658 60 : CHECK(return_value->SameValue(*context_vars[i].second));
2659 : }
2660 5 : }
2661 :
2662 26661 : TEST(InterpreterContextParameters) {
2663 10 : HandleAndZoneScope handles;
2664 : Isolate* isolate = handles.main_isolate();
2665 :
2666 : std::pair<const char*, Handle<Object>> context_params[] = {
2667 : std::make_pair("return (function() { return arg1; })();",
2668 : handle(Smi::FromInt(1), isolate)),
2669 : std::make_pair("(function() { arg1 = 4; })(); return arg1;",
2670 : handle(Smi::FromInt(4), isolate)),
2671 : std::make_pair("(function() { arg3 = arg2 - arg1; })(); return arg3;",
2672 : handle(Smi::FromInt(1), isolate)),
2673 : };
2674 :
2675 35 : for (size_t i = 0; i < arraysize(context_params); i++) {
2676 60 : std::string source = "function " + InterpreterTester::function_name() +
2677 45 : "(arg1, arg2, arg3) {" + context_params[i].first + "}";
2678 30 : InterpreterTester tester(isolate, source.c_str());
2679 : auto callable =
2680 : tester.GetCallable<Handle<Object>, Handle<Object>, Handle<Object>>();
2681 :
2682 : Handle<Object> a1 = handle(Smi::FromInt(1), isolate);
2683 : Handle<Object> a2 = handle(Smi::FromInt(2), isolate);
2684 : Handle<Object> a3 = handle(Smi::FromInt(3), isolate);
2685 : Handle<i::Object> return_value = callable(a1, a2, a3).ToHandleChecked();
2686 30 : CHECK(return_value->SameValue(*context_params[i].second));
2687 : }
2688 5 : }
2689 :
2690 26661 : TEST(InterpreterOuterContextVariables) {
2691 10 : HandleAndZoneScope handles;
2692 : Isolate* isolate = handles.main_isolate();
2693 :
2694 : std::pair<const char*, Handle<Object>> context_vars[] = {
2695 : std::make_pair("return outerVar * innerArg;",
2696 : handle(Smi::FromInt(200), isolate)),
2697 : std::make_pair("outerVar = innerArg; return outerVar",
2698 : handle(Smi::FromInt(20), isolate)),
2699 : };
2700 :
2701 : std::string header(
2702 : "function Outer() {"
2703 : " var outerVar = 10;"
2704 : " function Inner(innerArg) {"
2705 5 : " this.innerFunc = function() { ");
2706 : std::string footer(
2707 : " }}"
2708 : " this.getInnerFunc = function() { return new Inner(20).innerFunc; }"
2709 : "}"
2710 5 : "var f = new Outer().getInnerFunc();");
2711 :
2712 25 : for (size_t i = 0; i < arraysize(context_vars); i++) {
2713 30 : std::string source = header + context_vars[i].first + footer;
2714 20 : InterpreterTester tester(isolate, source.c_str(), "*");
2715 : auto callable = tester.GetCallable<>();
2716 :
2717 : Handle<i::Object> return_value = callable().ToHandleChecked();
2718 20 : CHECK(return_value->SameValue(*context_vars[i].second));
2719 : }
2720 5 : }
2721 :
2722 26661 : TEST(InterpreterComma) {
2723 10 : HandleAndZoneScope handles;
2724 : Isolate* isolate = handles.main_isolate();
2725 : Factory* factory = isolate->factory();
2726 :
2727 : std::pair<const char*, Handle<Object>> literals[] = {
2728 : std::make_pair("var a; return 0, a;\n", factory->undefined_value()),
2729 : std::make_pair("return 'a', 2.2, 3;\n",
2730 : handle(Smi::FromInt(3), isolate)),
2731 : std::make_pair("return 'a', 'b', 'c';\n",
2732 10 : factory->NewStringFromStaticChars("c")),
2733 10 : std::make_pair("return 3.2, 2.3, 4.5;\n", factory->NewNumber(4.5)),
2734 : std::make_pair("var a = 10; return b = a, b = b+1;\n",
2735 : handle(Smi::FromInt(11), isolate)),
2736 : std::make_pair("var a = 10; return b = a, b = b+1, b + 10;\n",
2737 5 : handle(Smi::FromInt(21), isolate))};
2738 :
2739 65 : for (size_t i = 0; i < arraysize(literals); i++) {
2740 30 : std::string source(InterpreterTester::SourceForBody(literals[i].first));
2741 60 : InterpreterTester tester(isolate, source.c_str());
2742 : auto callable = tester.GetCallable<>();
2743 :
2744 : Handle<i::Object> return_value = callable().ToHandleChecked();
2745 60 : CHECK(return_value->SameValue(*literals[i].second));
2746 : }
2747 5 : }
2748 :
2749 26661 : TEST(InterpreterLogicalOr) {
2750 10 : HandleAndZoneScope handles;
2751 : Isolate* isolate = handles.main_isolate();
2752 : Factory* factory = isolate->factory();
2753 :
2754 : std::pair<const char*, Handle<Object>> literals[] = {
2755 : std::make_pair("var a, b; return a || b;\n", factory->undefined_value()),
2756 : std::make_pair("var a, b = 10; return a || b;\n",
2757 : handle(Smi::FromInt(10), isolate)),
2758 : std::make_pair("var a = '0', b = 10; return a || b;\n",
2759 10 : factory->NewStringFromStaticChars("0")),
2760 10 : std::make_pair("return 0 || 3.2;\n", factory->NewNumber(3.2)),
2761 : std::make_pair("return 'a' || 0;\n",
2762 10 : factory->NewStringFromStaticChars("a")),
2763 : std::make_pair("var a = '0', b = 10; return (a == 0) || b;\n",
2764 5 : factory->true_value())};
2765 :
2766 65 : for (size_t i = 0; i < arraysize(literals); i++) {
2767 30 : std::string source(InterpreterTester::SourceForBody(literals[i].first));
2768 60 : InterpreterTester tester(isolate, source.c_str());
2769 : auto callable = tester.GetCallable<>();
2770 :
2771 : Handle<i::Object> return_value = callable().ToHandleChecked();
2772 60 : CHECK(return_value->SameValue(*literals[i].second));
2773 : }
2774 5 : }
2775 :
2776 26661 : TEST(InterpreterLogicalAnd) {
2777 10 : HandleAndZoneScope handles;
2778 : Isolate* isolate = handles.main_isolate();
2779 : Factory* factory = isolate->factory();
2780 :
2781 : std::pair<const char*, Handle<Object>> literals[] = {
2782 : std::make_pair("var a, b = 10; return a && b;\n",
2783 : factory->undefined_value()),
2784 : std::make_pair("var a = 0, b = 10; return a && b / a;\n",
2785 : handle(Smi::kZero, isolate)),
2786 : std::make_pair("var a = '0', b = 10; return a && b;\n",
2787 : handle(Smi::FromInt(10), isolate)),
2788 : std::make_pair("return 0.0 && 3.2;\n", handle(Smi::kZero, isolate)),
2789 : std::make_pair("return 'a' && 'b';\n",
2790 10 : factory->NewStringFromStaticChars("b")),
2791 : std::make_pair("return 'a' && 0 || 'b', 'c';\n",
2792 10 : factory->NewStringFromStaticChars("c")),
2793 : std::make_pair("var x = 1, y = 3; return x && 0 + 1 || y;\n",
2794 : handle(Smi::FromInt(1), isolate)),
2795 : std::make_pair("var x = 1, y = 3; return (x == 1) && (3 == 3) || y;\n",
2796 10 : factory->true_value())};
2797 :
2798 85 : for (size_t i = 0; i < arraysize(literals); i++) {
2799 40 : std::string source(InterpreterTester::SourceForBody(literals[i].first));
2800 80 : InterpreterTester tester(isolate, source.c_str());
2801 : auto callable = tester.GetCallable<>();
2802 :
2803 : Handle<i::Object> return_value = callable().ToHandleChecked();
2804 80 : CHECK(return_value->SameValue(*literals[i].second));
2805 : }
2806 5 : }
2807 :
2808 26661 : TEST(InterpreterTryCatch) {
2809 10 : HandleAndZoneScope handles;
2810 : Isolate* isolate = handles.main_isolate();
2811 :
2812 : std::pair<const char*, Handle<Object>> catches[] = {
2813 : std::make_pair("var a = 1; try { a = 2 } catch(e) { a = 3 }; return a;",
2814 : handle(Smi::FromInt(2), isolate)),
2815 : std::make_pair("var a; try { undef.x } catch(e) { a = 2 }; return a;",
2816 : handle(Smi::FromInt(2), isolate)),
2817 : std::make_pair("var a; try { throw 1 } catch(e) { a = e + 2 }; return a;",
2818 : handle(Smi::FromInt(3), isolate)),
2819 : std::make_pair("var a; try { throw 1 } catch(e) { a = e + 2 };"
2820 : " try { throw a } catch(e) { a = e + 3 }; return a;",
2821 : handle(Smi::FromInt(6), isolate)),
2822 : };
2823 :
2824 45 : for (size_t i = 0; i < arraysize(catches); i++) {
2825 20 : std::string source(InterpreterTester::SourceForBody(catches[i].first));
2826 40 : InterpreterTester tester(isolate, source.c_str());
2827 : auto callable = tester.GetCallable<>();
2828 :
2829 : Handle<i::Object> return_value = callable().ToHandleChecked();
2830 40 : CHECK(return_value->SameValue(*catches[i].second));
2831 : }
2832 5 : }
2833 :
2834 26661 : TEST(InterpreterTryFinally) {
2835 10 : HandleAndZoneScope handles;
2836 : Isolate* isolate = handles.main_isolate();
2837 : Factory* factory = isolate->factory();
2838 :
2839 : std::pair<const char*, Handle<Object>> finallies[] = {
2840 : std::make_pair(
2841 : "var a = 1; try { a = a + 1; } finally { a = a + 2; }; return a;",
2842 10 : factory->NewStringFromStaticChars("R4")),
2843 : std::make_pair(
2844 : "var a = 1; try { a = 2; return 23; } finally { a = 3 }; return a;",
2845 10 : factory->NewStringFromStaticChars("R23")),
2846 : std::make_pair(
2847 : "var a = 1; try { a = 2; throw 23; } finally { a = 3 }; return a;",
2848 10 : factory->NewStringFromStaticChars("E23")),
2849 : std::make_pair(
2850 : "var a = 1; try { a = 2; throw 23; } finally { return a; };",
2851 10 : factory->NewStringFromStaticChars("R2")),
2852 : std::make_pair(
2853 : "var a = 1; try { a = 2; throw 23; } finally { throw 42; };",
2854 10 : factory->NewStringFromStaticChars("E42")),
2855 : std::make_pair("var a = 1; for (var i = 10; i < 20; i += 5) {"
2856 : " try { a = 2; break; } finally { a = 3; }"
2857 : "} return a + i;",
2858 10 : factory->NewStringFromStaticChars("R13")),
2859 : std::make_pair("var a = 1; for (var i = 10; i < 20; i += 5) {"
2860 : " try { a = 2; continue; } finally { a = 3; }"
2861 : "} return a + i;",
2862 10 : factory->NewStringFromStaticChars("R23")),
2863 : std::make_pair("var a = 1; try { a = 2;"
2864 : " try { a = 3; throw 23; } finally { a = 4; }"
2865 : "} catch(e) { a = a + e; } return a;",
2866 10 : factory->NewStringFromStaticChars("R27")),
2867 : std::make_pair("var func_name;"
2868 : "function tcf2(a) {"
2869 : " try { throw new Error('boom');} "
2870 : " catch(e) {return 153; } "
2871 : " finally {func_name = tcf2.name;}"
2872 : "}"
2873 : "tcf2();"
2874 : "return func_name;",
2875 10 : factory->NewStringFromStaticChars("Rtcf2")),
2876 : };
2877 :
2878 : const char* try_wrapper =
2879 : "(function() { try { return 'R' + f() } catch(e) { return 'E' + e }})()";
2880 :
2881 95 : for (size_t i = 0; i < arraysize(finallies); i++) {
2882 45 : std::string source(InterpreterTester::SourceForBody(finallies[i].first));
2883 90 : InterpreterTester tester(isolate, source.c_str());
2884 : tester.GetCallable<>();
2885 : Handle<Object> wrapped = v8::Utils::OpenHandle(*CompileRun(try_wrapper));
2886 90 : CHECK(wrapped->SameValue(*finallies[i].second));
2887 : }
2888 5 : }
2889 :
2890 26661 : TEST(InterpreterThrow) {
2891 10 : HandleAndZoneScope handles;
2892 : Isolate* isolate = handles.main_isolate();
2893 : Factory* factory = isolate->factory();
2894 :
2895 : std::pair<const char*, Handle<Object>> throws[] = {
2896 : std::make_pair("throw undefined;\n",
2897 : factory->undefined_value()),
2898 : std::make_pair("throw 1;\n",
2899 : handle(Smi::FromInt(1), isolate)),
2900 : std::make_pair("throw 'Error';\n",
2901 10 : factory->NewStringFromStaticChars("Error")),
2902 : std::make_pair("var a = true; if (a) { throw 'Error'; }\n",
2903 10 : factory->NewStringFromStaticChars("Error")),
2904 : std::make_pair("var a = false; if (a) { throw 'Error'; }\n",
2905 : factory->undefined_value()),
2906 : std::make_pair("throw 'Error1'; throw 'Error2'\n",
2907 10 : factory->NewStringFromStaticChars("Error1")),
2908 : };
2909 :
2910 : const char* try_wrapper =
2911 : "(function() { try { f(); } catch(e) { return e; }})()";
2912 :
2913 65 : for (size_t i = 0; i < arraysize(throws); i++) {
2914 30 : std::string source(InterpreterTester::SourceForBody(throws[i].first));
2915 60 : InterpreterTester tester(isolate, source.c_str());
2916 : tester.GetCallable<>();
2917 : Handle<Object> thrown_obj = v8::Utils::OpenHandle(*CompileRun(try_wrapper));
2918 60 : CHECK(thrown_obj->SameValue(*throws[i].second));
2919 : }
2920 5 : }
2921 :
2922 26661 : TEST(InterpreterCountOperators) {
2923 10 : HandleAndZoneScope handles;
2924 : Isolate* isolate = handles.main_isolate();
2925 : Factory* factory = isolate->factory();
2926 :
2927 : std::pair<const char*, Handle<Object>> count_ops[] = {
2928 : std::make_pair("var a = 1; return ++a;",
2929 : handle(Smi::FromInt(2), isolate)),
2930 : std::make_pair("var a = 1; return a++;",
2931 : handle(Smi::FromInt(1), isolate)),
2932 : std::make_pair("var a = 5; return --a;",
2933 : handle(Smi::FromInt(4), isolate)),
2934 : std::make_pair("var a = 5; return a--;",
2935 : handle(Smi::FromInt(5), isolate)),
2936 10 : std::make_pair("var a = 5.2; return --a;", factory->NewHeapNumber(4.2)),
2937 : std::make_pair("var a = 'string'; return ++a;", factory->nan_value()),
2938 : std::make_pair("var a = 'string'; return a--;", factory->nan_value()),
2939 : std::make_pair("var a = true; return ++a;",
2940 : handle(Smi::FromInt(2), isolate)),
2941 : std::make_pair("var a = false; return a--;", handle(Smi::kZero, isolate)),
2942 : std::make_pair("var a = { val: 11 }; return ++a.val;",
2943 : handle(Smi::FromInt(12), isolate)),
2944 : std::make_pair("var a = { val: 11 }; return a.val--;",
2945 : handle(Smi::FromInt(11), isolate)),
2946 : std::make_pair("var a = { val: 11 }; return ++a.val;",
2947 : handle(Smi::FromInt(12), isolate)),
2948 : std::make_pair("var name = 'val'; var a = { val: 22 }; return --a[name];",
2949 : handle(Smi::FromInt(21), isolate)),
2950 : std::make_pair("var name = 'val'; var a = { val: 22 }; return a[name]++;",
2951 : handle(Smi::FromInt(22), isolate)),
2952 : std::make_pair("var a = 1; (function() { a = 2 })(); return ++a;",
2953 : handle(Smi::FromInt(3), isolate)),
2954 : std::make_pair("var a = 1; (function() { a = 2 })(); return a--;",
2955 : handle(Smi::FromInt(2), isolate)),
2956 : std::make_pair("var i = 5; while(i--) {}; return i;",
2957 : handle(Smi::FromInt(-1), isolate)),
2958 : std::make_pair("var i = 1; if(i--) { return 1; } else { return 2; };",
2959 : handle(Smi::FromInt(1), isolate)),
2960 : std::make_pair("var i = -2; do {} while(i++) {}; return i;",
2961 : handle(Smi::FromInt(1), isolate)),
2962 : std::make_pair("var i = -1; for(; i++; ) {}; return i",
2963 : handle(Smi::FromInt(1), isolate)),
2964 : std::make_pair("var i = 20; switch(i++) {\n"
2965 : " case 20: return 1;\n"
2966 : " default: return 2;\n"
2967 : "}",
2968 : handle(Smi::FromInt(1), isolate)),
2969 5 : };
2970 :
2971 215 : for (size_t i = 0; i < arraysize(count_ops); i++) {
2972 105 : std::string source(InterpreterTester::SourceForBody(count_ops[i].first));
2973 210 : InterpreterTester tester(isolate, source.c_str());
2974 : auto callable = tester.GetCallable<>();
2975 :
2976 : Handle<i::Object> return_value = callable().ToHandleChecked();
2977 210 : CHECK(return_value->SameValue(*count_ops[i].second));
2978 : }
2979 5 : }
2980 :
2981 26661 : TEST(InterpreterGlobalCountOperators) {
2982 10 : HandleAndZoneScope handles;
2983 : Isolate* isolate = handles.main_isolate();
2984 :
2985 : std::pair<const char*, Handle<Object>> count_ops[] = {
2986 : std::make_pair("var global = 100;function f(){ return ++global; }",
2987 : handle(Smi::FromInt(101), isolate)),
2988 : std::make_pair("var global = 100; function f(){ return --global; }",
2989 : handle(Smi::FromInt(99), isolate)),
2990 : std::make_pair("var global = 100; function f(){ return global++; }",
2991 : handle(Smi::FromInt(100), isolate)),
2992 : std::make_pair("unallocated = 200; function f(){ return ++unallocated; }",
2993 : handle(Smi::FromInt(201), isolate)),
2994 : std::make_pair("unallocated = 200; function f(){ return --unallocated; }",
2995 : handle(Smi::FromInt(199), isolate)),
2996 : std::make_pair("unallocated = 200; function f(){ return unallocated++; }",
2997 : handle(Smi::FromInt(200), isolate)),
2998 : };
2999 :
3000 65 : for (size_t i = 0; i < arraysize(count_ops); i++) {
3001 60 : InterpreterTester tester(isolate, count_ops[i].first);
3002 : auto callable = tester.GetCallable<>();
3003 :
3004 : Handle<i::Object> return_value = callable().ToHandleChecked();
3005 60 : CHECK(return_value->SameValue(*count_ops[i].second));
3006 : }
3007 5 : }
3008 :
3009 26661 : TEST(InterpreterCompoundExpressions) {
3010 10 : HandleAndZoneScope handles;
3011 : Isolate* isolate = handles.main_isolate();
3012 : Factory* factory = isolate->factory();
3013 :
3014 : std::pair<const char*, Handle<Object>> compound_expr[] = {
3015 : std::make_pair("var a = 1; a += 2; return a;",
3016 : Handle<Object>(Smi::FromInt(3), isolate)),
3017 : std::make_pair("var a = 10; a /= 2; return a;",
3018 : Handle<Object>(Smi::FromInt(5), isolate)),
3019 : std::make_pair("var a = 'test'; a += 'ing'; return a;",
3020 10 : factory->NewStringFromStaticChars("testing")),
3021 : std::make_pair("var a = { val: 2 }; a.val *= 2; return a.val;",
3022 : Handle<Object>(Smi::FromInt(4), isolate)),
3023 : std::make_pair("var a = 1; (function f() { a = 2; })(); a += 24;"
3024 : "return a;",
3025 : Handle<Object>(Smi::FromInt(26), isolate)),
3026 20 : };
3027 :
3028 55 : for (size_t i = 0; i < arraysize(compound_expr); i++) {
3029 : std::string source(
3030 25 : InterpreterTester::SourceForBody(compound_expr[i].first));
3031 50 : InterpreterTester tester(isolate, source.c_str());
3032 : auto callable = tester.GetCallable<>();
3033 :
3034 : Handle<i::Object> return_value = callable().ToHandleChecked();
3035 50 : CHECK(return_value->SameValue(*compound_expr[i].second));
3036 : }
3037 5 : }
3038 :
3039 26661 : TEST(InterpreterGlobalCompoundExpressions) {
3040 10 : HandleAndZoneScope handles;
3041 : Isolate* isolate = handles.main_isolate();
3042 :
3043 : std::pair<const char*, Handle<Object>> compound_expr[2] = {
3044 : std::make_pair("var global = 100;"
3045 : "function f() { global += 20; return global; }",
3046 : Handle<Object>(Smi::FromInt(120), isolate)),
3047 : std::make_pair("unallocated = 100;"
3048 : "function f() { unallocated -= 20; return unallocated; }",
3049 : Handle<Object>(Smi::FromInt(80), isolate)),
3050 10 : };
3051 :
3052 25 : for (size_t i = 0; i < arraysize(compound_expr); i++) {
3053 20 : InterpreterTester tester(isolate, compound_expr[i].first);
3054 : auto callable = tester.GetCallable<>();
3055 :
3056 : Handle<i::Object> return_value = callable().ToHandleChecked();
3057 20 : CHECK(return_value->SameValue(*compound_expr[i].second));
3058 : }
3059 5 : }
3060 :
3061 26661 : TEST(InterpreterCreateArguments) {
3062 10 : HandleAndZoneScope handles;
3063 : Isolate* isolate = handles.main_isolate();
3064 : Factory* factory = isolate->factory();
3065 :
3066 : std::pair<const char*, int> create_args[] = {
3067 : std::make_pair("function f() { return arguments[0]; }", 0),
3068 : std::make_pair("function f(a) { return arguments[0]; }", 0),
3069 : std::make_pair("function f() { return arguments[2]; }", 2),
3070 : std::make_pair("function f(a) { return arguments[2]; }", 2),
3071 : std::make_pair("function f(a, b, c, d) { return arguments[2]; }", 2),
3072 : std::make_pair("function f(a) {"
3073 : "'use strict'; return arguments[0]; }",
3074 : 0),
3075 : std::make_pair("function f(a, b, c, d) {"
3076 : "'use strict'; return arguments[2]; }",
3077 : 2),
3078 : // Check arguments are mapped in sloppy mode and unmapped in strict.
3079 : std::make_pair("function f(a, b, c, d) {"
3080 : " c = b; return arguments[2]; }",
3081 : 1),
3082 : std::make_pair("function f(a, b, c, d) {"
3083 : " 'use strict'; c = b; return arguments[2]; }",
3084 : 2),
3085 : // Check arguments for duplicate parameters in sloppy mode.
3086 : std::make_pair("function f(a, a, b) { return arguments[1]; }", 1),
3087 : // check rest parameters
3088 : std::make_pair("function f(...restArray) { return restArray[0]; }", 0),
3089 : std::make_pair("function f(a, ...restArray) { return restArray[0]; }", 1),
3090 : std::make_pair("function f(a, ...restArray) { return arguments[0]; }", 0),
3091 : std::make_pair("function f(a, ...restArray) { return arguments[1]; }", 1),
3092 : std::make_pair("function f(a, ...restArray) { return restArray[1]; }", 2),
3093 : std::make_pair("function f(a, ...arguments) { return arguments[0]; }", 1),
3094 : std::make_pair("function f(a, b, ...restArray) { return restArray[0]; }",
3095 : 2),
3096 5 : };
3097 :
3098 : // Test passing no arguments.
3099 175 : for (size_t i = 0; i < arraysize(create_args); i++) {
3100 170 : InterpreterTester tester(isolate, create_args[i].first);
3101 : auto callable = tester.GetCallable<>();
3102 : Handle<Object> return_val = callable().ToHandleChecked();
3103 85 : CHECK(return_val.is_identical_to(factory->undefined_value()));
3104 : }
3105 :
3106 : // Test passing one argument.
3107 175 : for (size_t i = 0; i < arraysize(create_args); i++) {
3108 170 : InterpreterTester tester(isolate, create_args[i].first);
3109 : auto callable = tester.GetCallable<Handle<Object>>();
3110 : Handle<Object> return_val =
3111 170 : callable(handle(Smi::FromInt(40), isolate)).ToHandleChecked();
3112 85 : if (create_args[i].second == 0) {
3113 25 : CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(40));
3114 : } else {
3115 60 : CHECK(return_val.is_identical_to(factory->undefined_value()));
3116 : }
3117 : }
3118 :
3119 : // Test passing three argument.
3120 175 : for (size_t i = 0; i < arraysize(create_args); i++) {
3121 : Handle<Object> args[3] = {
3122 : handle(Smi::FromInt(40), isolate),
3123 : handle(Smi::FromInt(60), isolate),
3124 : handle(Smi::FromInt(80), isolate),
3125 : };
3126 :
3127 170 : InterpreterTester tester(isolate, create_args[i].first);
3128 : auto callable =
3129 : tester.GetCallable<Handle<Object>, Handle<Object>, Handle<Object>>();
3130 : Handle<Object> return_val =
3131 : callable(args[0], args[1], args[2]).ToHandleChecked();
3132 170 : CHECK(return_val->SameValue(*args[create_args[i].second]));
3133 : }
3134 5 : }
3135 :
3136 26661 : TEST(InterpreterConditional) {
3137 10 : HandleAndZoneScope handles;
3138 : Isolate* isolate = handles.main_isolate();
3139 :
3140 : std::pair<const char*, Handle<Object>> conditional[] = {
3141 : std::make_pair("return true ? 2 : 3;",
3142 : handle(Smi::FromInt(2), isolate)),
3143 : std::make_pair("return false ? 2 : 3;",
3144 : handle(Smi::FromInt(3), isolate)),
3145 : std::make_pair("var a = 1; return a ? 20 : 30;",
3146 : handle(Smi::FromInt(20), isolate)),
3147 : std::make_pair("var a = 1; return a ? 20 : 30;",
3148 : handle(Smi::FromInt(20), isolate)),
3149 : std::make_pair("var a = 'string'; return a ? 20 : 30;",
3150 : handle(Smi::FromInt(20), isolate)),
3151 : std::make_pair("var a = undefined; return a ? 20 : 30;",
3152 : handle(Smi::FromInt(30), isolate)),
3153 : std::make_pair("return 1 ? 2 ? 3 : 4 : 5;",
3154 : handle(Smi::FromInt(3), isolate)),
3155 : std::make_pair("return 0 ? 2 ? 3 : 4 : 5;",
3156 : handle(Smi::FromInt(5), isolate)),
3157 : };
3158 :
3159 85 : for (size_t i = 0; i < arraysize(conditional); i++) {
3160 40 : std::string source(InterpreterTester::SourceForBody(conditional[i].first));
3161 80 : InterpreterTester tester(isolate, source.c_str());
3162 : auto callable = tester.GetCallable<>();
3163 :
3164 : Handle<i::Object> return_value = callable().ToHandleChecked();
3165 80 : CHECK(return_value->SameValue(*conditional[i].second));
3166 : }
3167 5 : }
3168 :
3169 26661 : TEST(InterpreterDelete) {
3170 10 : HandleAndZoneScope handles;
3171 : Isolate* isolate = handles.main_isolate();
3172 : Factory* factory = isolate->factory();
3173 :
3174 : // Tests for delete for local variables that work both in strict
3175 : // and sloppy modes
3176 : std::pair<const char*, Handle<Object>> test_delete[] = {
3177 : std::make_pair(
3178 : "var a = { x:10, y:'abc', z:30.2}; delete a.x; return a.x;\n",
3179 : factory->undefined_value()),
3180 : std::make_pair(
3181 : "var b = { x:10, y:'abc', z:30.2}; delete b.x; return b.y;\n",
3182 10 : factory->NewStringFromStaticChars("abc")),
3183 : std::make_pair("var c = { x:10, y:'abc', z:30.2}; var d = c; delete d.x; "
3184 : "return c.x;\n",
3185 : factory->undefined_value()),
3186 : std::make_pair("var e = { x:10, y:'abc', z:30.2}; var g = e; delete g.x; "
3187 : "return e.y;\n",
3188 10 : factory->NewStringFromStaticChars("abc")),
3189 : std::make_pair("var a = { x:10, y:'abc', z:30.2};\n"
3190 : "var b = a;"
3191 : "delete b.x;"
3192 : "return b.x;\n",
3193 : factory->undefined_value()),
3194 : std::make_pair("var a = {1:10};\n"
3195 : "(function f1() {return a;});"
3196 : "return delete a[1];",
3197 10 : factory->ToBoolean(true)),
3198 10 : std::make_pair("return delete this;", factory->ToBoolean(true)),
3199 20 : std::make_pair("return delete 'test';", factory->ToBoolean(true))};
3200 :
3201 : // Test delete in sloppy mode
3202 85 : for (size_t i = 0; i < arraysize(test_delete); i++) {
3203 40 : std::string source(InterpreterTester::SourceForBody(test_delete[i].first));
3204 80 : InterpreterTester tester(isolate, source.c_str());
3205 : auto callable = tester.GetCallable<>();
3206 :
3207 : Handle<i::Object> return_value = callable().ToHandleChecked();
3208 80 : CHECK(return_value->SameValue(*test_delete[i].second));
3209 : }
3210 :
3211 : // Test delete in strict mode
3212 85 : for (size_t i = 0; i < arraysize(test_delete); i++) {
3213 : std::string strict_test =
3214 80 : "'use strict'; " + std::string(test_delete[i].first);
3215 40 : std::string source(InterpreterTester::SourceForBody(strict_test.c_str()));
3216 80 : InterpreterTester tester(isolate, source.c_str());
3217 : auto callable = tester.GetCallable<>();
3218 :
3219 : Handle<i::Object> return_value = callable().ToHandleChecked();
3220 80 : CHECK(return_value->SameValue(*test_delete[i].second));
3221 : }
3222 5 : }
3223 :
3224 26661 : TEST(InterpreterDeleteSloppyUnqualifiedIdentifier) {
3225 10 : HandleAndZoneScope handles;
3226 : Isolate* isolate = handles.main_isolate();
3227 : Factory* factory = isolate->factory();
3228 :
3229 : // These tests generate a syntax error for strict mode. We don't
3230 : // test for it here.
3231 : std::pair<const char*, Handle<Object>> test_delete[] = {
3232 : std::make_pair("var sloppy_a = { x:10, y:'abc'};\n"
3233 : "var sloppy_b = delete sloppy_a;\n"
3234 : "if (delete sloppy_a) {\n"
3235 : " return undefined;\n"
3236 : "} else {\n"
3237 : " return sloppy_a.x;\n"
3238 : "}\n",
3239 : Handle<Object>(Smi::FromInt(10), isolate)),
3240 : // TODO(mythria) When try-catch is implemented change the tests to check
3241 : // if delete actually deletes
3242 : std::make_pair("sloppy_a = { x:10, y:'abc'};\n"
3243 : "var sloppy_b = delete sloppy_a;\n"
3244 : // "try{return a.x;} catch(e) {return b;}\n"
3245 : "return sloppy_b;",
3246 10 : factory->ToBoolean(true)),
3247 : std::make_pair("sloppy_a = { x:10, y:'abc'};\n"
3248 : "var sloppy_b = delete sloppy_c;\n"
3249 : "return sloppy_b;",
3250 20 : factory->ToBoolean(true))};
3251 :
3252 35 : for (size_t i = 0; i < arraysize(test_delete); i++) {
3253 15 : std::string source(InterpreterTester::SourceForBody(test_delete[i].first));
3254 30 : InterpreterTester tester(isolate, source.c_str());
3255 : auto callable = tester.GetCallable<>();
3256 :
3257 : Handle<i::Object> return_value = callable().ToHandleChecked();
3258 30 : CHECK(return_value->SameValue(*test_delete[i].second));
3259 : }
3260 5 : }
3261 :
3262 26661 : TEST(InterpreterGlobalDelete) {
3263 10 : HandleAndZoneScope handles;
3264 : Isolate* isolate = handles.main_isolate();
3265 : Factory* factory = isolate->factory();
3266 :
3267 : std::pair<const char*, Handle<Object>> test_global_delete[] = {
3268 : std::make_pair("var a = { x:10, y:'abc', z:30.2 };\n"
3269 : "function f() {\n"
3270 : " delete a.x;\n"
3271 : " return a.x;\n"
3272 : "}\n"
3273 : "f();\n",
3274 : factory->undefined_value()),
3275 : std::make_pair("var b = {1:10, 2:'abc', 3:30.2 };\n"
3276 : "function f() {\n"
3277 : " delete b[2];\n"
3278 : " return b[1];\n"
3279 : " }\n"
3280 : "f();\n",
3281 : Handle<Object>(Smi::FromInt(10), isolate)),
3282 : std::make_pair("var c = { x:10, y:'abc', z:30.2 };\n"
3283 : "function f() {\n"
3284 : " var d = c;\n"
3285 : " delete d.y;\n"
3286 : " return d.x;\n"
3287 : "}\n"
3288 : "f();\n",
3289 : Handle<Object>(Smi::FromInt(10), isolate)),
3290 : std::make_pair("e = { x:10, y:'abc' };\n"
3291 : "function f() {\n"
3292 : " return delete e;\n"
3293 : "}\n"
3294 : "f();\n",
3295 10 : factory->ToBoolean(true)),
3296 : std::make_pair("var g = { x:10, y:'abc' };\n"
3297 : "function f() {\n"
3298 : " return delete g;\n"
3299 : "}\n"
3300 : "f();\n",
3301 10 : factory->ToBoolean(false)),
3302 : std::make_pair("function f() {\n"
3303 : " var obj = {h:10, f1() {return delete this;}};\n"
3304 : " return obj.f1();\n"
3305 : "}\n"
3306 : "f();",
3307 10 : factory->ToBoolean(true)),
3308 : std::make_pair("function f() {\n"
3309 : " var obj = {h:10,\n"
3310 : " f1() {\n"
3311 : " 'use strict';\n"
3312 : " return delete this.h;}};\n"
3313 : " return obj.f1();\n"
3314 : "}\n"
3315 : "f();",
3316 35 : factory->ToBoolean(true))};
3317 :
3318 75 : for (size_t i = 0; i < arraysize(test_global_delete); i++) {
3319 70 : InterpreterTester tester(isolate, test_global_delete[i].first);
3320 : auto callable = tester.GetCallable<>();
3321 :
3322 : Handle<i::Object> return_value = callable().ToHandleChecked();
3323 70 : CHECK(return_value->SameValue(*test_global_delete[i].second));
3324 : }
3325 5 : }
3326 :
3327 26661 : TEST(InterpreterBasicLoops) {
3328 10 : HandleAndZoneScope handles;
3329 : Isolate* isolate = handles.main_isolate();
3330 : Factory* factory = isolate->factory();
3331 :
3332 : std::pair<const char*, Handle<Object>> loops[] = {
3333 : std::make_pair("var a = 10; var b = 1;\n"
3334 : "while (a) {\n"
3335 : " b = b * 2;\n"
3336 : " a = a - 1;\n"
3337 : "};\n"
3338 : "return b;\n",
3339 10 : factory->NewHeapNumber(1024)),
3340 : std::make_pair("var a = 1; var b = 1;\n"
3341 : "do {\n"
3342 : " b = b * 2;\n"
3343 : " --a;\n"
3344 : "} while(a);\n"
3345 : "return b;\n",
3346 : handle(Smi::FromInt(2), isolate)),
3347 : std::make_pair("var b = 1;\n"
3348 : "for ( var a = 10; a; a--) {\n"
3349 : " b *= 2;\n"
3350 : "}\n"
3351 : "return b;",
3352 10 : factory->NewHeapNumber(1024)),
3353 : std::make_pair("var a = 10; var b = 1;\n"
3354 : "while (a > 0) {\n"
3355 : " b = b * 2;\n"
3356 : " a = a - 1;\n"
3357 : "};\n"
3358 : "return b;\n",
3359 10 : factory->NewHeapNumber(1024)),
3360 : std::make_pair("var a = 1; var b = 1;\n"
3361 : "do {\n"
3362 : " b = b * 2;\n"
3363 : " --a;\n"
3364 : "} while(a);\n"
3365 : "return b;\n",
3366 : handle(Smi::FromInt(2), isolate)),
3367 : std::make_pair("var b = 1;\n"
3368 : "for ( var a = 10; a > 0; a--) {\n"
3369 : " b *= 2;\n"
3370 : "}\n"
3371 : "return b;",
3372 10 : factory->NewHeapNumber(1024)),
3373 : std::make_pair("var a = 10; var b = 1;\n"
3374 : "while (false) {\n"
3375 : " b = b * 2;\n"
3376 : " a = a - 1;\n"
3377 : "}\n"
3378 : "return b;\n",
3379 : Handle<Object>(Smi::FromInt(1), isolate)),
3380 : std::make_pair("var a = 10; var b = 1;\n"
3381 : "while (true) {\n"
3382 : " b = b * 2;\n"
3383 : " a = a - 1;\n"
3384 : " if (a == 0) break;"
3385 : " continue;"
3386 : "}\n"
3387 : "return b;\n",
3388 10 : factory->NewHeapNumber(1024)),
3389 : std::make_pair("var a = 10; var b = 1;\n"
3390 : "do {\n"
3391 : " b = b * 2;\n"
3392 : " a = a - 1;\n"
3393 : " if (a == 0) break;"
3394 : "} while(true);\n"
3395 : "return b;\n",
3396 10 : factory->NewHeapNumber(1024)),
3397 : std::make_pair("var a = 10; var b = 1;\n"
3398 : "do {\n"
3399 : " b = b * 2;\n"
3400 : " a = a - 1;\n"
3401 : " if (a == 0) break;"
3402 : "} while(false);\n"
3403 : "return b;\n",
3404 : Handle<Object>(Smi::FromInt(2), isolate)),
3405 : std::make_pair("var a = 10; var b = 1;\n"
3406 : "for ( a = 1, b = 30; false; ) {\n"
3407 : " b = b * 2;\n"
3408 : "}\n"
3409 : "return b;\n",
3410 15 : Handle<Object>(Smi::FromInt(30), isolate))};
3411 :
3412 115 : for (size_t i = 0; i < arraysize(loops); i++) {
3413 55 : std::string source(InterpreterTester::SourceForBody(loops[i].first));
3414 110 : InterpreterTester tester(isolate, source.c_str());
3415 : auto callable = tester.GetCallable<>();
3416 :
3417 : Handle<i::Object> return_value = callable().ToHandleChecked();
3418 110 : CHECK(return_value->SameValue(*loops[i].second));
3419 : }
3420 5 : }
3421 :
3422 26661 : TEST(InterpreterForIn) {
3423 : std::pair<const char*, int> for_in_samples[] = {
3424 : {"var r = -1;\n"
3425 : "for (var a in null) { r = a; }\n"
3426 : "return r;\n",
3427 : -1},
3428 : {"var r = -1;\n"
3429 : "for (var a in undefined) { r = a; }\n"
3430 : "return r;\n",
3431 : -1},
3432 : {"var r = 0;\n"
3433 : "for (var a in [0,6,7,9]) { r = r + (1 << a); }\n"
3434 : "return r;\n",
3435 : 0xF},
3436 : {"var r = 0;\n"
3437 : "for (var a in [0,6,7,9]) { r = r + (1 << a); }\n"
3438 : "var r = 0;\n"
3439 : "for (var a in [0,6,7,9]) { r = r + (1 << a); }\n"
3440 : "return r;\n",
3441 : 0xF},
3442 : {"var r = 0;\n"
3443 : "for (var a in 'foobar') { r = r + (1 << a); }\n"
3444 : "return r;\n",
3445 : 0x3F},
3446 : {"var r = 0;\n"
3447 : "for (var a in {1:0, 10:1, 100:2, 1000:3}) {\n"
3448 : " r = r + Number(a);\n"
3449 : " }\n"
3450 : " return r;\n",
3451 : 1111},
3452 : {"var r = 0;\n"
3453 : "var data = {1:0, 10:1, 100:2, 1000:3};\n"
3454 : "for (var a in data) {\n"
3455 : " if (a == 1) delete data[1];\n"
3456 : " r = r + Number(a);\n"
3457 : " }\n"
3458 : " return r;\n",
3459 : 1111},
3460 : {"var r = 0;\n"
3461 : "var data = {1:0, 10:1, 100:2, 1000:3};\n"
3462 : "for (var a in data) {\n"
3463 : " if (a == 10) delete data[100];\n"
3464 : " r = r + Number(a);\n"
3465 : " }\n"
3466 : " return r;\n",
3467 : 1011},
3468 : {"var r = 0;\n"
3469 : "var data = {1:0, 10:1, 100:2, 1000:3};\n"
3470 : "for (var a in data) {\n"
3471 : " if (a == 10) data[10000] = 4;\n"
3472 : " r = r + Number(a);\n"
3473 : " }\n"
3474 : " return r;\n",
3475 : 1111},
3476 : {"var r = 0;\n"
3477 : "var input = 'foobar';\n"
3478 : "for (var a in input) {\n"
3479 : " if (input[a] == 'b') break;\n"
3480 : " r = r + (1 << a);\n"
3481 : "}\n"
3482 : "return r;\n",
3483 : 0x7},
3484 : {"var r = 0;\n"
3485 : "var input = 'foobar';\n"
3486 : "for (var a in input) {\n"
3487 : " if (input[a] == 'b') continue;\n"
3488 : " r = r + (1 << a);\n"
3489 : "}\n"
3490 : "return r;\n",
3491 : 0x37},
3492 : {"var r = 0;\n"
3493 : "var data = {1:0, 10:1, 100:2, 1000:3};\n"
3494 : "for (var a in data) {\n"
3495 : " if (a == 10) {\n"
3496 : " data[10000] = 4;\n"
3497 : " }\n"
3498 : " r = r + Number(a);\n"
3499 : "}\n"
3500 : "return r;\n",
3501 : 1111},
3502 : {"var r = [ 3 ];\n"
3503 : "var data = {1:0, 10:1, 100:2, 1000:3};\n"
3504 : "for (r[10] in data) {\n"
3505 : "}\n"
3506 : "return Number(r[10]);\n",
3507 : 1000},
3508 : {"var r = [ 3 ];\n"
3509 : "var data = {1:0, 10:1, 100:2, 1000:3};\n"
3510 : "for (r['100'] in data) {\n"
3511 : "}\n"
3512 : "return Number(r['100']);\n",
3513 : 1000},
3514 : {"var obj = {}\n"
3515 : "var descObj = new Boolean(false);\n"
3516 : "var accessed = 0;\n"
3517 : "descObj.enumerable = true;\n"
3518 : "Object.defineProperties(obj, { prop:descObj });\n"
3519 : "for (var p in obj) {\n"
3520 : " if (p === 'prop') { accessed = 1; }\n"
3521 : "}\n"
3522 : "return accessed;",
3523 : 1},
3524 : {"var appointment = {};\n"
3525 : "Object.defineProperty(appointment, 'startTime', {\n"
3526 : " value: 1001,\n"
3527 : " writable: false,\n"
3528 : " enumerable: false,\n"
3529 : " configurable: true\n"
3530 : "});\n"
3531 : "Object.defineProperty(appointment, 'name', {\n"
3532 : " value: 'NAME',\n"
3533 : " writable: false,\n"
3534 : " enumerable: false,\n"
3535 : " configurable: true\n"
3536 : "});\n"
3537 : "var meeting = Object.create(appointment);\n"
3538 : "Object.defineProperty(meeting, 'conferenceCall', {\n"
3539 : " value: 'In-person meeting',\n"
3540 : " writable: false,\n"
3541 : " enumerable: false,\n"
3542 : " configurable: true\n"
3543 : "});\n"
3544 : "\n"
3545 : "var teamMeeting = Object.create(meeting);\n"
3546 : "\n"
3547 : "var flags = 0;\n"
3548 : "for (var p in teamMeeting) {\n"
3549 : " if (p === 'startTime') {\n"
3550 : " flags |= 1;\n"
3551 : " }\n"
3552 : " if (p === 'name') {\n"
3553 : " flags |= 2;\n"
3554 : " }\n"
3555 : " if (p === 'conferenceCall') {\n"
3556 : " flags |= 4;\n"
3557 : " }\n"
3558 : "}\n"
3559 : "\n"
3560 : "var hasOwnProperty = !teamMeeting.hasOwnProperty('name') &&\n"
3561 : " !teamMeeting.hasOwnProperty('startTime') &&\n"
3562 : " !teamMeeting.hasOwnProperty('conferenceCall');\n"
3563 : "if (!hasOwnProperty) {\n"
3564 : " flags |= 8;\n"
3565 : "}\n"
3566 : "return flags;\n",
3567 : 0},
3568 : {"var data = {x:23, y:34};\n"
3569 : " var result = 0;\n"
3570 : "var o = {};\n"
3571 : "var arr = [o];\n"
3572 : "for (arr[0].p in data)\n" // This is to test if value is loaded
3573 : " result += data[arr[0].p];\n" // back from accumulator before storing
3574 : "return result;\n", // named properties.
3575 : 57},
3576 : {"var data = {x:23, y:34};\n"
3577 : "var result = 0;\n"
3578 : "var o = {};\n"
3579 : "var i = 0;\n"
3580 : "for (o[i++] in data)\n" // This is to test if value is loaded
3581 : " result += data[o[i-1]];\n" // back from accumulator before
3582 : "return result;\n", // storing keyed properties.
3583 5 : 57}};
3584 :
3585 : // Two passes are made for this test. On the first, 8-bit register
3586 : // operands are employed, and on the 16-bit register operands are
3587 : // used.
3588 25 : for (int pass = 0; pass < 2; pass++) {
3589 20 : HandleAndZoneScope handles;
3590 : Isolate* isolate = handles.main_isolate();
3591 20 : std::ostringstream wide_os;
3592 10 : if (pass == 1) {
3593 2005 : for (int i = 0; i < 200; i++) {
3594 1000 : wide_os << "var local" << i << " = 0;\n";
3595 : }
3596 : }
3597 :
3598 370 : for (size_t i = 0; i < arraysize(for_in_samples); i++) {
3599 360 : std::ostringstream body_os;
3600 540 : body_os << wide_os.str() << for_in_samples[i].first;
3601 : std::string body(body_os.str());
3602 180 : std::string function = InterpreterTester::SourceForBody(body.c_str());
3603 360 : InterpreterTester tester(isolate, function.c_str());
3604 : auto callable = tester.GetCallable<>();
3605 : Handle<Object> return_val = callable().ToHandleChecked();
3606 360 : CHECK_EQ(Handle<Smi>::cast(return_val)->value(),
3607 : for_in_samples[i].second);
3608 : }
3609 : }
3610 5 : }
3611 :
3612 26661 : TEST(InterpreterForOf) {
3613 10 : HandleAndZoneScope handles;
3614 : Isolate* isolate = handles.main_isolate();
3615 : Factory* factory = isolate->factory();
3616 :
3617 : std::pair<const char*, Handle<Object>> for_of[] = {
3618 : {"function f() {\n"
3619 : " var r = 0;\n"
3620 : " for (var a of [0,6,7,9]) { r += a; }\n"
3621 : " return r;\n"
3622 : "}",
3623 : handle(Smi::FromInt(22), isolate)},
3624 : {"function f() {\n"
3625 : " var r = '';\n"
3626 : " for (var a of 'foobar') { r = a + r; }\n"
3627 : " return r;\n"
3628 : "}",
3629 10 : factory->NewStringFromStaticChars("raboof")},
3630 : {"function f() {\n"
3631 : " var a = [1, 2, 3];\n"
3632 : " a.name = 4;\n"
3633 : " var r = 0;\n"
3634 : " for (var x of a) { r += x; }\n"
3635 : " return r;\n"
3636 : "}",
3637 : handle(Smi::FromInt(6), isolate)},
3638 : {"function f() {\n"
3639 : " var r = '';\n"
3640 : " var data = [1, 2, 3]; \n"
3641 : " for (a of data) { delete data[0]; r += a; } return r; }",
3642 10 : factory->NewStringFromStaticChars("123")},
3643 : {"function f() {\n"
3644 : " var r = '';\n"
3645 : " var data = [1, 2, 3]; \n"
3646 : " for (a of data) { delete data[2]; r += a; } return r; }",
3647 10 : factory->NewStringFromStaticChars("12undefined")},
3648 : {"function f() {\n"
3649 : " var r = '';\n"
3650 : " var data = [1, 2, 3]; \n"
3651 : " for (a of data) { delete data; r += a; } return r; }",
3652 10 : factory->NewStringFromStaticChars("123")},
3653 : {"function f() {\n"
3654 : " var r = '';\n"
3655 : " var input = 'foobar';\n"
3656 : " for (var a of input) {\n"
3657 : " if (a == 'b') break;\n"
3658 : " r += a;\n"
3659 : " }\n"
3660 : " return r;\n"
3661 : "}",
3662 10 : factory->NewStringFromStaticChars("foo")},
3663 : {"function f() {\n"
3664 : " var r = '';\n"
3665 : " var input = 'foobar';\n"
3666 : " for (var a of input) {\n"
3667 : " if (a == 'b') continue;\n"
3668 : " r += a;\n"
3669 : " }\n"
3670 : " return r;\n"
3671 : "}",
3672 10 : factory->NewStringFromStaticChars("fooar")},
3673 : {"function f() {\n"
3674 : " var r = '';\n"
3675 : " var data = [1, 2, 3, 4]; \n"
3676 : " for (a of data) { data[2] = 567; r += a; }\n"
3677 : " return r;\n"
3678 : "}",
3679 10 : factory->NewStringFromStaticChars("125674")},
3680 : {"function f() {\n"
3681 : " var r = '';\n"
3682 : " var data = [1, 2, 3, 4]; \n"
3683 : " for (a of data) { data[4] = 567; r += a; }\n"
3684 : " return r;\n"
3685 : "}",
3686 10 : factory->NewStringFromStaticChars("1234567")},
3687 : {"function f() {\n"
3688 : " var r = '';\n"
3689 : " var data = [1, 2, 3, 4]; \n"
3690 : " for (a of data) { data[5] = 567; r += a; }\n"
3691 : " return r;\n"
3692 : "}",
3693 10 : factory->NewStringFromStaticChars("1234undefined567")},
3694 : {"function f() {\n"
3695 : " var r = '';\n"
3696 : " var obj = new Object();\n"
3697 : " obj[Symbol.iterator] = function() { return {\n"
3698 : " index: 3,\n"
3699 : " data: ['a', 'b', 'c', 'd'],"
3700 : " next: function() {"
3701 : " return {"
3702 : " done: this.index == -1,\n"
3703 : " value: this.index < 0 ? undefined : this.data[this.index--]\n"
3704 : " }\n"
3705 : " }\n"
3706 : " }}\n"
3707 : " for (a of obj) { r += a }\n"
3708 : " return r;\n"
3709 : "}",
3710 10 : factory->NewStringFromStaticChars("dcba")},
3711 : };
3712 :
3713 125 : for (size_t i = 0; i < arraysize(for_of); i++) {
3714 120 : InterpreterTester tester(isolate, for_of[i].first);
3715 : auto callable = tester.GetCallable<>();
3716 : Handle<Object> return_val = callable().ToHandleChecked();
3717 120 : CHECK(return_val->SameValue(*for_of[i].second));
3718 : }
3719 5 : }
3720 :
3721 26661 : TEST(InterpreterSwitch) {
3722 10 : HandleAndZoneScope handles;
3723 : Isolate* isolate = handles.main_isolate();
3724 : Factory* factory = isolate->factory();
3725 :
3726 : std::pair<const char*, Handle<Object>> switch_ops[] = {
3727 : std::make_pair("var a = 1;\n"
3728 : "switch(a) {\n"
3729 : " case 1: return 2;\n"
3730 : " case 2: return 3;\n"
3731 : "}\n",
3732 : handle(Smi::FromInt(2), isolate)),
3733 : std::make_pair("var a = 1;\n"
3734 : "switch(a) {\n"
3735 : " case 2: a = 2; break;\n"
3736 : " case 1: a = 3; break;\n"
3737 : "}\n"
3738 : "return a;",
3739 : handle(Smi::FromInt(3), isolate)),
3740 : std::make_pair("var a = 1;\n"
3741 : "switch(a) {\n"
3742 : " case 1: a = 2; // fall-through\n"
3743 : " case 2: a = 3; break;\n"
3744 : "}\n"
3745 : "return a;",
3746 : handle(Smi::FromInt(3), isolate)),
3747 : std::make_pair("var a = 100;\n"
3748 : "switch(a) {\n"
3749 : " case 1: return 100;\n"
3750 : " case 2: return 200;\n"
3751 : "}\n"
3752 : "return undefined;",
3753 : factory->undefined_value()),
3754 : std::make_pair("var a = 100;\n"
3755 : "switch(a) {\n"
3756 : " case 1: return 100;\n"
3757 : " case 2: return 200;\n"
3758 : " default: return 300;\n"
3759 : "}\n"
3760 : "return undefined;",
3761 : handle(Smi::FromInt(300), isolate)),
3762 : std::make_pair("var a = 100;\n"
3763 : "switch(typeof(a)) {\n"
3764 : " case 'string': return 1;\n"
3765 : " case 'number': return 2;\n"
3766 : " default: return 3;\n"
3767 : "}\n",
3768 : handle(Smi::FromInt(2), isolate)),
3769 : std::make_pair("var a = 100;\n"
3770 : "switch(a) {\n"
3771 : " case a += 20: return 1;\n"
3772 : " case a -= 10: return 2;\n"
3773 : " case a -= 10: return 3;\n"
3774 : " default: return 3;\n"
3775 : "}\n",
3776 : handle(Smi::FromInt(3), isolate)),
3777 : std::make_pair("var a = 1;\n"
3778 : "switch(a) {\n"
3779 : " case 1: \n"
3780 : " switch(a + 1) {\n"
3781 : " case 2 : a += 1; break;\n"
3782 : " default : a += 2; break;\n"
3783 : " } // fall-through\n"
3784 : " case 2: a += 3;\n"
3785 : "}\n"
3786 : "return a;",
3787 : handle(Smi::FromInt(5), isolate)),
3788 : };
3789 :
3790 85 : for (size_t i = 0; i < arraysize(switch_ops); i++) {
3791 40 : std::string source(InterpreterTester::SourceForBody(switch_ops[i].first));
3792 80 : InterpreterTester tester(isolate, source.c_str());
3793 : auto callable = tester.GetCallable<>();
3794 :
3795 : Handle<i::Object> return_value = callable().ToHandleChecked();
3796 80 : CHECK(return_value->SameValue(*switch_ops[i].second));
3797 : }
3798 5 : }
3799 :
3800 26661 : TEST(InterpreterSloppyThis) {
3801 10 : HandleAndZoneScope handles;
3802 : Isolate* isolate = handles.main_isolate();
3803 : Factory* factory = isolate->factory();
3804 :
3805 : std::pair<const char*, Handle<Object>> sloppy_this[] = {
3806 : std::make_pair("var global_val = 100;\n"
3807 : "function f() { return this.global_val; }\n",
3808 : handle(Smi::FromInt(100), isolate)),
3809 : std::make_pair("var global_val = 110;\n"
3810 : "function g() { return this.global_val; };"
3811 : "function f() { return g(); }\n",
3812 : handle(Smi::FromInt(110), isolate)),
3813 : std::make_pair("var global_val = 110;\n"
3814 : "function g() { return this.global_val };"
3815 : "function f() { 'use strict'; return g(); }\n",
3816 : handle(Smi::FromInt(110), isolate)),
3817 : std::make_pair("function f() { 'use strict'; return this; }\n",
3818 : factory->undefined_value()),
3819 : std::make_pair("function g() { 'use strict'; return this; };"
3820 : "function f() { return g(); }\n",
3821 : factory->undefined_value()),
3822 : };
3823 :
3824 55 : for (size_t i = 0; i < arraysize(sloppy_this); i++) {
3825 50 : InterpreterTester tester(isolate, sloppy_this[i].first);
3826 : auto callable = tester.GetCallable<>();
3827 :
3828 : Handle<i::Object> return_value = callable().ToHandleChecked();
3829 50 : CHECK(return_value->SameValue(*sloppy_this[i].second));
3830 : }
3831 5 : }
3832 :
3833 26661 : TEST(InterpreterThisFunction) {
3834 10 : HandleAndZoneScope handles;
3835 : Isolate* isolate = handles.main_isolate();
3836 : Factory* factory = isolate->factory();
3837 :
3838 : InterpreterTester tester(isolate,
3839 10 : "var f;\n f = function f() { return f.name; }");
3840 : auto callable = tester.GetCallable<>();
3841 :
3842 : Handle<i::Object> return_value = callable().ToHandleChecked();
3843 15 : CHECK(return_value->SameValue(*factory->NewStringFromStaticChars("f")));
3844 5 : }
3845 :
3846 26661 : TEST(InterpreterNewTarget) {
3847 10 : HandleAndZoneScope handles;
3848 : Isolate* isolate = handles.main_isolate();
3849 : Factory* factory = isolate->factory();
3850 :
3851 : // TODO(rmcilroy): Add tests that we get the original constructor for
3852 : // superclass constructors once we have class support.
3853 10 : InterpreterTester tester(isolate, "function f() { this.a = new.target; }");
3854 : auto callable = tester.GetCallable<>();
3855 : callable().ToHandleChecked();
3856 :
3857 : Handle<Object> new_target_name = v8::Utils::OpenHandle(
3858 : *CompileRun("(function() { return (new f()).a.name; })();"));
3859 15 : CHECK(new_target_name->SameValue(*factory->NewStringFromStaticChars("f")));
3860 5 : }
3861 :
3862 26661 : TEST(InterpreterAssignmentInExpressions) {
3863 10 : HandleAndZoneScope handles;
3864 : Isolate* isolate = handles.main_isolate();
3865 :
3866 : std::pair<const char*, int> samples[] = {
3867 : {"function f() {\n"
3868 : " var x = 7;\n"
3869 : " var y = x + (x = 1) + (x = 2);\n"
3870 : " return y;\n"
3871 : "}",
3872 : 10},
3873 : {"function f() {\n"
3874 : " var x = 7;\n"
3875 : " var y = x + (x = 1) + (x = 2);\n"
3876 : " return x;\n"
3877 : "}",
3878 : 2},
3879 : {"function f() {\n"
3880 : " var x = 55;\n"
3881 : " x = x + (x = 100) + (x = 101);\n"
3882 : " return x;\n"
3883 : "}",
3884 : 256},
3885 : {"function f() {\n"
3886 : " var x = 7;\n"
3887 : " return ++x + x + x++;\n"
3888 : "}",
3889 : 24},
3890 : {"function f() {\n"
3891 : " var x = 7;\n"
3892 : " var y = 1 + ++x + x + x++;\n"
3893 : " return x;\n"
3894 : "}",
3895 : 9},
3896 : {"function f() {\n"
3897 : " var x = 7;\n"
3898 : " var y = ++x + x + x++;\n"
3899 : " return x;\n"
3900 : "}",
3901 : 9},
3902 : {"function f() {\n"
3903 : " var x = 7, y = 100, z = 1000;\n"
3904 : " return x + (x += 3) + y + (y *= 10) + (z *= 7) + z;\n"
3905 : "}",
3906 : 15117},
3907 : {"function f() {\n"
3908 : " var inner = function (x) { return x + (x = 2) + (x = 4) + x; };\n"
3909 : " return inner(1);\n"
3910 : "}",
3911 : 11},
3912 : {"function f() {\n"
3913 : " var x = 1, y = 2;\n"
3914 : " x = x + (x = 3) + y + (y = 4), y = y + (y = 5) + y + x;\n"
3915 : " return x + y;\n"
3916 : "}",
3917 : 10 + 24},
3918 : {"function f() {\n"
3919 : " var x = 0;\n"
3920 : " var y = x | (x = 1) | (x = 2);\n"
3921 : " return x;\n"
3922 : "}",
3923 : 2},
3924 : {"function f() {\n"
3925 : " var x = 0;\n"
3926 : " var y = x || (x = 1);\n"
3927 : " return x;\n"
3928 : "}",
3929 : 1},
3930 : {"function f() {\n"
3931 : " var x = 1;\n"
3932 : " var y = x && (x = 2) && (x = 3);\n"
3933 : " return x;\n"
3934 : "}",
3935 : 3},
3936 : {"function f() {\n"
3937 : " var x = 1;\n"
3938 : " var y = x || (x = 2);\n"
3939 : " return x;\n"
3940 : "}",
3941 : 1},
3942 : {"function f() {\n"
3943 : " var x = 1;\n"
3944 : " x = (x << (x = 3)) | (x = 16);\n"
3945 : " return x;\n"
3946 : "}",
3947 : 24},
3948 : {"function f() {\n"
3949 : " var r = 7;\n"
3950 : " var s = 11;\n"
3951 : " var t = 13;\n"
3952 : " var u = r + s + t + (r = 10) + (s = 20) +"
3953 : " (t = (r + s)) + r + s + t;\n"
3954 : " return r + s + t + u;\n"
3955 : "}",
3956 : 211},
3957 : {"function f() {\n"
3958 : " var r = 7;\n"
3959 : " var s = 11;\n"
3960 : " var t = 13;\n"
3961 : " return r > (3 * s * (s = 1)) ? (t + (t += 1)) : (r + (r = 4));\n"
3962 : "}",
3963 : 11},
3964 : {"function f() {\n"
3965 : " var r = 7;\n"
3966 : " var s = 11;\n"
3967 : " var t = 13;\n"
3968 : " return r > (3 * s * (s = 0)) ? (t + (t += 1)) : (r + (r = 4));\n"
3969 : "}",
3970 : 27},
3971 : {"function f() {\n"
3972 : " var r = 7;\n"
3973 : " var s = 11;\n"
3974 : " var t = 13;\n"
3975 : " return (r + (r = 5)) > s ? r : t;\n"
3976 : "}",
3977 : 5},
3978 : {"function f(a) {\n"
3979 : " return a + (arguments[0] = 10);\n"
3980 : "}",
3981 : 50},
3982 : {"function f(a) {\n"
3983 : " return a + (arguments[0] = 10) + a;\n"
3984 : "}",
3985 : 60},
3986 : {"function f(a) {\n"
3987 : " return a + (arguments[0] = 10) + arguments[0];\n"
3988 : "}",
3989 : 60},
3990 5 : };
3991 :
3992 : const int arg_value = 40;
3993 215 : for (size_t i = 0; i < arraysize(samples); i++) {
3994 210 : InterpreterTester tester(isolate, samples[i].first);
3995 : auto callable = tester.GetCallable<Handle<Object>>();
3996 : Handle<Object> return_val =
3997 210 : callable(handle(Smi::FromInt(arg_value), handles.main_isolate()))
3998 : .ToHandleChecked();
3999 210 : CHECK_EQ(Handle<Smi>::cast(return_val)->value(), samples[i].second);
4000 : }
4001 5 : }
4002 :
4003 26661 : TEST(InterpreterToName) {
4004 10 : HandleAndZoneScope handles;
4005 : Isolate* isolate = handles.main_isolate();
4006 : Factory* factory = isolate->factory();
4007 :
4008 : std::pair<const char*, Handle<Object>> to_name_tests[] = {
4009 : {"var a = 'val'; var obj = {[a] : 10}; return obj.val;",
4010 10 : factory->NewNumberFromInt(10)},
4011 : {"var a = 20; var obj = {[a] : 10}; return obj['20'];",
4012 10 : factory->NewNumberFromInt(10)},
4013 : {"var a = 20; var obj = {[a] : 10}; return obj[20];",
4014 10 : factory->NewNumberFromInt(10)},
4015 : {"var a = {val:23}; var obj = {[a] : 10}; return obj[a];",
4016 10 : factory->NewNumberFromInt(10)},
4017 : {"var a = {val:23}; var obj = {[a] : 10};\n"
4018 : "return obj['[object Object]'];",
4019 10 : factory->NewNumberFromInt(10)},
4020 : {"var a = {toString : function() { return 'x'}};\n"
4021 : "var obj = {[a] : 10};\n"
4022 : "return obj.x;",
4023 10 : factory->NewNumberFromInt(10)},
4024 : {"var a = {valueOf : function() { return 'x'}};\n"
4025 : "var obj = {[a] : 10};\n"
4026 : "return obj.x;",
4027 : factory->undefined_value()},
4028 : {"var a = {[Symbol.toPrimitive] : function() { return 'x'}};\n"
4029 : "var obj = {[a] : 10};\n"
4030 : "return obj.x;",
4031 10 : factory->NewNumberFromInt(10)},
4032 : };
4033 :
4034 85 : for (size_t i = 0; i < arraysize(to_name_tests); i++) {
4035 : std::string source(
4036 40 : InterpreterTester::SourceForBody(to_name_tests[i].first));
4037 80 : InterpreterTester tester(isolate, source.c_str());
4038 : auto callable = tester.GetCallable<>();
4039 :
4040 : Handle<i::Object> return_value = callable().ToHandleChecked();
4041 80 : CHECK(return_value->SameValue(*to_name_tests[i].second));
4042 : }
4043 5 : }
4044 :
4045 26661 : TEST(TemporaryRegisterAllocation) {
4046 10 : HandleAndZoneScope handles;
4047 : Isolate* isolate = handles.main_isolate();
4048 : Factory* factory = isolate->factory();
4049 :
4050 : std::pair<const char*, Handle<Object>> reg_tests[] = {
4051 : {"function add(a, b, c) {"
4052 : " return a + b + c;"
4053 : "}"
4054 : "function f() {"
4055 : " var a = 10, b = 10;"
4056 : " return add(a, b++, b);"
4057 : "}",
4058 10 : factory->NewNumberFromInt(31)},
4059 : {"function add(a, b, c, d) {"
4060 : " return a + b + c + d;"
4061 : "}"
4062 : "function f() {"
4063 : " var x = 10, y = 20, z = 30;"
4064 : " return x + add(x, (y= x++), x, z);"
4065 : "}",
4066 10 : factory->NewNumberFromInt(71)},
4067 : };
4068 :
4069 25 : for (size_t i = 0; i < arraysize(reg_tests); i++) {
4070 20 : InterpreterTester tester(isolate, reg_tests[i].first);
4071 : auto callable = tester.GetCallable<>();
4072 :
4073 : Handle<i::Object> return_value = callable().ToHandleChecked();
4074 20 : CHECK(return_value->SameValue(*reg_tests[i].second));
4075 : }
4076 5 : }
4077 :
4078 26661 : TEST(InterpreterLookupSlot) {
4079 10 : HandleAndZoneScope handles;
4080 : Isolate* isolate = handles.main_isolate();
4081 : Factory* factory = isolate->factory();
4082 :
4083 : // TODO(mythria): Add more tests when we have support for eval/with.
4084 : const char* function_prologue = "var f;"
4085 : "var x = 1;"
4086 : "function f1() {"
4087 : " eval(\"function t() {";
4088 : const char* function_epilogue = " }; f = t;\");"
4089 : "}"
4090 : "f1();";
4091 :
4092 :
4093 : std::pair<const char*, Handle<Object>> lookup_slot[] = {
4094 : {"return x;", handle(Smi::FromInt(1), isolate)},
4095 10 : {"return typeof x;", factory->NewStringFromStaticChars("number")},
4096 10 : {"return typeof dummy;", factory->NewStringFromStaticChars("undefined")},
4097 : {"x = 10; return x;", handle(Smi::FromInt(10), isolate)},
4098 : {"'use strict'; x = 20; return x;", handle(Smi::FromInt(20), isolate)},
4099 : };
4100 :
4101 55 : for (size_t i = 0; i < arraysize(lookup_slot); i++) {
4102 100 : std::string script = std::string(function_prologue) +
4103 : std::string(lookup_slot[i].first) +
4104 75 : std::string(function_epilogue);
4105 :
4106 50 : InterpreterTester tester(isolate, script.c_str(), "t");
4107 : auto callable = tester.GetCallable<>();
4108 :
4109 : Handle<i::Object> return_value = callable().ToHandleChecked();
4110 50 : CHECK(return_value->SameValue(*lookup_slot[i].second));
4111 : }
4112 5 : }
4113 :
4114 26661 : TEST(InterpreterLookupContextSlot) {
4115 10 : HandleAndZoneScope handles;
4116 : Isolate* isolate = handles.main_isolate();
4117 :
4118 : const char* inner_function_prologue = "function inner() {";
4119 : const char* inner_function_epilogue = "};";
4120 : const char* outer_function_epilogue = "return inner();";
4121 :
4122 : std::tuple<const char*, const char*, Handle<Object>> lookup_slot[] = {
4123 : // Eval in inner context.
4124 : std::make_tuple("var x = 0;", "eval(''); return x;",
4125 : handle(Smi::kZero, isolate)),
4126 : std::make_tuple("var x = 0;", "eval('var x = 1'); return x;",
4127 : handle(Smi::FromInt(1), isolate)),
4128 : std::make_tuple("var x = 0;",
4129 : "'use strict'; eval('var x = 1'); return x;",
4130 : handle(Smi::kZero, isolate)),
4131 : // Eval in outer context.
4132 : std::make_tuple("var x = 0; eval('');", "return x;",
4133 : handle(Smi::kZero, isolate)),
4134 : std::make_tuple("var x = 0; eval('var x = 1');", "return x;",
4135 : handle(Smi::FromInt(1), isolate)),
4136 : std::make_tuple("'use strict'; var x = 0; eval('var x = 1');",
4137 : "return x;", handle(Smi::kZero, isolate)),
4138 : };
4139 :
4140 65 : for (size_t i = 0; i < arraysize(lookup_slot); i++) {
4141 120 : std::string body = std::string(std::get<0>(lookup_slot[i])) +
4142 120 : std::string(inner_function_prologue) +
4143 120 : std::string(std::get<1>(lookup_slot[i])) +
4144 : std::string(inner_function_epilogue) +
4145 90 : std::string(outer_function_epilogue);
4146 30 : std::string script = InterpreterTester::SourceForBody(body.c_str());
4147 :
4148 60 : InterpreterTester tester(isolate, script.c_str());
4149 : auto callable = tester.GetCallable<>();
4150 :
4151 : Handle<i::Object> return_value = callable().ToHandleChecked();
4152 30 : CHECK(return_value->SameValue(*std::get<2>(lookup_slot[i])));
4153 : }
4154 5 : }
4155 :
4156 26661 : TEST(InterpreterLookupGlobalSlot) {
4157 10 : HandleAndZoneScope handles;
4158 : Isolate* isolate = handles.main_isolate();
4159 :
4160 : const char* inner_function_prologue = "function inner() {";
4161 : const char* inner_function_epilogue = "};";
4162 : const char* outer_function_epilogue = "return inner();";
4163 :
4164 : std::tuple<const char*, const char*, Handle<Object>> lookup_slot[] = {
4165 : // Eval in inner context.
4166 : std::make_tuple("x = 0;", "eval(''); return x;",
4167 : handle(Smi::kZero, isolate)),
4168 : std::make_tuple("x = 0;", "eval('var x = 1'); return x;",
4169 : handle(Smi::FromInt(1), isolate)),
4170 : std::make_tuple("x = 0;", "'use strict'; eval('var x = 1'); return x;",
4171 : handle(Smi::kZero, isolate)),
4172 : // Eval in outer context.
4173 : std::make_tuple("x = 0; eval('');", "return x;",
4174 : handle(Smi::kZero, isolate)),
4175 : std::make_tuple("x = 0; eval('var x = 1');", "return x;",
4176 : handle(Smi::FromInt(1), isolate)),
4177 : std::make_tuple("'use strict'; x = 0; eval('var x = 1');", "return x;",
4178 : handle(Smi::kZero, isolate)),
4179 : };
4180 :
4181 65 : for (size_t i = 0; i < arraysize(lookup_slot); i++) {
4182 120 : std::string body = std::string(std::get<0>(lookup_slot[i])) +
4183 120 : std::string(inner_function_prologue) +
4184 120 : std::string(std::get<1>(lookup_slot[i])) +
4185 : std::string(inner_function_epilogue) +
4186 90 : std::string(outer_function_epilogue);
4187 30 : std::string script = InterpreterTester::SourceForBody(body.c_str());
4188 :
4189 60 : InterpreterTester tester(isolate, script.c_str());
4190 : auto callable = tester.GetCallable<>();
4191 :
4192 : Handle<i::Object> return_value = callable().ToHandleChecked();
4193 30 : CHECK(return_value->SameValue(*std::get<2>(lookup_slot[i])));
4194 : }
4195 5 : }
4196 :
4197 26661 : TEST(InterpreterCallLookupSlot) {
4198 10 : HandleAndZoneScope handles;
4199 : Isolate* isolate = handles.main_isolate();
4200 :
4201 : std::pair<const char*, Handle<Object>> call_lookup[] = {
4202 : {"g = function(){ return 2 }; eval(''); return g();",
4203 : handle(Smi::FromInt(2), isolate)},
4204 : {"g = function(){ return 2 }; eval('g = function() {return 3}');\n"
4205 : "return g();",
4206 : handle(Smi::FromInt(3), isolate)},
4207 : {"g = { x: function(){ return this.y }, y: 20 };\n"
4208 : "eval('g = { x: g.x, y: 30 }');\n"
4209 : "return g.x();",
4210 : handle(Smi::FromInt(30), isolate)},
4211 : };
4212 :
4213 35 : for (size_t i = 0; i < arraysize(call_lookup); i++) {
4214 15 : std::string source(InterpreterTester::SourceForBody(call_lookup[i].first));
4215 30 : InterpreterTester tester(isolate, source.c_str());
4216 : auto callable = tester.GetCallable<>();
4217 :
4218 : Handle<i::Object> return_value = callable().ToHandleChecked();
4219 30 : CHECK(return_value->SameValue(*call_lookup[i].second));
4220 : }
4221 5 : }
4222 :
4223 26661 : TEST(InterpreterLookupSlotWide) {
4224 10 : HandleAndZoneScope handles;
4225 : Isolate* isolate = handles.main_isolate();
4226 : Factory* factory = isolate->factory();
4227 :
4228 : const char* function_prologue =
4229 : "var f;"
4230 : "var x = 1;"
4231 : "function f1() {"
4232 : " eval(\"function t() {";
4233 : const char* function_epilogue =
4234 : " }; f = t;\");"
4235 : "}"
4236 : "f1();";
4237 10 : std::ostringstream str;
4238 5 : str << "var y = 2.3;";
4239 2555 : for (int i = 1; i < 256; i++) {
4240 2550 : str << "y = " << 2.3 + i << ";";
4241 : }
4242 : std::string init_function_body = str.str();
4243 :
4244 : std::pair<std::string, Handle<Object>> lookup_slot[] = {
4245 5 : {init_function_body + "return x;", handle(Smi::FromInt(1), isolate)},
4246 5 : {init_function_body + "return typeof x;",
4247 10 : factory->NewStringFromStaticChars("number")},
4248 5 : {init_function_body + "return x = 10;",
4249 : handle(Smi::FromInt(10), isolate)},
4250 15 : {"'use strict';" + init_function_body + "x = 20; return x;",
4251 : handle(Smi::FromInt(20), isolate)},
4252 25 : };
4253 :
4254 45 : for (size_t i = 0; i < arraysize(lookup_slot); i++) {
4255 60 : std::string script = std::string(function_prologue) + lookup_slot[i].first +
4256 60 : std::string(function_epilogue);
4257 :
4258 40 : InterpreterTester tester(isolate, script.c_str(), "t");
4259 : auto callable = tester.GetCallable<>();
4260 :
4261 : Handle<i::Object> return_value = callable().ToHandleChecked();
4262 40 : CHECK(return_value->SameValue(*lookup_slot[i].second));
4263 : }
4264 5 : }
4265 :
4266 26661 : TEST(InterpreterDeleteLookupSlot) {
4267 10 : HandleAndZoneScope handles;
4268 : Isolate* isolate = handles.main_isolate();
4269 : Factory* factory = isolate->factory();
4270 :
4271 : // TODO(mythria): Add more tests when we have support for eval/with.
4272 : const char* function_prologue = "var f;"
4273 : "var x = 1;"
4274 : "y = 10;"
4275 : "var obj = {val:10};"
4276 : "var z = 30;"
4277 : "function f1() {"
4278 : " var z = 20;"
4279 : " eval(\"function t() {";
4280 : const char* function_epilogue = " }; f = t;\");"
4281 : "}"
4282 : "f1();";
4283 :
4284 :
4285 : std::pair<const char*, Handle<Object>> delete_lookup_slot[] = {
4286 : {"return delete x;", factory->false_value()},
4287 : {"return delete y;", factory->true_value()},
4288 : {"return delete z;", factory->false_value()},
4289 : {"return delete obj.val;", factory->true_value()},
4290 : {"'use strict'; return delete obj.val;", factory->true_value()},
4291 : };
4292 :
4293 55 : for (size_t i = 0; i < arraysize(delete_lookup_slot); i++) {
4294 100 : std::string script = std::string(function_prologue) +
4295 : std::string(delete_lookup_slot[i].first) +
4296 75 : std::string(function_epilogue);
4297 :
4298 50 : InterpreterTester tester(isolate, script.c_str(), "t");
4299 : auto callable = tester.GetCallable<>();
4300 :
4301 : Handle<i::Object> return_value = callable().ToHandleChecked();
4302 50 : CHECK(return_value->SameValue(*delete_lookup_slot[i].second));
4303 : }
4304 5 : }
4305 :
4306 26661 : TEST(JumpWithConstantsAndWideConstants) {
4307 10 : HandleAndZoneScope handles;
4308 : Isolate* isolate = handles.main_isolate();
4309 : Factory* factory = isolate->factory();
4310 : const int kStep = 13;
4311 225 : for (int constants = 11; constants < 256 + 3 * kStep; constants += kStep) {
4312 220 : std::ostringstream filler_os;
4313 : // Generate a string that consumes constant pool entries and
4314 : // spread out branch distances in script below.
4315 32560 : for (int i = 0; i < constants; i++) {
4316 16225 : filler_os << "var x_ = 'x_" << i << "';\n";
4317 : }
4318 : std::string filler(filler_os.str());
4319 220 : std::ostringstream script_os;
4320 330 : script_os << "function " << InterpreterTester::function_name() << "(a) {\n";
4321 : script_os << " " << filler;
4322 110 : script_os << " for (var i = a; i < 2; i++) {\n";
4323 : script_os << " " << filler;
4324 110 : script_os << " if (i == 0) { " << filler << "i = 10; continue; }\n";
4325 110 : script_os << " else if (i == a) { " << filler << "i = 12; break; }\n";
4326 110 : script_os << " else { " << filler << " }\n";
4327 110 : script_os << " }\n";
4328 110 : script_os << " return i;\n";
4329 110 : script_os << "}\n";
4330 : std::string script(script_os.str());
4331 770 : for (int a = 0; a < 3; a++) {
4332 660 : InterpreterTester tester(isolate, script.c_str());
4333 : auto callable = tester.GetCallable<Handle<Object>>();
4334 330 : Handle<Object> argument = factory->NewNumberFromInt(a);
4335 660 : Handle<Object> return_val = callable(argument).ToHandleChecked();
4336 : static const int results[] = {11, 12, 2};
4337 660 : CHECK_EQ(Handle<Smi>::cast(return_val)->value(), results[a]);
4338 : }
4339 : }
4340 5 : }
4341 :
4342 26661 : TEST(InterpreterEval) {
4343 10 : HandleAndZoneScope handles;
4344 : Isolate* isolate = handles.main_isolate();
4345 : Factory* factory = isolate->factory();
4346 :
4347 : std::pair<const char*, Handle<Object>> eval[] = {
4348 : {"return eval('1;');", handle(Smi::FromInt(1), isolate)},
4349 : {"return eval('100 * 20;');", handle(Smi::FromInt(2000), isolate)},
4350 : {"var x = 10; return eval('x + 20;');",
4351 : handle(Smi::FromInt(30), isolate)},
4352 : {"var x = 10; eval('x = 33;'); return x;",
4353 : handle(Smi::FromInt(33), isolate)},
4354 : {"'use strict'; var x = 20; var z = 0;\n"
4355 : "eval('var x = 33; z = x;'); return x + z;",
4356 : handle(Smi::FromInt(53), isolate)},
4357 : {"eval('var x = 33;'); eval('var y = x + 20'); return x + y;",
4358 : handle(Smi::FromInt(86), isolate)},
4359 : {"var x = 1; eval('for(i = 0; i < 10; i++) x = x + 1;'); return x",
4360 : handle(Smi::FromInt(11), isolate)},
4361 : {"var x = 10; eval('var x = 20;'); return x;",
4362 : handle(Smi::FromInt(20), isolate)},
4363 : {"var x = 1; eval('\"use strict\"; var x = 2;'); return x;",
4364 : handle(Smi::FromInt(1), isolate)},
4365 : {"'use strict'; var x = 1; eval('var x = 2;'); return x;",
4366 : handle(Smi::FromInt(1), isolate)},
4367 : {"var x = 10; eval('x + 20;'); return typeof x;",
4368 10 : factory->NewStringFromStaticChars("number")},
4369 : {"eval('var y = 10;'); return typeof unallocated;",
4370 10 : factory->NewStringFromStaticChars("undefined")},
4371 : {"'use strict'; eval('var y = 10;'); return typeof unallocated;",
4372 10 : factory->NewStringFromStaticChars("undefined")},
4373 : {"eval('var x = 10;'); return typeof x;",
4374 10 : factory->NewStringFromStaticChars("number")},
4375 : {"var x = {}; eval('var x = 10;'); return typeof x;",
4376 10 : factory->NewStringFromStaticChars("number")},
4377 : {"'use strict'; var x = {}; eval('var x = 10;'); return typeof x;",
4378 10 : factory->NewStringFromStaticChars("object")},
4379 : };
4380 :
4381 165 : for (size_t i = 0; i < arraysize(eval); i++) {
4382 80 : std::string source(InterpreterTester::SourceForBody(eval[i].first));
4383 160 : InterpreterTester tester(isolate, source.c_str());
4384 : auto callable = tester.GetCallable<>();
4385 : Handle<i::Object> return_value = callable().ToHandleChecked();
4386 160 : CHECK(return_value->SameValue(*eval[i].second));
4387 : }
4388 5 : }
4389 :
4390 26661 : TEST(InterpreterEvalParams) {
4391 10 : HandleAndZoneScope handles;
4392 : Isolate* isolate = handles.main_isolate();
4393 :
4394 : std::pair<const char*, Handle<Object>> eval_params[] = {
4395 : {"var x = 10; return eval('x + p1;');",
4396 : handle(Smi::FromInt(30), isolate)},
4397 : {"var x = 10; eval('p1 = x;'); return p1;",
4398 : handle(Smi::FromInt(10), isolate)},
4399 : {"var a = 10;"
4400 : "function inner() { return eval('a + p1;');}"
4401 : "return inner();",
4402 : handle(Smi::FromInt(30), isolate)},
4403 : };
4404 :
4405 35 : for (size_t i = 0; i < arraysize(eval_params); i++) {
4406 60 : std::string source = "function " + InterpreterTester::function_name() +
4407 45 : "(p1) {" + eval_params[i].first + "}";
4408 30 : InterpreterTester tester(isolate, source.c_str());
4409 : auto callable = tester.GetCallable<Handle<Object>>();
4410 :
4411 : Handle<i::Object> return_value =
4412 30 : callable(handle(Smi::FromInt(20), isolate)).ToHandleChecked();
4413 30 : CHECK(return_value->SameValue(*eval_params[i].second));
4414 : }
4415 5 : }
4416 :
4417 26661 : TEST(InterpreterEvalGlobal) {
4418 10 : HandleAndZoneScope handles;
4419 : Isolate* isolate = handles.main_isolate();
4420 : Factory* factory = isolate->factory();
4421 :
4422 : std::pair<const char*, Handle<Object>> eval_global[] = {
4423 : {"function add_global() { eval('function test() { z = 33; }; test()'); };"
4424 : "function f() { add_global(); return z; }; f();",
4425 : handle(Smi::FromInt(33), isolate)},
4426 : {"function add_global() {\n"
4427 : " eval('\"use strict\"; function test() { y = 33; };"
4428 : " try { test() } catch(e) {}');\n"
4429 : "}\n"
4430 : "function f() { add_global(); return typeof y; } f();",
4431 10 : factory->NewStringFromStaticChars("undefined")},
4432 : };
4433 :
4434 25 : for (size_t i = 0; i < arraysize(eval_global); i++) {
4435 20 : InterpreterTester tester(isolate, eval_global[i].first, "test");
4436 : auto callable = tester.GetCallable<>();
4437 :
4438 : Handle<i::Object> return_value = callable().ToHandleChecked();
4439 20 : CHECK(return_value->SameValue(*eval_global[i].second));
4440 : }
4441 5 : }
4442 :
4443 26661 : TEST(InterpreterEvalVariableDecl) {
4444 10 : HandleAndZoneScope handles;
4445 : Isolate* isolate = handles.main_isolate();
4446 : Factory* factory = isolate->factory();
4447 :
4448 : std::pair<const char*, Handle<Object>> eval_global[] = {
4449 : {"function f() { eval('var x = 10; x++;'); return x; }",
4450 : handle(Smi::FromInt(11), isolate)},
4451 : {"function f() { var x = 20; eval('var x = 10; x++;'); return x; }",
4452 : handle(Smi::FromInt(11), isolate)},
4453 : {"function f() {"
4454 : " var x = 20;"
4455 : " eval('\"use strict\"; var x = 10; x++;');"
4456 : " return x; }",
4457 : handle(Smi::FromInt(20), isolate)},
4458 : {"function f() {"
4459 : " var y = 30;"
4460 : " eval('var x = {1:20}; x[2]=y;');"
4461 : " return x[2]; }",
4462 : handle(Smi::FromInt(30), isolate)},
4463 : {"function f() {"
4464 : " eval('var x = {name:\"test\"};');"
4465 : " return x.name; }",
4466 10 : factory->NewStringFromStaticChars("test")},
4467 : {"function f() {"
4468 : " eval('var x = [{name:\"test\"}, {type:\"cc\"}];');"
4469 : " return x[1].type+x[0].name; }",
4470 10 : factory->NewStringFromStaticChars("cctest")},
4471 : {"function f() {\n"
4472 : " var x = 3;\n"
4473 : " var get_eval_x;\n"
4474 : " eval('\"use strict\"; "
4475 : " var x = 20; "
4476 : " get_eval_x = function func() {return x;};');\n"
4477 : " return get_eval_x() + x;\n"
4478 : "}",
4479 : handle(Smi::FromInt(23), isolate)},
4480 : // TODO(mythria): Add tests with const declarations.
4481 : };
4482 :
4483 75 : for (size_t i = 0; i < arraysize(eval_global); i++) {
4484 70 : InterpreterTester tester(isolate, eval_global[i].first, "*");
4485 : auto callable = tester.GetCallable<>();
4486 :
4487 : Handle<i::Object> return_value = callable().ToHandleChecked();
4488 70 : CHECK(return_value->SameValue(*eval_global[i].second));
4489 : }
4490 5 : }
4491 :
4492 26661 : TEST(InterpreterEvalFunctionDecl) {
4493 10 : HandleAndZoneScope handles;
4494 : Isolate* isolate = handles.main_isolate();
4495 :
4496 : std::pair<const char*, Handle<Object>> eval_func_decl[] = {
4497 : {"function f() {\n"
4498 : " var x = 3;\n"
4499 : " eval('var x = 20;"
4500 : " function get_x() {return x;};');\n"
4501 : " return get_x() + x;\n"
4502 : "}",
4503 : handle(Smi::FromInt(40), isolate)},
4504 : };
4505 :
4506 15 : for (size_t i = 0; i < arraysize(eval_func_decl); i++) {
4507 10 : InterpreterTester tester(isolate, eval_func_decl[i].first, "*");
4508 : auto callable = tester.GetCallable<>();
4509 :
4510 : Handle<i::Object> return_value = callable().ToHandleChecked();
4511 10 : CHECK(return_value->SameValue(*eval_func_decl[i].second));
4512 : }
4513 5 : }
4514 :
4515 26661 : TEST(InterpreterWideRegisterArithmetic) {
4516 10 : HandleAndZoneScope handles;
4517 : Isolate* isolate = handles.main_isolate();
4518 :
4519 : static const size_t kMaxRegisterForTest = 150;
4520 10 : std::ostringstream os;
4521 15 : os << "function " << InterpreterTester::function_name() << "(arg) {\n";
4522 5 : os << " var retval = -77;\n";
4523 1505 : for (size_t i = 0; i < kMaxRegisterForTest; i++) {
4524 750 : os << " var x" << i << " = " << i << ";\n";
4525 : }
4526 755 : for (size_t i = 0; i < kMaxRegisterForTest / 2; i++) {
4527 375 : size_t j = kMaxRegisterForTest - i - 1;
4528 375 : os << " var tmp = x" << j << ";\n";
4529 375 : os << " var x" << j << " = x" << i << ";\n";
4530 375 : os << " var x" << i << " = tmp;\n";
4531 : }
4532 755 : for (size_t i = 0; i < kMaxRegisterForTest / 2; i++) {
4533 375 : size_t j = kMaxRegisterForTest - i - 1;
4534 375 : os << " var tmp = x" << j << ";\n";
4535 375 : os << " var x" << j << " = x" << i << ";\n";
4536 375 : os << " var x" << i << " = tmp;\n";
4537 : }
4538 1505 : for (size_t i = 0; i < kMaxRegisterForTest; i++) {
4539 : os << " if (arg == " << i << ") {\n" //
4540 : << " retval = x" << i << ";\n" //
4541 750 : << " }\n"; //
4542 : }
4543 5 : os << " return retval;\n";
4544 5 : os << "}\n";
4545 :
4546 : std::string source = os.str();
4547 10 : InterpreterTester tester(isolate, source.c_str());
4548 : auto callable = tester.GetCallable<Handle<Object>>();
4549 1505 : for (size_t i = 0; i < kMaxRegisterForTest; i++) {
4550 750 : Handle<Object> arg = handle(Smi::FromInt(static_cast<int>(i)), isolate);
4551 1500 : Handle<Object> return_value = callable(arg).ToHandleChecked();
4552 750 : CHECK(return_value->SameValue(*arg));
4553 : }
4554 5 : }
4555 :
4556 26661 : TEST(InterpreterCallWideRegisters) {
4557 : static const int kPeriod = 25;
4558 : static const int kLength = 512;
4559 : static const int kStartChar = 65;
4560 :
4561 10 : HandleAndZoneScope handles;
4562 : Isolate* isolate = handles.main_isolate();
4563 :
4564 35 : for (int pass = 0; pass < 3; pass += 1) {
4565 30 : std::ostringstream os;
4566 2925 : for (int i = 0; i < pass * 97; i += 1) {
4567 2910 : os << "var x" << i << " = " << i << "\n";
4568 : }
4569 15 : os << "return String.fromCharCode(";
4570 15 : os << kStartChar;
4571 15345 : for (int i = 1; i < kLength; i += 1) {
4572 15330 : os << "," << kStartChar + (i % kPeriod);
4573 : }
4574 15 : os << ");";
4575 30 : std::string source = InterpreterTester::SourceForBody(os.str().c_str());
4576 30 : InterpreterTester tester(isolate, source.c_str());
4577 : auto callable = tester.GetCallable();
4578 : Handle<Object> return_val = callable().ToHandleChecked();
4579 : Handle<String> return_string = Handle<String>::cast(return_val);
4580 15 : CHECK_EQ(return_string->length(), kLength);
4581 15375 : for (int i = 0; i < kLength; i += 1) {
4582 15360 : CHECK_EQ(return_string->Get(i), 65 + (i % kPeriod));
4583 : }
4584 : }
4585 5 : }
4586 :
4587 26661 : TEST(InterpreterWideParametersPickOne) {
4588 10 : HandleAndZoneScope handles;
4589 : Isolate* isolate = handles.main_isolate();
4590 : static const int kParameterCount = 130;
4591 105 : for (int parameter = 0; parameter < 10; parameter++) {
4592 100 : std::ostringstream os;
4593 150 : os << "function " << InterpreterTester::function_name() << "(arg) {\n";
4594 50 : os << " function selector(i";
4595 13050 : for (int i = 0; i < kParameterCount; i++) {
4596 : os << ","
4597 6500 : << "a" << i;
4598 : }
4599 50 : os << ") {\n";
4600 50 : os << " return a" << parameter << ";\n";
4601 50 : os << " };\n";
4602 50 : os << " return selector(arg";
4603 13050 : for (int i = 0; i < kParameterCount; i++) {
4604 6500 : os << "," << i;
4605 : }
4606 50 : os << ");";
4607 50 : os << "}\n";
4608 :
4609 : std::string source = os.str();
4610 100 : InterpreterTester tester(isolate, source.c_str(), "*");
4611 : auto callable = tester.GetCallable<Handle<Object>>();
4612 : Handle<Object> arg = handle(Smi::FromInt(0xAA55), isolate);
4613 100 : Handle<Object> return_value = callable(arg).ToHandleChecked();
4614 : Handle<Smi> actual = Handle<Smi>::cast(return_value);
4615 50 : CHECK_EQ(actual->value(), parameter);
4616 : }
4617 5 : }
4618 :
4619 26661 : TEST(InterpreterWideParametersSummation) {
4620 : static int kParameterCount = 200;
4621 : static int kBaseValue = 17000;
4622 10 : HandleAndZoneScope handles;
4623 : Isolate* isolate = handles.main_isolate();
4624 10 : std::ostringstream os;
4625 15 : os << "function " << InterpreterTester::function_name() << "(arg) {\n";
4626 5 : os << " function summation(i";
4627 2005 : for (int i = 0; i < kParameterCount; i++) {
4628 : os << ","
4629 1000 : << "a" << i;
4630 : }
4631 5 : os << ") {\n";
4632 10 : os << " var sum = " << kBaseValue << ";\n";
4633 5 : os << " switch(i) {\n";
4634 2005 : for (int i = 0; i < kParameterCount; i++) {
4635 1000 : int j = kParameterCount - i - 1;
4636 2000 : os << " case " << j << ": sum += a" << j << ";\n";
4637 : }
4638 5 : os << " }\n";
4639 5 : os << " return sum;\n";
4640 5 : os << " };\n";
4641 5 : os << " return summation(arg";
4642 2005 : for (int i = 0; i < kParameterCount; i++) {
4643 1000 : os << "," << i;
4644 : }
4645 5 : os << ");";
4646 5 : os << "}\n";
4647 :
4648 : std::string source = os.str();
4649 10 : InterpreterTester tester(isolate, source.c_str(), "*");
4650 : auto callable = tester.GetCallable<Handle<Object>>();
4651 2005 : for (int i = 0; i < kParameterCount; i++) {
4652 : Handle<Object> arg = handle(Smi::FromInt(i), isolate);
4653 2000 : Handle<Object> return_value = callable(arg).ToHandleChecked();
4654 1000 : int expected = kBaseValue + i * (i + 1) / 2;
4655 : Handle<Smi> actual = Handle<Smi>::cast(return_value);
4656 1000 : CHECK_EQ(actual->value(), expected);
4657 : }
4658 5 : }
4659 :
4660 26661 : TEST(InterpreterWithStatement) {
4661 10 : HandleAndZoneScope handles;
4662 : Isolate* isolate = handles.main_isolate();
4663 :
4664 : std::pair<const char*, Handle<Object>> with_stmt[] = {
4665 : {"with({x:42}) return x;", handle(Smi::FromInt(42), isolate)},
4666 : {"with({}) { var y = 10; return y;}", handle(Smi::FromInt(10), isolate)},
4667 : {"var y = {x:42};"
4668 : " function inner() {"
4669 : " var x = 20;"
4670 : " with(y) return x;"
4671 : "}"
4672 : "return inner();",
4673 : handle(Smi::FromInt(42), isolate)},
4674 : {"var y = {x:42};"
4675 : " function inner(o) {"
4676 : " var x = 20;"
4677 : " with(o) return x;"
4678 : "}"
4679 : "return inner(y);",
4680 : handle(Smi::FromInt(42), isolate)},
4681 : };
4682 :
4683 45 : for (size_t i = 0; i < arraysize(with_stmt); i++) {
4684 20 : std::string source(InterpreterTester::SourceForBody(with_stmt[i].first));
4685 40 : InterpreterTester tester(isolate, source.c_str());
4686 : auto callable = tester.GetCallable<>();
4687 :
4688 : Handle<i::Object> return_value = callable().ToHandleChecked();
4689 40 : CHECK(return_value->SameValue(*with_stmt[i].second));
4690 : }
4691 5 : }
4692 :
4693 26661 : TEST(InterpreterClassLiterals) {
4694 10 : HandleAndZoneScope handles;
4695 : Isolate* isolate = handles.main_isolate();
4696 : std::pair<const char*, Handle<Object>> examples[] = {
4697 : {"class C {\n"
4698 : " constructor(x) { this.x_ = x; }\n"
4699 : " method() { return this.x_; }\n"
4700 : "}\n"
4701 : "return new C(99).method();",
4702 : handle(Smi::FromInt(99), isolate)},
4703 : {"class C {\n"
4704 : " constructor(x) { this.x_ = x; }\n"
4705 : " static static_method(x) { return x; }\n"
4706 : "}\n"
4707 : "return C.static_method(101);",
4708 : handle(Smi::FromInt(101), isolate)},
4709 : {"class C {\n"
4710 : " get x() { return 102; }\n"
4711 : "}\n"
4712 : "return new C().x",
4713 : handle(Smi::FromInt(102), isolate)},
4714 : {"class C {\n"
4715 : " static get x() { return 103; }\n"
4716 : "}\n"
4717 : "return C.x",
4718 : handle(Smi::FromInt(103), isolate)},
4719 : {"class C {\n"
4720 : " constructor() { this.x_ = 0; }"
4721 : " set x(value) { this.x_ = value; }\n"
4722 : " get x() { return this.x_; }\n"
4723 : "}\n"
4724 : "var c = new C();"
4725 : "c.x = 104;"
4726 : "return c.x;",
4727 : handle(Smi::FromInt(104), isolate)},
4728 : {"var x = 0;"
4729 : "class C {\n"
4730 : " static set x(value) { x = value; }\n"
4731 : " static get x() { return x; }\n"
4732 : "}\n"
4733 : "C.x = 105;"
4734 : "return C.x;",
4735 : handle(Smi::FromInt(105), isolate)},
4736 : {"var method = 'f';"
4737 : "class C {\n"
4738 : " [method]() { return 106; }\n"
4739 : "}\n"
4740 : "return new C().f();",
4741 : handle(Smi::FromInt(106), isolate)},
4742 : };
4743 :
4744 75 : for (size_t i = 0; i < arraysize(examples); ++i) {
4745 35 : std::string source(InterpreterTester::SourceForBody(examples[i].first));
4746 70 : InterpreterTester tester(isolate, source.c_str(), "*");
4747 : auto callable = tester.GetCallable<>();
4748 :
4749 : Handle<i::Object> return_value = callable().ToHandleChecked();
4750 70 : CHECK(return_value->SameValue(*examples[i].second));
4751 : }
4752 5 : }
4753 :
4754 26661 : TEST(InterpreterClassAndSuperClass) {
4755 10 : HandleAndZoneScope handles;
4756 : Isolate* isolate = handles.main_isolate();
4757 : std::pair<const char*, Handle<Object>> examples[] = {
4758 : {"class A {\n"
4759 : " constructor(x) { this.x_ = x; }\n"
4760 : " method() { return this.x_; }\n"
4761 : "}\n"
4762 : "class B extends A {\n"
4763 : " constructor(x, y) { super(x); this.y_ = y; }\n"
4764 : " method() { return super.method() + 1; }\n"
4765 : "}\n"
4766 : "return new B(998, 0).method();\n",
4767 : handle(Smi::FromInt(999), isolate)},
4768 : {"class A {\n"
4769 : " constructor() { this.x_ = 2; this.y_ = 3; }\n"
4770 : "}\n"
4771 : "class B extends A {\n"
4772 : " constructor() { super(); }"
4773 : " method() { this.x_++; this.y_++; return this.x_ + this.y_; }\n"
4774 : "}\n"
4775 : "return new B().method();\n",
4776 : handle(Smi::FromInt(7), isolate)},
4777 : {"var calls = 0;\n"
4778 : "class B {}\n"
4779 : "B.prototype.x = 42;\n"
4780 : "class C extends B {\n"
4781 : " constructor() {\n"
4782 : " super();\n"
4783 : " calls++;\n"
4784 : " }\n"
4785 : "}\n"
4786 : "new C;\n"
4787 : "return calls;\n",
4788 : handle(Smi::FromInt(1), isolate)},
4789 : {"class A {\n"
4790 : " method() { return 1; }\n"
4791 : " get x() { return 2; }\n"
4792 : "}\n"
4793 : "class B extends A {\n"
4794 : " method() { return super.x === 2 ? super.method() : -1; }\n"
4795 : "}\n"
4796 : "return new B().method();\n",
4797 : handle(Smi::FromInt(1), isolate)},
4798 : {"var object = { setY(v) { super.y = v; }};\n"
4799 : "object.setY(10);\n"
4800 : "return object.y;\n",
4801 : handle(Smi::FromInt(10), isolate)},
4802 : };
4803 :
4804 55 : for (size_t i = 0; i < arraysize(examples); ++i) {
4805 25 : std::string source(InterpreterTester::SourceForBody(examples[i].first));
4806 50 : InterpreterTester tester(isolate, source.c_str(), "*");
4807 : auto callable = tester.GetCallable<>();
4808 : Handle<i::Object> return_value = callable().ToHandleChecked();
4809 50 : CHECK(return_value->SameValue(*examples[i].second));
4810 : }
4811 5 : }
4812 :
4813 26661 : TEST(InterpreterConstDeclaration) {
4814 10 : HandleAndZoneScope handles;
4815 : Isolate* isolate = handles.main_isolate();
4816 : Factory* factory = isolate->factory();
4817 :
4818 : std::pair<const char*, Handle<Object>> const_decl[] = {
4819 : {"const x = 3; return x;", handle(Smi::FromInt(3), isolate)},
4820 : {"let x = 10; x = x + 20; return x;", handle(Smi::FromInt(30), isolate)},
4821 : {"let x = 10; x = 20; return x;", handle(Smi::FromInt(20), isolate)},
4822 : {"let x; x = 20; return x;", handle(Smi::FromInt(20), isolate)},
4823 : {"let x; return x;", factory->undefined_value()},
4824 : {"var x = 10; { let x = 30; } return x;",
4825 : handle(Smi::FromInt(10), isolate)},
4826 : {"let x = 10; { let x = 20; } return x;",
4827 : handle(Smi::FromInt(10), isolate)},
4828 : {"var x = 10; eval('let x = 20;'); return x;",
4829 : handle(Smi::FromInt(10), isolate)},
4830 : {"var x = 10; eval('const x = 20;'); return x;",
4831 : handle(Smi::FromInt(10), isolate)},
4832 : {"var x = 10; { const x = 20; } return x;",
4833 : handle(Smi::FromInt(10), isolate)},
4834 : {"var x = 10; { const x = 20; return x;} return -1;",
4835 : handle(Smi::FromInt(20), isolate)},
4836 : {"var a = 10;\n"
4837 : "for (var i = 0; i < 10; ++i) {\n"
4838 : " const x = i;\n" // const declarations are block scoped.
4839 : " a = a + x;\n"
4840 : "}\n"
4841 : "return a;\n",
4842 : handle(Smi::FromInt(55), isolate)},
4843 : };
4844 :
4845 : // Tests for sloppy mode.
4846 125 : for (size_t i = 0; i < arraysize(const_decl); i++) {
4847 60 : std::string source(InterpreterTester::SourceForBody(const_decl[i].first));
4848 120 : InterpreterTester tester(isolate, source.c_str());
4849 : auto callable = tester.GetCallable<>();
4850 :
4851 : Handle<i::Object> return_value = callable().ToHandleChecked();
4852 120 : CHECK(return_value->SameValue(*const_decl[i].second));
4853 : }
4854 :
4855 : // Tests for strict mode.
4856 125 : for (size_t i = 0; i < arraysize(const_decl); i++) {
4857 : std::string strict_body =
4858 120 : "'use strict'; " + std::string(const_decl[i].first);
4859 60 : std::string source(InterpreterTester::SourceForBody(strict_body.c_str()));
4860 120 : InterpreterTester tester(isolate, source.c_str());
4861 : auto callable = tester.GetCallable<>();
4862 :
4863 : Handle<i::Object> return_value = callable().ToHandleChecked();
4864 120 : CHECK(return_value->SameValue(*const_decl[i].second));
4865 : }
4866 5 : }
4867 :
4868 26661 : TEST(InterpreterConstDeclarationLookupSlots) {
4869 10 : HandleAndZoneScope handles;
4870 : Isolate* isolate = handles.main_isolate();
4871 : Factory* factory = isolate->factory();
4872 :
4873 : std::pair<const char*, Handle<Object>> const_decl[] = {
4874 : {"const x = 3; function f1() {return x;}; return x;",
4875 : handle(Smi::FromInt(3), isolate)},
4876 : {"let x = 10; x = x + 20; function f1() {return x;}; return x;",
4877 : handle(Smi::FromInt(30), isolate)},
4878 : {"let x; x = 20; function f1() {return x;}; return x;",
4879 : handle(Smi::FromInt(20), isolate)},
4880 : {"let x; function f1() {return x;}; return x;",
4881 : factory->undefined_value()},
4882 : };
4883 :
4884 : // Tests for sloppy mode.
4885 45 : for (size_t i = 0; i < arraysize(const_decl); i++) {
4886 20 : std::string source(InterpreterTester::SourceForBody(const_decl[i].first));
4887 40 : InterpreterTester tester(isolate, source.c_str());
4888 : auto callable = tester.GetCallable<>();
4889 :
4890 : Handle<i::Object> return_value = callable().ToHandleChecked();
4891 40 : CHECK(return_value->SameValue(*const_decl[i].second));
4892 : }
4893 :
4894 : // Tests for strict mode.
4895 45 : for (size_t i = 0; i < arraysize(const_decl); i++) {
4896 : std::string strict_body =
4897 40 : "'use strict'; " + std::string(const_decl[i].first);
4898 20 : std::string source(InterpreterTester::SourceForBody(strict_body.c_str()));
4899 40 : InterpreterTester tester(isolate, source.c_str());
4900 : auto callable = tester.GetCallable<>();
4901 :
4902 : Handle<i::Object> return_value = callable().ToHandleChecked();
4903 40 : CHECK(return_value->SameValue(*const_decl[i].second));
4904 : }
4905 5 : }
4906 :
4907 26661 : TEST(InterpreterConstInLookupContextChain) {
4908 10 : HandleAndZoneScope handles;
4909 : Isolate* isolate = handles.main_isolate();
4910 :
4911 : const char* prologue =
4912 : "function OuterMost() {\n"
4913 : " const outerConst = 10;\n"
4914 : " let outerLet = 20;\n"
4915 : " function Outer() {\n"
4916 : " function Inner() {\n"
4917 : " this.innerFunc = function() { ";
4918 : const char* epilogue =
4919 : " }\n"
4920 : " }\n"
4921 : " this.getInnerFunc ="
4922 : " function() {return new Inner().innerFunc;}\n"
4923 : " }\n"
4924 : " this.getOuterFunc ="
4925 : " function() {return new Outer().getInnerFunc();}"
4926 : "}\n"
4927 : "var f = new OuterMost().getOuterFunc();\n"
4928 : "f();\n";
4929 : std::pair<const char*, Handle<Object>> const_decl[] = {
4930 : {"return outerConst;", handle(Smi::FromInt(10), isolate)},
4931 : {"return outerLet;", handle(Smi::FromInt(20), isolate)},
4932 : {"outerLet = 30; return outerLet;", handle(Smi::FromInt(30), isolate)},
4933 : {"var outerLet = 40; return outerLet;",
4934 : handle(Smi::FromInt(40), isolate)},
4935 : {"var outerConst = 50; return outerConst;",
4936 : handle(Smi::FromInt(50), isolate)},
4937 : {"try { outerConst = 30 } catch(e) { return -1; }",
4938 : handle(Smi::FromInt(-1), isolate)}};
4939 :
4940 65 : for (size_t i = 0; i < arraysize(const_decl); i++) {
4941 120 : std::string script = std::string(prologue) +
4942 : std::string(const_decl[i].first) +
4943 90 : std::string(epilogue);
4944 60 : InterpreterTester tester(isolate, script.c_str(), "*");
4945 : auto callable = tester.GetCallable<>();
4946 :
4947 : Handle<i::Object> return_value = callable().ToHandleChecked();
4948 60 : CHECK(return_value->SameValue(*const_decl[i].second));
4949 : }
4950 5 : }
4951 :
4952 26661 : TEST(InterpreterIllegalConstDeclaration) {
4953 10 : HandleAndZoneScope handles;
4954 : Isolate* isolate = handles.main_isolate();
4955 :
4956 : std::pair<const char*, const char*> const_decl[] = {
4957 : {"const x = x = 10 + 3; return x;",
4958 : "Uncaught ReferenceError: Cannot access 'x' before initialization"},
4959 : {"const x = 10; x = 20; return x;",
4960 : "Uncaught TypeError: Assignment to constant variable."},
4961 : {"const x = 10; { x = 20; } return x;",
4962 : "Uncaught TypeError: Assignment to constant variable."},
4963 : {"const x = 10; eval('x = 20;'); return x;",
4964 : "Uncaught TypeError: Assignment to constant variable."},
4965 : {"let x = x + 10; return x;",
4966 : "Uncaught ReferenceError: Cannot access 'x' before initialization"},
4967 : {"'use strict'; (function f1() { f1 = 123; })() ",
4968 : "Uncaught TypeError: Assignment to constant variable."},
4969 5 : };
4970 :
4971 : // Tests for sloppy mode.
4972 65 : for (size_t i = 0; i < arraysize(const_decl); i++) {
4973 30 : std::string source(InterpreterTester::SourceForBody(const_decl[i].first));
4974 60 : InterpreterTester tester(isolate, source.c_str());
4975 60 : v8::Local<v8::String> message = tester.CheckThrowsReturnMessage()->Get();
4976 30 : v8::Local<v8::String> expected_string = v8_str(const_decl[i].second);
4977 90 : CHECK(
4978 : message->Equals(CcTest::isolate()->GetCurrentContext(), expected_string)
4979 : .FromJust());
4980 : }
4981 :
4982 : // Tests for strict mode.
4983 65 : for (size_t i = 0; i < arraysize(const_decl); i++) {
4984 : std::string strict_body =
4985 60 : "'use strict'; " + std::string(const_decl[i].first);
4986 30 : std::string source(InterpreterTester::SourceForBody(strict_body.c_str()));
4987 60 : InterpreterTester tester(isolate, source.c_str());
4988 60 : v8::Local<v8::String> message = tester.CheckThrowsReturnMessage()->Get();
4989 30 : v8::Local<v8::String> expected_string = v8_str(const_decl[i].second);
4990 90 : CHECK(
4991 : message->Equals(CcTest::isolate()->GetCurrentContext(), expected_string)
4992 : .FromJust());
4993 : }
4994 5 : }
4995 :
4996 26661 : TEST(InterpreterGenerators) {
4997 10 : HandleAndZoneScope handles;
4998 : Isolate* isolate = handles.main_isolate();
4999 : Factory* factory = isolate->factory();
5000 :
5001 : std::pair<const char*, Handle<Object>> tests[] = {
5002 : {"function* f() { }; return f().next().value",
5003 : factory->undefined_value()},
5004 : {"function* f() { yield 42 }; return f().next().value",
5005 10 : factory->NewNumberFromInt(42)},
5006 : {"function* f() { for (let x of [42]) yield x}; return f().next().value",
5007 10 : factory->NewNumberFromInt(42)},
5008 : };
5009 :
5010 35 : for (size_t i = 0; i < arraysize(tests); i++) {
5011 15 : std::string source(InterpreterTester::SourceForBody(tests[i].first));
5012 30 : InterpreterTester tester(isolate, source.c_str());
5013 : auto callable = tester.GetCallable<>();
5014 :
5015 : Handle<i::Object> return_value = callable().ToHandleChecked();
5016 30 : CHECK(return_value->SameValue(*tests[i].second));
5017 : }
5018 5 : }
5019 :
5020 : #ifndef V8_TARGET_ARCH_ARM
5021 26661 : TEST(InterpreterWithNativeStack) {
5022 5 : i::FLAG_interpreted_frames_native_stack = true;
5023 :
5024 10 : HandleAndZoneScope handles;
5025 : i::Isolate* isolate = handles.main_isolate();
5026 :
5027 : const char* source_text =
5028 : "function testInterpreterWithNativeStack(a,b) { return a + b };";
5029 :
5030 : i::Handle<i::Object> o = v8::Utils::OpenHandle(*v8_compile(source_text));
5031 : i::Handle<i::JSFunction> f = i::Handle<i::JSFunction>::cast(o);
5032 :
5033 5 : CHECK(f->shared()->HasBytecodeArray());
5034 5 : i::Code code = f->shared()->GetCode();
5035 : i::Handle<i::Code> interpreter_entry_trampoline =
5036 5 : BUILTIN_CODE(isolate, InterpreterEntryTrampoline);
5037 :
5038 5 : CHECK(code->IsCode());
5039 5 : CHECK(code->is_interpreter_trampoline_builtin());
5040 5 : CHECK_NE(code->address(), interpreter_entry_trampoline->address());
5041 5 : }
5042 : #endif // V8_TARGET_ARCH_ARM
5043 :
5044 26661 : TEST(InterpreterGetBytecodeHandler) {
5045 10 : HandleAndZoneScope handles;
5046 : Isolate* isolate = handles.main_isolate();
5047 : Interpreter* interpreter = isolate->interpreter();
5048 :
5049 : // Test that single-width bytecode handlers deserializer correctly.
5050 : Code wide_handler =
5051 5 : interpreter->GetBytecodeHandler(Bytecode::kWide, OperandScale::kSingle);
5052 :
5053 5 : CHECK_EQ(wide_handler->builtin_index(), Builtins::kWideHandler);
5054 :
5055 : Code add_handler =
5056 5 : interpreter->GetBytecodeHandler(Bytecode::kAdd, OperandScale::kSingle);
5057 :
5058 5 : CHECK_EQ(add_handler->builtin_index(), Builtins::kAddHandler);
5059 :
5060 : // Test that double-width bytecode handlers deserializer correctly, including
5061 : // an illegal bytecode handler since there is no Wide.Wide handler.
5062 : Code wide_wide_handler =
5063 5 : interpreter->GetBytecodeHandler(Bytecode::kWide, OperandScale::kDouble);
5064 :
5065 5 : CHECK_EQ(wide_wide_handler->builtin_index(), Builtins::kIllegalHandler);
5066 :
5067 : Code add_wide_handler =
5068 5 : interpreter->GetBytecodeHandler(Bytecode::kAdd, OperandScale::kDouble);
5069 :
5070 5 : CHECK_EQ(add_wide_handler->builtin_index(), Builtins::kAddWideHandler);
5071 5 : }
5072 :
5073 26661 : TEST(InterpreterCollectSourcePositions) {
5074 5 : FLAG_enable_lazy_source_positions = true;
5075 10 : HandleAndZoneScope handles;
5076 : Isolate* isolate = handles.main_isolate();
5077 :
5078 : const char* source =
5079 : "(function () {\n"
5080 : " return 1;\n"
5081 : "})";
5082 :
5083 : Handle<JSFunction> function = Handle<JSFunction>::cast(v8::Utils::OpenHandle(
5084 : *v8::Local<v8::Function>::Cast(CompileRun(source))));
5085 :
5086 : Handle<SharedFunctionInfo> sfi = handle(function->shared(), isolate);
5087 : Handle<BytecodeArray> bytecode_array =
5088 10 : handle(sfi->GetBytecodeArray(), isolate);
5089 5 : CHECK(!bytecode_array->HasSourcePositionTable());
5090 :
5091 5 : Compiler::CollectSourcePositions(isolate, sfi);
5092 :
5093 5 : ByteArray source_position_table = bytecode_array->SourcePositionTable();
5094 5 : CHECK(bytecode_array->HasSourcePositionTable());
5095 5 : CHECK_GT(source_position_table->length(), 0);
5096 5 : }
5097 :
5098 26661 : TEST(InterpreterCollectSourcePositions_StackOverflow) {
5099 5 : FLAG_enable_lazy_source_positions = true;
5100 10 : HandleAndZoneScope handles;
5101 : Isolate* isolate = handles.main_isolate();
5102 :
5103 : const char* source =
5104 : "(function () {\n"
5105 : " return 1;\n"
5106 : "})";
5107 :
5108 : Handle<JSFunction> function = Handle<JSFunction>::cast(v8::Utils::OpenHandle(
5109 : *v8::Local<v8::Function>::Cast(CompileRun(source))));
5110 :
5111 : Handle<SharedFunctionInfo> sfi = handle(function->shared(), isolate);
5112 : Handle<BytecodeArray> bytecode_array =
5113 10 : handle(sfi->GetBytecodeArray(), isolate);
5114 5 : CHECK(!bytecode_array->HasSourcePositionTable());
5115 :
5116 : // Make the stack limit the same as the current position so recompilation
5117 : // overflows.
5118 : uint64_t previous_limit = isolate->stack_guard()->real_climit();
5119 10 : isolate->stack_guard()->SetStackLimit(GetCurrentStackPosition());
5120 5 : Compiler::CollectSourcePositions(isolate, sfi);
5121 : // Stack overflowed so source position table can be returned but is empty.
5122 5 : ByteArray source_position_table = bytecode_array->SourcePositionTable();
5123 5 : CHECK(!bytecode_array->HasSourcePositionTable());
5124 5 : CHECK_EQ(source_position_table->length(), 0);
5125 :
5126 : // Reset the stack limit and try again.
5127 5 : isolate->stack_guard()->SetStackLimit(previous_limit);
5128 5 : Compiler::CollectSourcePositions(isolate, sfi);
5129 5 : source_position_table = bytecode_array->SourcePositionTable();
5130 5 : CHECK(bytecode_array->HasSourcePositionTable());
5131 5 : CHECK_GT(source_position_table->length(), 0);
5132 5 : }
5133 :
5134 : // TODO(v8:8510): When an exception is thrown, the top frame still has its
5135 : // source positions collected. Re-enable this test when that is fixed.
5136 26656 : DISABLED_TEST(InterpreterCollectSourcePositions_ThrowFrom1stFrame) {
5137 0 : FLAG_enable_lazy_source_positions = true;
5138 0 : HandleAndZoneScope handles;
5139 : Isolate* isolate = handles.main_isolate();
5140 :
5141 : const char* source =
5142 : R"javascript(
5143 : (function () {
5144 : throw new Error();
5145 : });
5146 : )javascript";
5147 :
5148 : Handle<JSFunction> function = Handle<JSFunction>::cast(v8::Utils::OpenHandle(
5149 : *v8::Local<v8::Function>::Cast(CompileRun(source))));
5150 :
5151 : Handle<SharedFunctionInfo> sfi = handle(function->shared(), isolate);
5152 : // This is the bytecode for the top-level iife.
5153 : Handle<BytecodeArray> bytecode_array =
5154 0 : handle(sfi->GetBytecodeArray(), isolate);
5155 0 : CHECK(!bytecode_array->HasSourcePositionTable());
5156 :
5157 : {
5158 0 : v8::TryCatch try_catch(CcTest::isolate());
5159 : MaybeHandle<Object> result = Execution::Call(
5160 : isolate, function, ReadOnlyRoots(isolate).undefined_value_handle(), 0,
5161 0 : nullptr);
5162 0 : CHECK(result.is_null());
5163 0 : CHECK(try_catch.HasCaught());
5164 : }
5165 :
5166 : // The exception was caught but source positions were not retrieved from it so
5167 : // there should be no source position table.
5168 0 : CHECK(!bytecode_array->HasSourcePositionTable());
5169 0 : }
5170 :
5171 26661 : TEST(InterpreterCollectSourcePositions_ThrowFrom2ndFrame) {
5172 5 : FLAG_enable_lazy_source_positions = true;
5173 10 : HandleAndZoneScope handles;
5174 : Isolate* isolate = handles.main_isolate();
5175 :
5176 : const char* source =
5177 : R"javascript(
5178 : (function () {
5179 : (function () {
5180 : throw new Error();
5181 : })();
5182 : });
5183 : )javascript";
5184 :
5185 : Handle<JSFunction> function = Handle<JSFunction>::cast(v8::Utils::OpenHandle(
5186 : *v8::Local<v8::Function>::Cast(CompileRun(source))));
5187 :
5188 : Handle<SharedFunctionInfo> sfi = handle(function->shared(), isolate);
5189 : // This is the bytecode for the top-level iife.
5190 : Handle<BytecodeArray> bytecode_array =
5191 10 : handle(sfi->GetBytecodeArray(), isolate);
5192 5 : CHECK(!bytecode_array->HasSourcePositionTable());
5193 :
5194 : {
5195 10 : v8::TryCatch try_catch(CcTest::isolate());
5196 : MaybeHandle<Object> result = Execution::Call(
5197 : isolate, function, ReadOnlyRoots(isolate).undefined_value_handle(), 0,
5198 5 : nullptr);
5199 5 : CHECK(result.is_null());
5200 5 : CHECK(try_catch.HasCaught());
5201 : }
5202 :
5203 : // The exception was caught but source positions were not retrieved from it so
5204 : // there should be no source position table.
5205 5 : CHECK(!bytecode_array->HasSourcePositionTable());
5206 5 : }
5207 :
5208 : namespace {
5209 :
5210 5 : void CheckStringEqual(const char* expected_ptr, Handle<Object> actual_handle) {
5211 : v8::String::Utf8Value utf8(
5212 : v8::Isolate::GetCurrent(),
5213 10 : v8::Utils::ToLocal(Handle<String>::cast(actual_handle)));
5214 5 : std::string expected(expected_ptr);
5215 5 : std::string actual(*utf8);
5216 5 : CHECK_EQ(expected, actual);
5217 5 : }
5218 :
5219 : } // namespace
5220 :
5221 26661 : TEST(InterpreterCollectSourcePositions_GenerateStackTrace) {
5222 5 : FLAG_enable_lazy_source_positions = true;
5223 10 : HandleAndZoneScope handles;
5224 : Isolate* isolate = handles.main_isolate();
5225 :
5226 : const char* source =
5227 : R"javascript(
5228 : (function () {
5229 : try {
5230 : throw new Error();
5231 : } catch (e) {
5232 : return e.stack;
5233 : }
5234 : });
5235 : )javascript";
5236 :
5237 : Handle<JSFunction> function = Handle<JSFunction>::cast(v8::Utils::OpenHandle(
5238 : *v8::Local<v8::Function>::Cast(CompileRun(source))));
5239 :
5240 : Handle<SharedFunctionInfo> sfi = handle(function->shared(), isolate);
5241 : Handle<BytecodeArray> bytecode_array =
5242 10 : handle(sfi->GetBytecodeArray(), isolate);
5243 5 : CHECK(!bytecode_array->HasSourcePositionTable());
5244 :
5245 : {
5246 : Handle<Object> result =
5247 10 : Execution::Call(isolate, function,
5248 : ReadOnlyRoots(isolate).undefined_value_handle(), 0,
5249 5 : nullptr)
5250 5 : .ToHandleChecked();
5251 5 : CheckStringEqual("Error\n at <anonymous>:4:17", result);
5252 : }
5253 :
5254 5 : CHECK(bytecode_array->HasSourcePositionTable());
5255 5 : ByteArray source_position_table = bytecode_array->SourcePositionTable();
5256 5 : CHECK_GT(source_position_table->length(), 0);
5257 5 : }
5258 :
5259 : } // namespace interpreter
5260 : } // namespace internal
5261 79968 : } // namespace v8
|