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 25880 : TEST(InterpreterReturn) {
39 5 : HandleAndZoneScope handles;
40 5 : 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 10 : CHECK(return_val.is_identical_to(undefined_value));
52 5 : }
53 :
54 25880 : TEST(InterpreterLoadUndefined) {
55 5 : HandleAndZoneScope handles;
56 5 : 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 10 : CHECK(return_val.is_identical_to(undefined_value));
68 5 : }
69 :
70 25880 : TEST(InterpreterLoadNull) {
71 5 : HandleAndZoneScope handles;
72 5 : 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 10 : CHECK(return_val.is_identical_to(null_value));
84 5 : }
85 :
86 25880 : TEST(InterpreterLoadTheHole) {
87 5 : HandleAndZoneScope handles;
88 5 : 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 10 : CHECK(return_val.is_identical_to(the_hole_value));
100 5 : }
101 :
102 25880 : TEST(InterpreterLoadTrue) {
103 5 : HandleAndZoneScope handles;
104 5 : 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 10 : CHECK(return_val.is_identical_to(true_value));
116 5 : }
117 :
118 25880 : TEST(InterpreterLoadFalse) {
119 5 : HandleAndZoneScope handles;
120 5 : 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 10 : CHECK(return_val.is_identical_to(false_value));
132 5 : }
133 :
134 25880 : TEST(InterpreterLoadLiteral) {
135 5 : HandleAndZoneScope handles;
136 15 : Isolate* isolate = handles.main_isolate();
137 : Zone* zone = handles.main_zone();
138 :
139 : // Small Smis.
140 1285 : for (int i = -128; i < 128; i++) {
141 1280 : 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 3840 : CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(i));
149 1280 : }
150 :
151 : // Large Smis.
152 : {
153 5 : 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 20 : 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 10 : 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 10 : HashSeed(isolate));
186 :
187 10 : BytecodeArrayBuilder builder(zone, 1, 0);
188 :
189 10 : 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 5 : }
200 5 : }
201 :
202 25880 : TEST(InterpreterLoadStoreRegisters) {
203 5 : HandleAndZoneScope handles;
204 5 : Isolate* isolate = handles.main_isolate();
205 : Zone* zone = handles.main_zone();
206 : Handle<Object> true_value = isolate->factory()->true_value();
207 650 : for (int i = 0; i <= kMaxInt8; i++) {
208 640 : 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 645 : }
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 25880 : 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 30 : for (size_t l = 0; l < arraysize(lhs_inputs); l++) {
282 275 : for (size_t r = 0; r < arraysize(rhs_inputs); r++) {
283 825 : for (size_t o = 0; o < arraysize(kShiftOperators); o++) {
284 825 : HandleAndZoneScope handles;
285 825 : 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 825 : }
312 : }
313 : }
314 5 : }
315 :
316 25880 : 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 30 : for (size_t l = 0; l < arraysize(lhs_inputs); l++) {
320 200 : for (size_t r = 0; r < arraysize(rhs_inputs); r++) {
321 2200 : for (size_t o = 0; o < arraysize(kArithmeticOperators); o++) {
322 2200 : HandleAndZoneScope handles;
323 2200 : 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 2200 : }
350 : }
351 : }
352 5 : }
353 :
354 25880 : 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 35 : for (size_t l = 0; l < arraysize(lhs_inputs); l++) {
359 270 : for (size_t r = 0; r < arraysize(rhs_inputs); r++) {
360 2970 : for (size_t o = 0; o < arraysize(kArithmeticOperators); o++) {
361 2970 : HandleAndZoneScope handles;
362 2970 : 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 2970 : }
389 : }
390 : }
391 5 : }
392 :
393 25880 : TEST(InterpreterBinaryOpsBigInt) {
394 : // This test only checks that the recorded type feedback is kBigInt.
395 : AstBigInt inputs[] = {AstBigInt("1"), AstBigInt("-42"), AstBigInt("0xFFFF")};
396 20 : for (size_t l = 0; l < arraysize(inputs); l++) {
397 45 : for (size_t r = 0; r < arraysize(inputs); r++) {
398 495 : 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 450 : HandleAndZoneScope handles;
403 450 : 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 900 : CHECK(return_value->IsBigInt());
426 450 : if (tester.HasFeedbackMetadata()) {
427 900 : MaybeObject feedback = callable.vector()->Get(slot);
428 450 : CHECK(feedback->IsSmi());
429 900 : CHECK_EQ(BinaryOperationFeedback::kBigInt, feedback->ToSmi().value());
430 : }
431 450 : }
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 25880 : TEST(InterpreterStringAdd) {
486 5 : HandleAndZoneScope handles;
487 10 : 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 10 : 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 45 : 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 80 : MaybeObject feedback = callable.vector()->Get(slot);
550 40 : CHECK(feedback->IsSmi());
551 80 : CHECK_EQ(test_cases[i].expected_feedback, feedback->ToSmi().value());
552 : }
553 5 : }
554 5 : }
555 :
556 25880 : TEST(InterpreterParameter1) {
557 5 : HandleAndZoneScope handles;
558 5 : 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 : Handle<Object> return_val = callable(true_value).ToHandleChecked();
571 5 : CHECK(return_val.is_identical_to(true_value));
572 :
573 : // Check for Smis.
574 5 : return_val = callable(Handle<Smi>(Smi::FromInt(3), handles.main_isolate()))
575 : .ToHandleChecked();
576 20 : CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(3));
577 5 : }
578 :
579 25880 : TEST(InterpreterParameter8) {
580 5 : HandleAndZoneScope handles;
581 10 : Isolate* isolate = handles.main_isolate();
582 : Zone* zone = handles.main_zone();
583 : AstValueFactory ast_factory(zone, isolate->ast_string_constants(),
584 10 : 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 5 : Handle<Smi> arg1 = Handle<Smi>(Smi::FromInt(1), handles.main_isolate());
616 5 : Handle<Smi> arg2 = Handle<Smi>(Smi::FromInt(2), handles.main_isolate());
617 5 : Handle<Smi> arg3 = Handle<Smi>(Smi::FromInt(3), handles.main_isolate());
618 5 : Handle<Smi> arg4 = Handle<Smi>(Smi::FromInt(4), handles.main_isolate());
619 5 : Handle<Smi> arg5 = Handle<Smi>(Smi::FromInt(5), handles.main_isolate());
620 5 : Handle<Smi> arg6 = Handle<Smi>(Smi::FromInt(6), handles.main_isolate());
621 5 : Handle<Smi> arg7 = Handle<Smi>(Smi::FromInt(7), handles.main_isolate());
622 5 : 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 20 : CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(36));
628 5 : }
629 :
630 25880 : TEST(InterpreterBinaryOpTypeFeedback) {
631 5 : if (FLAG_lite_mode) return;
632 :
633 5 : HandleAndZoneScope handles;
634 10 : i::Isolate* isolate = handles.main_isolate();
635 : Zone* zone = handles.main_zone();
636 : AstValueFactory ast_factory(zone, isolate->ast_string_constants(),
637 10 : 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 135 : 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 260 : MaybeObject feedback0 = callable.vector()->Get(slot0);
758 130 : CHECK(feedback0->IsSmi());
759 260 : CHECK_EQ(test_case.feedback, feedback0->ToSmi().value());
760 260 : CHECK(Object::Equals(isolate, test_case.result, return_val).ToChecked());
761 5 : }
762 : }
763 :
764 25880 : TEST(InterpreterBinaryOpSmiTypeFeedback) {
765 5 : if (FLAG_lite_mode) return;
766 :
767 5 : HandleAndZoneScope handles;
768 10 : i::Isolate* isolate = handles.main_isolate();
769 : Zone* zone = handles.main_zone();
770 : AstValueFactory ast_factory(zone, isolate->ast_string_constants(),
771 10 : 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 105 : 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 200 : MaybeObject feedback0 = callable.vector()->Get(slot0);
866 100 : CHECK(feedback0->IsSmi());
867 200 : CHECK_EQ(test_case.feedback, feedback0->ToSmi().value());
868 200 : CHECK(Object::Equals(isolate, test_case.result, return_val).ToChecked());
869 5 : }
870 : }
871 :
872 25880 : TEST(InterpreterUnaryOpFeedback) {
873 5 : if (FLAG_lite_mode) return;
874 :
875 5 : HandleAndZoneScope handles;
876 5 : 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 20 : 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 15 : .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 30 : MaybeObject feedback0 = callable.vector()->Get(slot0);
939 15 : CHECK(feedback0->IsSmi());
940 30 : CHECK_EQ(BinaryOperationFeedback::kSignedSmall, feedback0->ToSmi().value());
941 :
942 30 : MaybeObject feedback1 = callable.vector()->Get(slot1);
943 15 : CHECK(feedback1->IsSmi());
944 30 : CHECK_EQ(BinaryOperationFeedback::kNumber, feedback1->ToSmi().value());
945 :
946 30 : MaybeObject feedback2 = callable.vector()->Get(slot2);
947 15 : CHECK(feedback2->IsSmi());
948 30 : CHECK_EQ(BinaryOperationFeedback::kNumber, feedback2->ToSmi().value());
949 :
950 30 : MaybeObject feedback3 = callable.vector()->Get(slot3);
951 15 : CHECK(feedback3->IsSmi());
952 30 : CHECK_EQ(BinaryOperationFeedback::kBigInt, feedback3->ToSmi().value());
953 :
954 30 : MaybeObject feedback4 = callable.vector()->Get(slot4);
955 15 : CHECK(feedback4->IsSmi());
956 30 : CHECK_EQ(BinaryOperationFeedback::kAny, feedback4->ToSmi().value());
957 5 : }
958 : }
959 :
960 25880 : TEST(InterpreterBitwiseTypeFeedback) {
961 5 : if (FLAG_lite_mode) return;
962 :
963 5 : HandleAndZoneScope handles;
964 5 : 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 35 : 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 60 : MaybeObject feedback0 = callable.vector()->Get(slot0);
1002 30 : CHECK(feedback0->IsSmi());
1003 60 : CHECK_EQ(BinaryOperationFeedback::kSignedSmall, feedback0->ToSmi().value());
1004 :
1005 60 : MaybeObject feedback1 = callable.vector()->Get(slot1);
1006 30 : CHECK(feedback1->IsSmi());
1007 60 : CHECK_EQ(BinaryOperationFeedback::kNumber, feedback1->ToSmi().value());
1008 :
1009 60 : MaybeObject feedback2 = callable.vector()->Get(slot2);
1010 30 : CHECK(feedback2->IsSmi());
1011 60 : CHECK_EQ(BinaryOperationFeedback::kAny, feedback2->ToSmi().value());
1012 5 : }
1013 : }
1014 :
1015 25880 : TEST(InterpreterParameter1Assign) {
1016 5 : HandleAndZoneScope handles;
1017 5 : 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 5 : callable(Handle<Smi>(Smi::FromInt(3), handles.main_isolate()))
1032 : .ToHandleChecked();
1033 20 : CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(5));
1034 5 : }
1035 :
1036 25880 : TEST(InterpreterLoadGlobal) {
1037 5 : HandleAndZoneScope handles;
1038 5 : 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 : "}");
1046 10 : InterpreterTester tester(isolate, source.c_str());
1047 : auto callable = tester.GetCallable<>();
1048 :
1049 : Handle<Object> return_val = callable().ToHandleChecked();
1050 20 : CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(321));
1051 5 : }
1052 :
1053 25880 : TEST(InterpreterStoreGlobal) {
1054 5 : HandleAndZoneScope handles;
1055 5 : 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 : "}");
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 10 : Object::GetProperty(isolate, isolate->global_object(), name)
1071 10 : .ToHandleChecked();
1072 20 : CHECK_EQ(Smi::cast(*global_obj), Smi::FromInt(999));
1073 5 : }
1074 :
1075 25880 : TEST(InterpreterCallGlobal) {
1076 5 : HandleAndZoneScope handles;
1077 5 : 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 : "}");
1085 10 : InterpreterTester tester(isolate, source.c_str());
1086 : auto callable = tester.GetCallable<>();
1087 :
1088 : Handle<Object> return_val = callable().ToHandleChecked();
1089 20 : CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(15));
1090 5 : }
1091 :
1092 25880 : TEST(InterpreterLoadUnallocated) {
1093 5 : HandleAndZoneScope handles;
1094 5 : 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 : "}");
1102 10 : InterpreterTester tester(isolate, source.c_str());
1103 : auto callable = tester.GetCallable<>();
1104 :
1105 : Handle<Object> return_val = callable().ToHandleChecked();
1106 20 : CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(123));
1107 5 : }
1108 :
1109 25880 : TEST(InterpreterStoreUnallocated) {
1110 5 : HandleAndZoneScope handles;
1111 5 : 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 : "}");
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 10 : Object::GetProperty(isolate, isolate->global_object(), name)
1127 10 : .ToHandleChecked();
1128 20 : CHECK_EQ(Smi::cast(*global_obj), Smi::FromInt(999));
1129 5 : }
1130 :
1131 25880 : TEST(InterpreterLoadNamedProperty) {
1132 5 : HandleAndZoneScope handles;
1133 10 : Isolate* isolate = handles.main_isolate();
1134 : Zone* zone = handles.main_zone();
1135 : AstValueFactory ast_factory(zone, isolate->ast_string_constants(),
1136 10 : 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 : Handle<Object> return_val = callable(object).ToHandleChecked();
1158 15 : CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(123));
1159 :
1160 : // Test transition to monomorphic IC.
1161 : return_val = callable(object).ToHandleChecked();
1162 15 : 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 : return_val = callable(object2).ToHandleChecked();
1168 15 : 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 : callable(object3).ToHandleChecked();
1174 : Handle<Object> object4 =
1175 5 : InterpreterTester::NewObject("({ val : 789, val3 : 123 })");
1176 : callable(object4).ToHandleChecked();
1177 : Handle<Object> object5 =
1178 5 : InterpreterTester::NewObject("({ val : 789, val4 : 123 })");
1179 : return_val = callable(object5).ToHandleChecked();
1180 20 : CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(789));
1181 5 : }
1182 :
1183 25880 : TEST(InterpreterLoadKeyedProperty) {
1184 5 : HandleAndZoneScope handles;
1185 10 : Isolate* isolate = handles.main_isolate();
1186 : Zone* zone = handles.main_zone();
1187 : AstValueFactory ast_factory(zone, isolate->ast_string_constants(),
1188 10 : 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 : Handle<Object> return_val = callable(object).ToHandleChecked();
1212 15 : CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(123));
1213 :
1214 : // Test transition to monomorphic IC.
1215 : return_val = callable(object).ToHandleChecked();
1216 15 : 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 : return_val = callable(object3).ToHandleChecked();
1222 20 : CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(789));
1223 5 : }
1224 :
1225 25880 : TEST(InterpreterStoreNamedProperty) {
1226 5 : HandleAndZoneScope handles;
1227 10 : Isolate* isolate = handles.main_isolate();
1228 : Zone* zone = handles.main_zone();
1229 : AstValueFactory ast_factory(zone, isolate->ast_string_constants(),
1230 10 : 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 25 : 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 : callable(object).ToHandleChecked();
1255 10 : CHECK(Runtime::GetObjectProperty(isolate, object, name->string())
1256 : .ToHandle(&result));
1257 15 : CHECK_EQ(Smi::cast(*result), Smi::FromInt(999));
1258 :
1259 : // Test transition to monomorphic IC.
1260 : callable(object).ToHandleChecked();
1261 10 : CHECK(Runtime::GetObjectProperty(isolate, object, name->string())
1262 : .ToHandle(&result));
1263 15 : 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 : callable(object2).ToHandleChecked();
1269 10 : CHECK(Runtime::GetObjectProperty(isolate, object2, name->string())
1270 : .ToHandle(&result));
1271 15 : 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 : callable(object3).ToHandleChecked();
1277 : Handle<Object> object4 =
1278 5 : InterpreterTester::NewObject("({ val : 789, val3 : 123 })");
1279 : callable(object4).ToHandleChecked();
1280 : Handle<Object> object5 =
1281 5 : InterpreterTester::NewObject("({ val : 789, val4 : 123 })");
1282 : callable(object5).ToHandleChecked();
1283 10 : CHECK(Runtime::GetObjectProperty(isolate, object5, name->string())
1284 : .ToHandle(&result));
1285 20 : CHECK_EQ(Smi::cast(*result), Smi::FromInt(999));
1286 5 : }
1287 :
1288 25880 : TEST(InterpreterStoreKeyedProperty) {
1289 5 : HandleAndZoneScope handles;
1290 10 : Isolate* isolate = handles.main_isolate();
1291 : Zone* zone = handles.main_zone();
1292 : AstValueFactory ast_factory(zone, isolate->ast_string_constants(),
1293 10 : 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 20 : 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 : callable(object).ToHandleChecked();
1320 10 : CHECK(Runtime::GetObjectProperty(isolate, object, name->string())
1321 : .ToHandle(&result));
1322 15 : CHECK_EQ(Smi::cast(*result), Smi::FromInt(999));
1323 :
1324 : // Test transition to monomorphic IC.
1325 : callable(object).ToHandleChecked();
1326 10 : CHECK(Runtime::GetObjectProperty(isolate, object, name->string())
1327 : .ToHandle(&result));
1328 15 : 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 : callable(object2).ToHandleChecked();
1334 10 : CHECK(Runtime::GetObjectProperty(isolate, object2, name->string())
1335 : .ToHandle(&result));
1336 20 : CHECK_EQ(Smi::cast(*result), Smi::FromInt(999));
1337 5 : }
1338 :
1339 25880 : TEST(InterpreterCall) {
1340 5 : HandleAndZoneScope handles;
1341 10 : 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 10 : 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 5 : 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 : Handle<Object> return_val = callable(object).ToHandleChecked();
1380 20 : CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(0x265));
1381 : }
1382 :
1383 : // Check that receiver is passed properly.
1384 : {
1385 5 : 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 : Handle<Object> return_val = callable(object).ToHandleChecked();
1405 20 : CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(1234));
1406 : }
1407 :
1408 : // Check with two parameters (+ receiver).
1409 : {
1410 5 : 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 : Handle<Object> return_val = callable(object).ToHandleChecked();
1438 15 : CHECK(return_val->SameValue(Smi::FromInt(40)));
1439 : }
1440 :
1441 : // Check with 10 parameters (+ receiver).
1442 : {
1443 5 : 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 : Handle<Object> return_val = callable(object).ToHandleChecked();
1490 : Handle<i::String> expected =
1491 5 : factory->NewStringFromAsciiChecked("prefix_abcdefghij");
1492 10 : CHECK(i::String::cast(*return_val)->Equals(*expected));
1493 5 : }
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 25880 : TEST(InterpreterJumps) {
1517 5 : HandleAndZoneScope handles;
1518 5 : 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 20 : BytecodeLabel label[3];
1532 :
1533 5 : builder.LoadLiteral(Smi::zero())
1534 5 : .StoreAccumulatorInRegister(reg)
1535 5 : .Jump(&label[1]);
1536 5 : SetRegister(builder, reg, 1024, scratch).Bind(&label[0]);
1537 5 : IncrementRegister(builder, reg, 1, scratch, GetIndex(slot)).Jump(&label[2]);
1538 5 : SetRegister(builder, reg, 2048, scratch).Bind(&label[1]);
1539 5 : IncrementRegister(builder, reg, 2, scratch, GetIndex(slot1))
1540 5 : .JumpLoop(&label[0], 0);
1541 5 : SetRegister(builder, reg, 4096, scratch).Bind(&label[2]);
1542 5 : IncrementRegister(builder, reg, 4, scratch, GetIndex(slot2))
1543 5 : .LoadAccumulatorWithRegister(reg)
1544 5 : .Return();
1545 :
1546 5 : Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(isolate);
1547 10 : InterpreterTester tester(isolate, bytecode_array, metadata);
1548 : auto callable = tester.GetCallable<>();
1549 : Handle<Object> return_value = callable().ToHandleChecked();
1550 10 : CHECK_EQ(Smi::ToInt(*return_value), 7);
1551 5 : }
1552 :
1553 25880 : TEST(InterpreterConditionalJumps) {
1554 5 : HandleAndZoneScope handles;
1555 5 : Isolate* isolate = handles.main_isolate();
1556 : Zone* zone = handles.main_zone();
1557 : FeedbackVectorSpec feedback_spec(zone);
1558 10 : BytecodeArrayBuilder builder(zone, 1, 2, &feedback_spec);
1559 :
1560 : FeedbackSlot slot = feedback_spec.AddBinaryOpICSlot();
1561 : FeedbackSlot slot1 = feedback_spec.AddBinaryOpICSlot();
1562 : FeedbackSlot slot2 = feedback_spec.AddBinaryOpICSlot();
1563 : FeedbackSlot slot3 = feedback_spec.AddBinaryOpICSlot();
1564 : FeedbackSlot slot4 = feedback_spec.AddBinaryOpICSlot();
1565 :
1566 : Handle<i::FeedbackMetadata> metadata =
1567 : NewFeedbackMetadata(isolate, &feedback_spec);
1568 :
1569 : Register reg(0), scratch(1);
1570 15 : BytecodeLabel label[2];
1571 : BytecodeLabel done, done1;
1572 :
1573 5 : builder.LoadLiteral(Smi::zero())
1574 5 : .StoreAccumulatorInRegister(reg)
1575 5 : .LoadFalse()
1576 5 : .JumpIfFalse(ToBooleanMode::kAlreadyBoolean, &label[0]);
1577 5 : IncrementRegister(builder, reg, 1024, scratch, GetIndex(slot))
1578 5 : .Bind(&label[0])
1579 5 : .LoadTrue()
1580 5 : .JumpIfFalse(ToBooleanMode::kAlreadyBoolean, &done);
1581 5 : IncrementRegister(builder, reg, 1, scratch, GetIndex(slot1))
1582 5 : .LoadTrue()
1583 5 : .JumpIfTrue(ToBooleanMode::kAlreadyBoolean, &label[1]);
1584 5 : IncrementRegister(builder, reg, 2048, scratch, GetIndex(slot2))
1585 5 : .Bind(&label[1]);
1586 5 : IncrementRegister(builder, reg, 2, scratch, GetIndex(slot3))
1587 5 : .LoadFalse()
1588 5 : .JumpIfTrue(ToBooleanMode::kAlreadyBoolean, &done1);
1589 5 : IncrementRegister(builder, reg, 4, scratch, GetIndex(slot4))
1590 5 : .LoadAccumulatorWithRegister(reg)
1591 5 : .Bind(&done)
1592 5 : .Bind(&done1)
1593 5 : .Return();
1594 :
1595 5 : Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(isolate);
1596 10 : InterpreterTester tester(isolate, bytecode_array, metadata);
1597 : auto callable = tester.GetCallable<>();
1598 : Handle<Object> return_value = callable().ToHandleChecked();
1599 10 : CHECK_EQ(Smi::ToInt(*return_value), 7);
1600 5 : }
1601 :
1602 25880 : TEST(InterpreterConditionalJumps2) {
1603 : // TODO(oth): Add tests for all conditional jumps near and far.
1604 5 : HandleAndZoneScope handles;
1605 5 : Isolate* isolate = handles.main_isolate();
1606 : Zone* zone = handles.main_zone();
1607 : FeedbackVectorSpec feedback_spec(zone);
1608 10 : BytecodeArrayBuilder builder(zone, 1, 2, &feedback_spec);
1609 :
1610 : FeedbackSlot slot = feedback_spec.AddBinaryOpICSlot();
1611 : FeedbackSlot slot1 = feedback_spec.AddBinaryOpICSlot();
1612 : FeedbackSlot slot2 = feedback_spec.AddBinaryOpICSlot();
1613 : FeedbackSlot slot3 = feedback_spec.AddBinaryOpICSlot();
1614 : FeedbackSlot slot4 = feedback_spec.AddBinaryOpICSlot();
1615 :
1616 : Handle<i::FeedbackMetadata> metadata =
1617 : NewFeedbackMetadata(isolate, &feedback_spec);
1618 :
1619 : Register reg(0), scratch(1);
1620 15 : BytecodeLabel label[2];
1621 : BytecodeLabel done, done1;
1622 :
1623 5 : builder.LoadLiteral(Smi::zero())
1624 5 : .StoreAccumulatorInRegister(reg)
1625 5 : .LoadFalse()
1626 5 : .JumpIfFalse(ToBooleanMode::kAlreadyBoolean, &label[0]);
1627 5 : IncrementRegister(builder, reg, 1024, scratch, GetIndex(slot))
1628 5 : .Bind(&label[0])
1629 5 : .LoadTrue()
1630 5 : .JumpIfFalse(ToBooleanMode::kAlreadyBoolean, &done);
1631 5 : IncrementRegister(builder, reg, 1, scratch, GetIndex(slot1))
1632 5 : .LoadTrue()
1633 5 : .JumpIfTrue(ToBooleanMode::kAlreadyBoolean, &label[1]);
1634 5 : IncrementRegister(builder, reg, 2048, scratch, GetIndex(slot2))
1635 5 : .Bind(&label[1]);
1636 5 : IncrementRegister(builder, reg, 2, scratch, GetIndex(slot3))
1637 5 : .LoadFalse()
1638 5 : .JumpIfTrue(ToBooleanMode::kAlreadyBoolean, &done1);
1639 5 : IncrementRegister(builder, reg, 4, scratch, GetIndex(slot4))
1640 5 : .LoadAccumulatorWithRegister(reg)
1641 5 : .Bind(&done)
1642 5 : .Bind(&done1)
1643 5 : .Return();
1644 :
1645 5 : Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(isolate);
1646 10 : InterpreterTester tester(isolate, bytecode_array, metadata);
1647 : auto callable = tester.GetCallable<>();
1648 : Handle<Object> return_value = callable().ToHandleChecked();
1649 10 : CHECK_EQ(Smi::ToInt(*return_value), 7);
1650 5 : }
1651 :
1652 25880 : TEST(InterpreterJumpConstantWith16BitOperand) {
1653 5 : HandleAndZoneScope handles;
1654 10 : Isolate* isolate = handles.main_isolate();
1655 : Zone* zone = handles.main_zone();
1656 : AstValueFactory ast_factory(zone, isolate->ast_string_constants(),
1657 10 : HashSeed(isolate));
1658 : FeedbackVectorSpec feedback_spec(zone);
1659 10 : BytecodeArrayBuilder builder(zone, 1, 257, &feedback_spec);
1660 :
1661 : FeedbackSlot slot = feedback_spec.AddBinaryOpICSlot();
1662 : Handle<i::FeedbackMetadata> metadata =
1663 : NewFeedbackMetadata(isolate, &feedback_spec);
1664 :
1665 : Register reg(0), scratch(256);
1666 : BytecodeLabel done, fake;
1667 :
1668 5 : builder.LoadLiteral(Smi::zero());
1669 5 : builder.StoreAccumulatorInRegister(reg);
1670 : // Consume all 8-bit operands
1671 1285 : for (int i = 1; i <= 256; i++) {
1672 1280 : builder.LoadLiteral(i + 0.5);
1673 1280 : builder.BinaryOperation(Token::Value::ADD, reg, GetIndex(slot));
1674 1280 : builder.StoreAccumulatorInRegister(reg);
1675 : }
1676 5 : builder.Jump(&done);
1677 :
1678 : // Emit more than 16-bit immediate operands worth of code to jump over.
1679 5 : builder.Bind(&fake);
1680 33005 : for (int i = 0; i < 6600; i++) {
1681 33000 : builder.LoadLiteral(Smi::zero()); // 1-byte
1682 : builder.BinaryOperation(Token::Value::ADD, scratch,
1683 33000 : GetIndex(slot)); // 6-bytes
1684 33000 : builder.StoreAccumulatorInRegister(scratch); // 4-bytes
1685 33000 : builder.MoveRegister(scratch, reg); // 6-bytes
1686 : }
1687 5 : builder.Bind(&done);
1688 5 : builder.LoadAccumulatorWithRegister(reg);
1689 5 : builder.Return();
1690 :
1691 5 : ast_factory.Internalize(isolate);
1692 5 : Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(isolate);
1693 5 : BytecodeArrayIterator iterator(bytecode_array);
1694 :
1695 : bool found_16bit_constant_jump = false;
1696 3860 : while (!iterator.done()) {
1697 3860 : if (iterator.current_bytecode() == Bytecode::kJumpConstant &&
1698 5 : iterator.current_operand_scale() == OperandScale::kDouble) {
1699 : found_16bit_constant_jump = true;
1700 : break;
1701 : }
1702 3850 : iterator.Advance();
1703 : }
1704 5 : CHECK(found_16bit_constant_jump);
1705 :
1706 10 : InterpreterTester tester(isolate, bytecode_array, metadata);
1707 : auto callable = tester.GetCallable<>();
1708 5 : Handle<Object> return_value = callable().ToHandleChecked();
1709 10 : CHECK_EQ(Handle<HeapNumber>::cast(return_value)->value(),
1710 5 : 256.0 / 2 * (1.5 + 256.5));
1711 5 : }
1712 :
1713 25880 : TEST(InterpreterJumpWith32BitOperand) {
1714 5 : HandleAndZoneScope handles;
1715 10 : Isolate* isolate = handles.main_isolate();
1716 : Zone* zone = handles.main_zone();
1717 : AstValueFactory ast_factory(zone, isolate->ast_string_constants(),
1718 10 : HashSeed(isolate));
1719 10 : BytecodeArrayBuilder builder(zone, 1, 1);
1720 : Register reg(0);
1721 : BytecodeLabel done;
1722 :
1723 5 : builder.LoadLiteral(Smi::zero());
1724 5 : builder.StoreAccumulatorInRegister(reg);
1725 : // Consume all 16-bit constant pool entries. Make sure to use doubles so that
1726 : // the jump can't re-use an integer.
1727 327685 : for (int i = 1; i <= 65536; i++) {
1728 327680 : builder.LoadLiteral(i + 0.5);
1729 : }
1730 5 : builder.Jump(&done);
1731 5 : builder.LoadLiteral(Smi::zero());
1732 5 : builder.Bind(&done);
1733 5 : builder.Return();
1734 :
1735 5 : ast_factory.Internalize(isolate);
1736 5 : Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(isolate);
1737 :
1738 5 : BytecodeArrayIterator iterator(bytecode_array);
1739 :
1740 : bool found_32bit_jump = false;
1741 25 : while (!iterator.done()) {
1742 25 : if (iterator.current_bytecode() == Bytecode::kJump &&
1743 5 : iterator.current_operand_scale() == OperandScale::kQuadruple) {
1744 : found_32bit_jump = true;
1745 : break;
1746 : }
1747 15 : iterator.Advance();
1748 : }
1749 5 : CHECK(found_32bit_jump);
1750 :
1751 10 : InterpreterTester tester(isolate, bytecode_array);
1752 : auto callable = tester.GetCallable<>();
1753 5 : Handle<Object> return_value = callable().ToHandleChecked();
1754 15 : CHECK_EQ(Handle<HeapNumber>::cast(return_value)->value(), 65536.5);
1755 5 : }
1756 :
1757 : static const Token::Value kComparisonTypes[] = {
1758 : Token::Value::EQ, Token::Value::EQ_STRICT, Token::Value::LT,
1759 : Token::Value::LTE, Token::Value::GT, Token::Value::GTE};
1760 :
1761 : template <typename T>
1762 10480 : bool CompareC(Token::Value op, T lhs, T rhs, bool types_differed = false) {
1763 10480 : switch (op) {
1764 : case Token::Value::EQ:
1765 1655 : return lhs == rhs;
1766 : case Token::Value::NE:
1767 0 : return lhs != rhs;
1768 : case Token::Value::EQ_STRICT:
1769 1655 : return (lhs == rhs) && !types_differed;
1770 : case Token::Value::NE_STRICT:
1771 550 : return (lhs != rhs) || types_differed;
1772 : case Token::Value::LT:
1773 1655 : return lhs < rhs;
1774 : case Token::Value::LTE:
1775 1655 : return lhs <= rhs;
1776 : case Token::Value::GT:
1777 1655 : return lhs > rhs;
1778 : case Token::Value::GTE:
1779 1655 : return lhs >= rhs;
1780 : default:
1781 0 : UNREACHABLE();
1782 : }
1783 : }
1784 :
1785 25880 : TEST(InterpreterSmiComparisons) {
1786 : // NB Constants cover 31-bit space.
1787 : int inputs[] = {v8::internal::kMinInt / 2,
1788 : v8::internal::kMinInt / 4,
1789 : -108733832,
1790 : -999,
1791 : -42,
1792 : -2,
1793 : -1,
1794 : 0,
1795 : +1,
1796 : +2,
1797 : 42,
1798 : 12345678,
1799 : v8::internal::kMaxInt / 4,
1800 5 : v8::internal::kMaxInt / 2};
1801 :
1802 35 : for (size_t c = 0; c < arraysize(kComparisonTypes); c++) {
1803 30 : Token::Value comparison = kComparisonTypes[c];
1804 450 : for (size_t i = 0; i < arraysize(inputs); i++) {
1805 5880 : for (size_t j = 0; j < arraysize(inputs); j++) {
1806 5880 : HandleAndZoneScope handles;
1807 5880 : Isolate* isolate = handles.main_isolate();
1808 : Zone* zone = handles.main_zone();
1809 : FeedbackVectorSpec feedback_spec(zone);
1810 11760 : BytecodeArrayBuilder builder(zone, 1, 1, &feedback_spec);
1811 :
1812 : FeedbackSlot slot = feedback_spec.AddCompareICSlot();
1813 : Handle<i::FeedbackMetadata> metadata =
1814 : NewFeedbackMetadata(isolate, &feedback_spec);
1815 :
1816 : Register r0(0);
1817 11760 : builder.LoadLiteral(Smi::FromInt(inputs[i]))
1818 5880 : .StoreAccumulatorInRegister(r0)
1819 11760 : .LoadLiteral(Smi::FromInt(inputs[j]))
1820 11760 : .CompareOperation(comparison, r0, GetIndex(slot))
1821 5880 : .Return();
1822 :
1823 5880 : Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(isolate);
1824 11760 : InterpreterTester tester(isolate, bytecode_array, metadata);
1825 : auto callable = tester.GetCallable<>();
1826 : Handle<Object> return_value = callable().ToHandleChecked();
1827 11760 : CHECK(return_value->IsBoolean());
1828 11760 : CHECK_EQ(return_value->BooleanValue(isolate),
1829 : CompareC(comparison, inputs[i], inputs[j]));
1830 5880 : if (tester.HasFeedbackMetadata()) {
1831 11760 : MaybeObject feedback = callable.vector()->Get(slot);
1832 5880 : CHECK(feedback->IsSmi());
1833 11760 : CHECK_EQ(CompareOperationFeedback::kSignedSmall,
1834 : feedback->ToSmi().value());
1835 : }
1836 5880 : }
1837 : }
1838 : }
1839 5 : }
1840 :
1841 25880 : TEST(InterpreterHeapNumberComparisons) {
1842 : double inputs[] = {std::numeric_limits<double>::min(),
1843 : std::numeric_limits<double>::max(),
1844 : -0.001,
1845 : 0.01,
1846 : 0.1000001,
1847 : 1e99,
1848 5 : -1e-99};
1849 35 : for (size_t c = 0; c < arraysize(kComparisonTypes); c++) {
1850 30 : Token::Value comparison = kComparisonTypes[c];
1851 240 : for (size_t i = 0; i < arraysize(inputs); i++) {
1852 1470 : for (size_t j = 0; j < arraysize(inputs); j++) {
1853 1470 : HandleAndZoneScope handles;
1854 2940 : Isolate* isolate = handles.main_isolate();
1855 : Zone* zone = handles.main_zone();
1856 : AstValueFactory ast_factory(zone, isolate->ast_string_constants(),
1857 2940 : HashSeed(isolate));
1858 :
1859 : FeedbackVectorSpec feedback_spec(zone);
1860 2940 : BytecodeArrayBuilder builder(zone, 1, 1, &feedback_spec);
1861 :
1862 : FeedbackSlot slot = feedback_spec.AddCompareICSlot();
1863 : Handle<i::FeedbackMetadata> metadata =
1864 : NewFeedbackMetadata(isolate, &feedback_spec);
1865 :
1866 : Register r0(0);
1867 1470 : builder.LoadLiteral(inputs[i])
1868 1470 : .StoreAccumulatorInRegister(r0)
1869 2940 : .LoadLiteral(inputs[j])
1870 2940 : .CompareOperation(comparison, r0, GetIndex(slot))
1871 1470 : .Return();
1872 :
1873 1470 : ast_factory.Internalize(isolate);
1874 1470 : Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(isolate);
1875 2940 : InterpreterTester tester(isolate, bytecode_array, metadata);
1876 : auto callable = tester.GetCallable<>();
1877 : Handle<Object> return_value = callable().ToHandleChecked();
1878 2940 : CHECK(return_value->IsBoolean());
1879 2940 : CHECK_EQ(return_value->BooleanValue(isolate),
1880 : CompareC(comparison, inputs[i], inputs[j]));
1881 1470 : if (tester.HasFeedbackMetadata()) {
1882 2940 : MaybeObject feedback = callable.vector()->Get(slot);
1883 1470 : CHECK(feedback->IsSmi());
1884 2940 : CHECK_EQ(CompareOperationFeedback::kNumber,
1885 : feedback->ToSmi().value());
1886 : }
1887 1470 : }
1888 : }
1889 : }
1890 5 : }
1891 :
1892 25880 : TEST(InterpreterBigIntComparisons) {
1893 : // This test only checks that the recorded type feedback is kBigInt.
1894 : AstBigInt inputs[] = {AstBigInt("0"), AstBigInt("-42"),
1895 : AstBigInt("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF")};
1896 35 : for (size_t c = 0; c < arraysize(kComparisonTypes); c++) {
1897 30 : Token::Value comparison = kComparisonTypes[c];
1898 120 : for (size_t i = 0; i < arraysize(inputs); i++) {
1899 270 : for (size_t j = 0; j < arraysize(inputs); j++) {
1900 270 : HandleAndZoneScope handles;
1901 540 : Isolate* isolate = handles.main_isolate();
1902 : Zone* zone = handles.main_zone();
1903 : AstValueFactory ast_factory(zone, isolate->ast_string_constants(),
1904 540 : HashSeed(isolate));
1905 :
1906 : FeedbackVectorSpec feedback_spec(zone);
1907 540 : BytecodeArrayBuilder builder(zone, 1, 1, &feedback_spec);
1908 :
1909 : FeedbackSlot slot = feedback_spec.AddCompareICSlot();
1910 : Handle<i::FeedbackMetadata> metadata =
1911 : NewFeedbackMetadata(isolate, &feedback_spec);
1912 :
1913 : Register r0(0);
1914 270 : builder.LoadLiteral(inputs[i])
1915 270 : .StoreAccumulatorInRegister(r0)
1916 270 : .LoadLiteral(inputs[j])
1917 540 : .CompareOperation(comparison, r0, GetIndex(slot))
1918 270 : .Return();
1919 :
1920 270 : ast_factory.Internalize(isolate);
1921 270 : Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(isolate);
1922 540 : InterpreterTester tester(isolate, bytecode_array, metadata);
1923 : auto callable = tester.GetCallable<>();
1924 : Handle<Object> return_value = callable().ToHandleChecked();
1925 540 : CHECK(return_value->IsBoolean());
1926 270 : if (tester.HasFeedbackMetadata()) {
1927 540 : MaybeObject feedback = callable.vector()->Get(slot);
1928 270 : CHECK(feedback->IsSmi());
1929 540 : CHECK_EQ(CompareOperationFeedback::kBigInt,
1930 : feedback->ToSmi().value());
1931 : }
1932 270 : }
1933 : }
1934 : }
1935 5 : }
1936 :
1937 25880 : TEST(InterpreterStringComparisons) {
1938 5 : HandleAndZoneScope handles;
1939 1085 : Isolate* isolate = handles.main_isolate();
1940 : Zone* zone = handles.main_zone();
1941 :
1942 40 : std::string inputs[] = {"A", "abc", "z", "", "Foo!", "Foo"};
1943 :
1944 35 : for (size_t c = 0; c < arraysize(kComparisonTypes); c++) {
1945 30 : Token::Value comparison = kComparisonTypes[c];
1946 210 : for (size_t i = 0; i < arraysize(inputs); i++) {
1947 1080 : for (size_t j = 0; j < arraysize(inputs); j++) {
1948 : AstValueFactory ast_factory(zone, isolate->ast_string_constants(),
1949 2160 : HashSeed(isolate));
1950 :
1951 2160 : CanonicalHandleScope canonical(isolate);
1952 1080 : const char* lhs = inputs[i].c_str();
1953 1080 : const char* rhs = inputs[j].c_str();
1954 :
1955 : FeedbackVectorSpec feedback_spec(zone);
1956 : FeedbackSlot slot = feedback_spec.AddCompareICSlot();
1957 : Handle<i::FeedbackMetadata> metadata =
1958 : NewFeedbackMetadata(isolate, &feedback_spec);
1959 :
1960 2160 : BytecodeArrayBuilder builder(zone, 1, 1, &feedback_spec);
1961 : Register r0(0);
1962 1080 : builder.LoadLiteral(ast_factory.GetOneByteString(lhs))
1963 1080 : .StoreAccumulatorInRegister(r0)
1964 2160 : .LoadLiteral(ast_factory.GetOneByteString(rhs))
1965 2160 : .CompareOperation(comparison, r0, GetIndex(slot))
1966 1080 : .Return();
1967 :
1968 1080 : ast_factory.Internalize(isolate);
1969 1080 : Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(isolate);
1970 2160 : InterpreterTester tester(isolate, bytecode_array, metadata);
1971 : auto callable = tester.GetCallable<>();
1972 : Handle<Object> return_value = callable().ToHandleChecked();
1973 2160 : CHECK(return_value->IsBoolean());
1974 4320 : CHECK_EQ(return_value->BooleanValue(isolate),
1975 : CompareC(comparison, inputs[i], inputs[j]));
1976 1080 : if (tester.HasFeedbackMetadata()) {
1977 2160 : MaybeObject feedback = callable.vector()->Get(slot);
1978 1080 : CHECK(feedback->IsSmi());
1979 : int const expected_feedback =
1980 : Token::IsOrderedRelationalCompareOp(comparison)
1981 : ? CompareOperationFeedback::kString
1982 1080 : : CompareOperationFeedback::kInternalizedString;
1983 2160 : CHECK_EQ(expected_feedback, feedback->ToSmi().value());
1984 : }
1985 : }
1986 : }
1987 5 : }
1988 5 : }
1989 :
1990 750 : static void LoadStringAndAddSpace(BytecodeArrayBuilder* builder,
1991 : AstValueFactory* ast_factory,
1992 : const char* cstr,
1993 : FeedbackSlot string_add_slot) {
1994 750 : Register string_reg = builder->register_allocator()->NewRegister();
1995 :
1996 : (*builder)
1997 750 : .LoadLiteral(ast_factory->GetOneByteString(cstr))
1998 750 : .StoreAccumulatorInRegister(string_reg)
1999 1500 : .LoadLiteral(ast_factory->GetOneByteString(" "))
2000 : .BinaryOperation(Token::Value::ADD, string_reg,
2001 750 : GetIndex(string_add_slot));
2002 750 : }
2003 :
2004 25880 : TEST(InterpreterMixedComparisons) {
2005 : // This test compares a HeapNumber with a String. The latter is
2006 : // convertible to a HeapNumber so comparison will be between numeric
2007 : // values except for the strict comparisons where no conversion is
2008 : // performed.
2009 5 : const char* inputs[] = {"-1.77", "-40.333", "0.01", "55.77e50", "2.01"};
2010 :
2011 : enum WhichSideString { kLhsIsString, kRhsIsString };
2012 :
2013 : enum StringType { kInternalizedStringConstant, kComputedString };
2014 :
2015 35 : for (size_t c = 0; c < arraysize(kComparisonTypes); c++) {
2016 30 : Token::Value comparison = kComparisonTypes[c];
2017 180 : for (size_t i = 0; i < arraysize(inputs); i++) {
2018 750 : for (size_t j = 0; j < arraysize(inputs); j++) {
2019 : // We test the case where either the lhs or the rhs is a string...
2020 3000 : for (WhichSideString which_side : {kLhsIsString, kRhsIsString}) {
2021 : // ... and the case when the string is internalized or computed.
2022 6000 : for (StringType string_type :
2023 2250 : {kInternalizedStringConstant, kComputedString}) {
2024 2250 : const char* lhs_cstr = inputs[i];
2025 2250 : const char* rhs_cstr = inputs[j];
2026 2250 : double lhs = StringToDouble(lhs_cstr, ConversionFlags::NO_FLAGS);
2027 2250 : double rhs = StringToDouble(rhs_cstr, ConversionFlags::NO_FLAGS);
2028 2250 : HandleAndZoneScope handles;
2029 4500 : Isolate* isolate = handles.main_isolate();
2030 : Zone* zone = handles.main_zone();
2031 : AstValueFactory ast_factory(zone, isolate->ast_string_constants(),
2032 4500 : HashSeed(isolate));
2033 : FeedbackVectorSpec feedback_spec(zone);
2034 3750 : BytecodeArrayBuilder builder(zone, 1, 0, &feedback_spec);
2035 :
2036 2250 : FeedbackSlot string_add_slot = feedback_spec.AddBinaryOpICSlot();
2037 : FeedbackSlot slot = feedback_spec.AddCompareICSlot();
2038 : Handle<i::FeedbackMetadata> metadata =
2039 : NewFeedbackMetadata(isolate, &feedback_spec);
2040 :
2041 : // lhs is in a register, rhs is in the accumulator.
2042 2250 : Register lhs_reg = builder.register_allocator()->NewRegister();
2043 :
2044 2250 : if (which_side == kRhsIsString) {
2045 : // Comparison with HeapNumber on the lhs and String on the rhs.
2046 :
2047 750 : builder.LoadLiteral(lhs).StoreAccumulatorInRegister(lhs_reg);
2048 :
2049 750 : if (string_type == kInternalizedStringConstant) {
2050 : // rhs string is internalized.
2051 750 : builder.LoadLiteral(ast_factory.GetOneByteString(rhs_cstr));
2052 : } else {
2053 0 : CHECK_EQ(string_type, kComputedString);
2054 : // rhs string is not internalized (append a space to the end).
2055 : LoadStringAndAddSpace(&builder, &ast_factory, rhs_cstr,
2056 0 : string_add_slot);
2057 : }
2058 750 : break;
2059 : } else {
2060 1500 : CHECK_EQ(which_side, kLhsIsString);
2061 : // Comparison with String on the lhs and HeapNumber on the rhs.
2062 :
2063 1500 : if (string_type == kInternalizedStringConstant) {
2064 : // lhs string is internalized
2065 750 : builder.LoadLiteral(ast_factory.GetOneByteString(lhs_cstr));
2066 : } else {
2067 750 : CHECK_EQ(string_type, kComputedString);
2068 : // lhs string is not internalized (append a space to the end).
2069 : LoadStringAndAddSpace(&builder, &ast_factory, lhs_cstr,
2070 750 : string_add_slot);
2071 : }
2072 1500 : builder.StoreAccumulatorInRegister(lhs_reg);
2073 :
2074 1500 : builder.LoadLiteral(rhs);
2075 : }
2076 :
2077 1500 : builder.CompareOperation(comparison, lhs_reg, GetIndex(slot))
2078 1500 : .Return();
2079 :
2080 1500 : ast_factory.Internalize(isolate);
2081 : Handle<BytecodeArray> bytecode_array =
2082 1500 : builder.ToBytecodeArray(isolate);
2083 3000 : InterpreterTester tester(isolate, bytecode_array, metadata);
2084 : auto callable = tester.GetCallable<>();
2085 : Handle<Object> return_value = callable().ToHandleChecked();
2086 3000 : CHECK(return_value->IsBoolean());
2087 3000 : CHECK_EQ(return_value->BooleanValue(isolate),
2088 : CompareC(comparison, lhs, rhs, true));
2089 1500 : if (tester.HasFeedbackMetadata()) {
2090 3000 : MaybeObject feedback = callable.vector()->Get(slot);
2091 1500 : CHECK(feedback->IsSmi());
2092 : // Comparison with a number and string collects kAny feedback.
2093 3000 : CHECK_EQ(CompareOperationFeedback::kAny,
2094 : feedback->ToSmi().value());
2095 : }
2096 1500 : }
2097 : }
2098 : }
2099 : }
2100 : }
2101 5 : }
2102 :
2103 25880 : TEST(InterpreterStrictNotEqual) {
2104 5 : HandleAndZoneScope handles;
2105 5 : Isolate* isolate = handles.main_isolate();
2106 : Factory* factory = isolate->factory();
2107 : const char* code_snippet =
2108 : "function f(lhs, rhs) {\n"
2109 : " return lhs !== rhs;\n"
2110 : "}\n"
2111 : "f(0, 0);\n";
2112 10 : InterpreterTester tester(isolate, code_snippet);
2113 : auto callable = tester.GetCallable<Handle<Object>, Handle<Object>>();
2114 :
2115 : // Test passing different types.
2116 5 : const char* inputs[] = {"-1.77", "-40.333", "0.01", "55.77e5", "2.01"};
2117 30 : for (size_t i = 0; i < arraysize(inputs); i++) {
2118 125 : for (size_t j = 0; j < arraysize(inputs); j++) {
2119 125 : double lhs = StringToDouble(inputs[i], ConversionFlags::NO_FLAGS);
2120 125 : double rhs = StringToDouble(inputs[j], ConversionFlags::NO_FLAGS);
2121 125 : Handle<Object> lhs_obj = factory->NewNumber(lhs);
2122 125 : Handle<Object> rhs_obj = factory->NewStringFromAsciiChecked(inputs[j]);
2123 :
2124 : Handle<Object> return_value =
2125 : callable(lhs_obj, rhs_obj).ToHandleChecked();
2126 250 : CHECK(return_value->IsBoolean());
2127 250 : CHECK_EQ(return_value->BooleanValue(isolate),
2128 : CompareC(Token::Value::NE_STRICT, lhs, rhs, true));
2129 : }
2130 : }
2131 :
2132 : // Test passing string types.
2133 5 : const char* inputs_str[] = {"A", "abc", "z", "", "Foo!", "Foo"};
2134 35 : for (size_t i = 0; i < arraysize(inputs_str); i++) {
2135 180 : for (size_t j = 0; j < arraysize(inputs_str); j++) {
2136 : Handle<Object> lhs_obj =
2137 180 : factory->NewStringFromAsciiChecked(inputs_str[i]);
2138 : Handle<Object> rhs_obj =
2139 180 : factory->NewStringFromAsciiChecked(inputs_str[j]);
2140 :
2141 : Handle<Object> return_value =
2142 : callable(lhs_obj, rhs_obj).ToHandleChecked();
2143 360 : CHECK(return_value->IsBoolean());
2144 360 : CHECK_EQ(return_value->BooleanValue(isolate),
2145 : CompareC(Token::Value::NE_STRICT, inputs_str[i], inputs_str[j]));
2146 : }
2147 : }
2148 :
2149 : // Test passing doubles.
2150 : double inputs_number[] = {std::numeric_limits<double>::min(),
2151 : std::numeric_limits<double>::max(),
2152 : -0.001,
2153 : 0.01,
2154 : 0.1000001,
2155 : 1e99,
2156 5 : -1e-99};
2157 40 : for (size_t i = 0; i < arraysize(inputs_number); i++) {
2158 245 : for (size_t j = 0; j < arraysize(inputs_number); j++) {
2159 245 : Handle<Object> lhs_obj = factory->NewNumber(inputs_number[i]);
2160 245 : Handle<Object> rhs_obj = factory->NewNumber(inputs_number[j]);
2161 :
2162 : Handle<Object> return_value =
2163 : callable(lhs_obj, rhs_obj).ToHandleChecked();
2164 490 : CHECK(return_value->IsBoolean());
2165 490 : CHECK_EQ(return_value->BooleanValue(isolate),
2166 : CompareC(Token::Value::NE_STRICT, inputs_number[i],
2167 : inputs_number[j]));
2168 : }
2169 5 : }
2170 5 : }
2171 :
2172 25880 : TEST(InterpreterCompareTypeOf) {
2173 : typedef TestTypeOfFlags::LiteralFlag LiteralFlag;
2174 5 : HandleAndZoneScope handles;
2175 5 : Isolate* isolate = handles.main_isolate();
2176 : Factory* factory = isolate->factory();
2177 : Zone* zone = handles.main_zone();
2178 : std::pair<Handle<Object>, LiteralFlag> inputs[] = {
2179 : {handle(Smi::FromInt(24), isolate), LiteralFlag::kNumber},
2180 : {factory->NewNumber(2.5), LiteralFlag::kNumber},
2181 : {factory->NewStringFromAsciiChecked("foo"), LiteralFlag::kString},
2182 : {factory
2183 : ->NewConsString(factory->NewStringFromAsciiChecked("foo"),
2184 5 : factory->NewStringFromAsciiChecked("bar"))
2185 10 : .ToHandleChecked(),
2186 : LiteralFlag::kString},
2187 : {factory->prototype_string(), LiteralFlag::kString},
2188 : {factory->NewSymbol(), LiteralFlag::kSymbol},
2189 : {factory->true_value(), LiteralFlag::kBoolean},
2190 : {factory->false_value(), LiteralFlag::kBoolean},
2191 : {factory->undefined_value(), LiteralFlag::kUndefined},
2192 : {InterpreterTester::NewObject(
2193 : "(function() { return function() {}; })();"),
2194 : LiteralFlag::kFunction},
2195 : {InterpreterTester::NewObject("new Object();"), LiteralFlag::kObject},
2196 : {factory->null_value(), LiteralFlag::kObject},
2197 40 : };
2198 : const LiteralFlag kLiterals[] = {
2199 : #define LITERAL_FLAG(name, _) LiteralFlag::k##name,
2200 : TYPEOF_LITERAL_LIST(LITERAL_FLAG)
2201 : #undef LITERAL_FLAG
2202 5 : };
2203 :
2204 50 : for (size_t l = 0; l < arraysize(kLiterals); l++) {
2205 45 : LiteralFlag literal_flag = kLiterals[l];
2206 50 : if (literal_flag == LiteralFlag::kOther) continue;
2207 :
2208 40 : BytecodeArrayBuilder builder(zone, 1, 0);
2209 40 : builder.LoadAccumulatorWithRegister(builder.Receiver())
2210 40 : .CompareTypeOf(kLiterals[l])
2211 40 : .Return();
2212 40 : Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(isolate);
2213 80 : InterpreterTester tester(isolate, bytecode_array);
2214 : auto callable = tester.GetCallable<Handle<Object>>();
2215 :
2216 520 : for (size_t i = 0; i < arraysize(inputs); i++) {
2217 : Handle<Object> return_value = callable(inputs[i].first).ToHandleChecked();
2218 960 : CHECK(return_value->IsBoolean());
2219 960 : CHECK_EQ(return_value->BooleanValue(isolate),
2220 : inputs[i].second == literal_flag);
2221 : }
2222 45 : }
2223 5 : }
2224 :
2225 25880 : TEST(InterpreterInstanceOf) {
2226 5 : HandleAndZoneScope handles;
2227 5 : Isolate* isolate = handles.main_isolate();
2228 : Zone* zone = handles.main_zone();
2229 : Factory* factory = isolate->factory();
2230 5 : Handle<i::String> name = factory->NewStringFromAsciiChecked("cons");
2231 5 : Handle<i::JSFunction> func = factory->NewFunctionForTest(name);
2232 5 : Handle<i::JSObject> instance = factory->NewJSObject(func);
2233 5 : Handle<i::Object> other = factory->NewNumber(3.3333);
2234 5 : Handle<i::Object> cases[] = {Handle<i::Object>::cast(instance), other};
2235 15 : for (size_t i = 0; i < arraysize(cases); i++) {
2236 10 : bool expected_value = (i == 0);
2237 : FeedbackVectorSpec feedback_spec(zone);
2238 20 : BytecodeArrayBuilder builder(zone, 1, 1, &feedback_spec);
2239 :
2240 : Register r0(0);
2241 10 : size_t case_entry = builder.AllocateDeferredConstantPoolEntry();
2242 10 : builder.SetDeferredConstantPoolEntry(case_entry, cases[i]);
2243 10 : builder.LoadConstantPoolEntry(case_entry).StoreAccumulatorInRegister(r0);
2244 :
2245 : FeedbackSlot slot = feedback_spec.AddInstanceOfSlot();
2246 : Handle<i::FeedbackMetadata> metadata =
2247 : NewFeedbackMetadata(isolate, &feedback_spec);
2248 :
2249 10 : size_t func_entry = builder.AllocateDeferredConstantPoolEntry();
2250 10 : builder.SetDeferredConstantPoolEntry(func_entry, func);
2251 10 : builder.LoadConstantPoolEntry(func_entry)
2252 10 : .CompareOperation(Token::Value::INSTANCEOF, r0, GetIndex(slot))
2253 10 : .Return();
2254 :
2255 10 : Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(isolate);
2256 20 : InterpreterTester tester(isolate, bytecode_array, metadata);
2257 : auto callable = tester.GetCallable<>();
2258 : Handle<Object> return_value = callable().ToHandleChecked();
2259 20 : CHECK(return_value->IsBoolean());
2260 10 : CHECK_EQ(return_value->BooleanValue(isolate), expected_value);
2261 5 : }
2262 5 : }
2263 :
2264 25880 : TEST(InterpreterTestIn) {
2265 5 : HandleAndZoneScope handles;
2266 10 : Isolate* isolate = handles.main_isolate();
2267 : Zone* zone = handles.main_zone();
2268 : Factory* factory = isolate->factory();
2269 : AstValueFactory ast_factory(zone, isolate->ast_string_constants(),
2270 10 : HashSeed(isolate));
2271 : // Allocate an array
2272 : Handle<i::JSArray> array =
2273 5 : factory->NewJSArray(0, i::ElementsKind::PACKED_SMI_ELEMENTS);
2274 : // Check for these properties on the array object
2275 5 : const char* properties[] = {"length", "fuzzle", "x", "0"};
2276 25 : for (size_t i = 0; i < arraysize(properties); i++) {
2277 20 : bool expected_value = (i == 0);
2278 20 : BytecodeArrayBuilder builder(zone, 1, 1);
2279 :
2280 : Register r0(0);
2281 20 : builder.LoadLiteral(ast_factory.GetOneByteString(properties[i]))
2282 20 : .StoreAccumulatorInRegister(r0);
2283 :
2284 20 : size_t array_entry = builder.AllocateDeferredConstantPoolEntry();
2285 20 : builder.SetDeferredConstantPoolEntry(array_entry, array);
2286 20 : builder.LoadConstantPoolEntry(array_entry)
2287 20 : .CompareOperation(Token::Value::IN, r0)
2288 20 : .Return();
2289 :
2290 20 : ast_factory.Internalize(isolate);
2291 20 : Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(isolate);
2292 40 : InterpreterTester tester(isolate, bytecode_array);
2293 : auto callable = tester.GetCallable<>();
2294 : Handle<Object> return_value = callable().ToHandleChecked();
2295 40 : CHECK(return_value->IsBoolean());
2296 20 : CHECK_EQ(return_value->BooleanValue(isolate), expected_value);
2297 25 : }
2298 5 : }
2299 :
2300 25880 : TEST(InterpreterUnaryNot) {
2301 5 : HandleAndZoneScope handles;
2302 5 : Isolate* isolate = handles.main_isolate();
2303 : Zone* zone = handles.main_zone();
2304 50 : for (size_t i = 1; i < 10; i++) {
2305 45 : bool expected_value = ((i & 1) == 1);
2306 45 : BytecodeArrayBuilder builder(zone, 1, 0);
2307 :
2308 : Register r0(0);
2309 45 : builder.LoadFalse();
2310 270 : for (size_t j = 0; j < i; j++) {
2311 225 : builder.LogicalNot(ToBooleanMode::kAlreadyBoolean);
2312 : }
2313 45 : builder.Return();
2314 45 : Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(isolate);
2315 90 : InterpreterTester tester(isolate, bytecode_array);
2316 : auto callable = tester.GetCallable<>();
2317 : Handle<Object> return_value = callable().ToHandleChecked();
2318 90 : CHECK(return_value->IsBoolean());
2319 45 : CHECK_EQ(return_value->BooleanValue(isolate), expected_value);
2320 50 : }
2321 5 : }
2322 :
2323 25880 : TEST(InterpreterUnaryNotNonBoolean) {
2324 5 : HandleAndZoneScope handles;
2325 10 : Isolate* isolate = handles.main_isolate();
2326 : Zone* zone = handles.main_zone();
2327 : AstValueFactory ast_factory(zone, isolate->ast_string_constants(),
2328 10 : HashSeed(isolate));
2329 :
2330 : std::pair<LiteralForTest, bool> object_type_tuples[] = {
2331 : std::make_pair(LiteralForTest(LiteralForTest::kUndefined), true),
2332 : std::make_pair(LiteralForTest(LiteralForTest::kNull), true),
2333 : std::make_pair(LiteralForTest(LiteralForTest::kFalse), true),
2334 : std::make_pair(LiteralForTest(LiteralForTest::kTrue), false),
2335 : std::make_pair(LiteralForTest(9.1), false),
2336 : std::make_pair(LiteralForTest(0), true),
2337 : std::make_pair(LiteralForTest(ast_factory.GetOneByteString("hello")),
2338 5 : false),
2339 5 : std::make_pair(LiteralForTest(ast_factory.GetOneByteString("")), true),
2340 : };
2341 :
2342 45 : for (size_t i = 0; i < arraysize(object_type_tuples); i++) {
2343 40 : BytecodeArrayBuilder builder(zone, 1, 0);
2344 :
2345 : Register r0(0);
2346 40 : LoadLiteralForTest(&builder, object_type_tuples[i].first);
2347 40 : builder.LogicalNot(ToBooleanMode::kConvertToBoolean).Return();
2348 40 : ast_factory.Internalize(isolate);
2349 40 : Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(isolate);
2350 80 : InterpreterTester tester(isolate, bytecode_array);
2351 : auto callable = tester.GetCallable<>();
2352 : Handle<Object> return_value = callable().ToHandleChecked();
2353 80 : CHECK(return_value->IsBoolean());
2354 80 : CHECK_EQ(return_value->BooleanValue(isolate), object_type_tuples[i].second);
2355 45 : }
2356 5 : }
2357 :
2358 25880 : TEST(InterpreterTypeof) {
2359 5 : HandleAndZoneScope handles;
2360 5 : Isolate* isolate = handles.main_isolate();
2361 :
2362 : std::pair<const char*, const char*> typeof_vals[] = {
2363 : std::make_pair("return typeof undefined;", "undefined"),
2364 : std::make_pair("return typeof null;", "object"),
2365 : std::make_pair("return typeof true;", "boolean"),
2366 : std::make_pair("return typeof false;", "boolean"),
2367 : std::make_pair("return typeof 9.1;", "number"),
2368 : std::make_pair("return typeof 7771;", "number"),
2369 : std::make_pair("return typeof 'hello';", "string"),
2370 : std::make_pair("return typeof global_unallocated;", "undefined"),
2371 5 : };
2372 :
2373 45 : for (size_t i = 0; i < arraysize(typeof_vals); i++) {
2374 40 : std::string source(InterpreterTester::SourceForBody(typeof_vals[i].first));
2375 80 : InterpreterTester tester(isolate, source.c_str());
2376 :
2377 : auto callable = tester.GetCallable<>();
2378 : Handle<v8::internal::String> return_value =
2379 40 : Handle<v8::internal::String>::cast(callable().ToHandleChecked());
2380 40 : auto actual = return_value->ToCString();
2381 80 : CHECK_EQ(strcmp(&actual[0], typeof_vals[i].second), 0);
2382 5 : }
2383 5 : }
2384 :
2385 25880 : TEST(InterpreterCallRuntime) {
2386 5 : HandleAndZoneScope handles;
2387 5 : Isolate* isolate = handles.main_isolate();
2388 : Zone* zone = handles.main_zone();
2389 :
2390 10 : BytecodeArrayBuilder builder(zone, 1, 2);
2391 5 : RegisterList args = builder.register_allocator()->NewRegisterList(2);
2392 :
2393 5 : builder.LoadLiteral(Smi::FromInt(15))
2394 5 : .StoreAccumulatorInRegister(args[0])
2395 5 : .LoadLiteral(Smi::FromInt(40))
2396 5 : .StoreAccumulatorInRegister(args[1])
2397 5 : .CallRuntime(Runtime::kAdd, args)
2398 5 : .Return();
2399 5 : Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(isolate);
2400 :
2401 10 : InterpreterTester tester(isolate, bytecode_array);
2402 : auto callable = tester.GetCallable<>();
2403 :
2404 : Handle<Object> return_val = callable().ToHandleChecked();
2405 20 : CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(55));
2406 5 : }
2407 :
2408 25880 : TEST(InterpreterInvokeIntrinsic) {
2409 5 : HandleAndZoneScope handles;
2410 5 : Isolate* isolate = handles.main_isolate();
2411 : Zone* zone = handles.main_zone();
2412 :
2413 10 : BytecodeArrayBuilder builder(zone, 1, 2);
2414 :
2415 5 : builder.LoadLiteral(Smi::FromInt(15))
2416 10 : .StoreAccumulatorInRegister(Register(0))
2417 10 : .CallRuntime(Runtime::kInlineIsArray, Register(0))
2418 5 : .Return();
2419 5 : Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(isolate);
2420 :
2421 10 : InterpreterTester tester(isolate, bytecode_array);
2422 : auto callable = tester.GetCallable<>();
2423 :
2424 : Handle<Object> return_val = callable().ToHandleChecked();
2425 10 : CHECK(return_val->IsBoolean());
2426 15 : CHECK_EQ(return_val->BooleanValue(isolate), false);
2427 5 : }
2428 :
2429 25880 : TEST(InterpreterFunctionLiteral) {
2430 5 : HandleAndZoneScope handles;
2431 5 : Isolate* isolate = handles.main_isolate();
2432 :
2433 : // Test calling a function literal.
2434 : std::string source(
2435 15 : "function " + InterpreterTester::function_name() + "(a) {\n"
2436 : " return (function(x){ return x + 2; })(a);\n"
2437 : "}");
2438 10 : InterpreterTester tester(isolate, source.c_str());
2439 : auto callable = tester.GetCallable<Handle<Object>>();
2440 :
2441 : Handle<i::Object> return_val = callable(
2442 5 : Handle<Smi>(Smi::FromInt(3), handles.main_isolate())).ToHandleChecked();
2443 20 : CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(5));
2444 5 : }
2445 :
2446 25880 : TEST(InterpreterRegExpLiterals) {
2447 5 : HandleAndZoneScope handles;
2448 5 : Isolate* isolate = handles.main_isolate();
2449 : Factory* factory = isolate->factory();
2450 :
2451 : std::pair<const char*, Handle<Object>> literals[] = {
2452 : std::make_pair("return /abd/.exec('cccabbdd');\n",
2453 : factory->null_value()),
2454 : std::make_pair("return /ab+d/.exec('cccabbdd')[0];\n",
2455 10 : factory->NewStringFromStaticChars("abbd")),
2456 : std::make_pair("return /AbC/i.exec('ssaBC')[0];\n",
2457 10 : factory->NewStringFromStaticChars("aBC")),
2458 : std::make_pair("return 'ssaBC'.match(/AbC/i)[0];\n",
2459 10 : factory->NewStringFromStaticChars("aBC")),
2460 : std::make_pair("return 'ssaBCtAbC'.match(/(AbC)/gi)[1];\n",
2461 10 : factory->NewStringFromStaticChars("AbC")),
2462 : };
2463 :
2464 30 : for (size_t i = 0; i < arraysize(literals); i++) {
2465 25 : std::string source(InterpreterTester::SourceForBody(literals[i].first));
2466 50 : InterpreterTester tester(isolate, source.c_str());
2467 : auto callable = tester.GetCallable<>();
2468 :
2469 : Handle<i::Object> return_value = callable().ToHandleChecked();
2470 50 : CHECK(return_value->SameValue(*literals[i].second));
2471 5 : }
2472 5 : }
2473 :
2474 25880 : TEST(InterpreterArrayLiterals) {
2475 5 : HandleAndZoneScope handles;
2476 5 : Isolate* isolate = handles.main_isolate();
2477 : Factory* factory = isolate->factory();
2478 :
2479 : std::pair<const char*, Handle<Object>> literals[] = {
2480 : std::make_pair("return [][0];\n",
2481 : factory->undefined_value()),
2482 : std::make_pair("return [1, 3, 2][1];\n",
2483 : handle(Smi::FromInt(3), isolate)),
2484 : std::make_pair("return ['a', 'b', 'c'][2];\n",
2485 10 : factory->NewStringFromStaticChars("c")),
2486 : std::make_pair("var a = 100; return [a, a + 1, a + 2, a + 3][2];\n",
2487 : handle(Smi::FromInt(102), isolate)),
2488 : std::make_pair("return [[1, 2, 3], ['a', 'b', 'c']][1][0];\n",
2489 10 : factory->NewStringFromStaticChars("a")),
2490 : std::make_pair("var t = 't'; return [[t, t + 'est'], [1 + t]][0][1];\n",
2491 10 : factory->NewStringFromStaticChars("test"))
2492 : };
2493 :
2494 35 : for (size_t i = 0; i < arraysize(literals); i++) {
2495 30 : std::string source(InterpreterTester::SourceForBody(literals[i].first));
2496 60 : InterpreterTester tester(isolate, source.c_str());
2497 : auto callable = tester.GetCallable<>();
2498 :
2499 : Handle<i::Object> return_value = callable().ToHandleChecked();
2500 60 : CHECK(return_value->SameValue(*literals[i].second));
2501 5 : }
2502 5 : }
2503 :
2504 25880 : TEST(InterpreterObjectLiterals) {
2505 5 : HandleAndZoneScope handles;
2506 5 : Isolate* isolate = handles.main_isolate();
2507 : Factory* factory = isolate->factory();
2508 :
2509 : std::pair<const char*, Handle<Object>> literals[] = {
2510 : std::make_pair("return { }.name;",
2511 : factory->undefined_value()),
2512 : std::make_pair("return { name: 'string', val: 9.2 }.name;",
2513 10 : factory->NewStringFromStaticChars("string")),
2514 : std::make_pair("var a = 15; return { name: 'string', val: a }.val;",
2515 : handle(Smi::FromInt(15), isolate)),
2516 : std::make_pair("var a = 5; return { val: a, val: a + 1 }.val;",
2517 : handle(Smi::FromInt(6), isolate)),
2518 : std::make_pair("return { func: function() { return 'test' } }.func();",
2519 10 : factory->NewStringFromStaticChars("test")),
2520 : std::make_pair("return { func(a) { return a + 'st'; } }.func('te');",
2521 10 : factory->NewStringFromStaticChars("test")),
2522 : std::make_pair("return { get a() { return 22; } }.a;",
2523 : handle(Smi::FromInt(22), isolate)),
2524 : std::make_pair("var a = { get b() { return this.x + 't'; },\n"
2525 : " set b(val) { this.x = val + 's' } };\n"
2526 : "a.b = 'te';\n"
2527 : "return a.b;",
2528 10 : factory->NewStringFromStaticChars("test")),
2529 : std::make_pair("var a = 123; return { 1: a }[1];",
2530 : handle(Smi::FromInt(123), isolate)),
2531 : std::make_pair("return Object.getPrototypeOf({ __proto__: null });",
2532 : factory->null_value()),
2533 : std::make_pair("var a = 'test'; return { [a]: 1 }.test;",
2534 : handle(Smi::FromInt(1), isolate)),
2535 : std::make_pair("var a = 'test'; return { b: a, [a]: a + 'ing' }['test']",
2536 10 : factory->NewStringFromStaticChars("testing")),
2537 : std::make_pair("var a = 'proto_str';\n"
2538 : "var b = { [a]: 1, __proto__: { var : a } };\n"
2539 : "return Object.getPrototypeOf(b).var",
2540 10 : factory->NewStringFromStaticChars("proto_str")),
2541 : std::make_pair("var n = 'name';\n"
2542 : "return { [n]: 'val', get a() { return 987 } }['a'];",
2543 : handle(Smi::FromInt(987), isolate)),
2544 : };
2545 :
2546 75 : for (size_t i = 0; i < arraysize(literals); i++) {
2547 70 : std::string source(InterpreterTester::SourceForBody(literals[i].first));
2548 140 : InterpreterTester tester(isolate, source.c_str());
2549 : auto callable = tester.GetCallable<>();
2550 :
2551 : Handle<i::Object> return_value = callable().ToHandleChecked();
2552 140 : CHECK(return_value->SameValue(*literals[i].second));
2553 5 : }
2554 5 : }
2555 :
2556 25880 : TEST(InterpreterConstruct) {
2557 5 : HandleAndZoneScope handles;
2558 5 : Isolate* isolate = handles.main_isolate();
2559 :
2560 : std::string source(
2561 : "function counter() { this.count = 0; }\n"
2562 15 : "function " +
2563 : InterpreterTester::function_name() +
2564 : "() {\n"
2565 : " var c = new counter();\n"
2566 : " return c.count;\n"
2567 : "}");
2568 10 : InterpreterTester tester(isolate, source.c_str());
2569 : auto callable = tester.GetCallable<>();
2570 :
2571 : Handle<Object> return_val = callable().ToHandleChecked();
2572 15 : CHECK_EQ(Smi::cast(*return_val), Smi::kZero);
2573 5 : }
2574 :
2575 25880 : TEST(InterpreterConstructWithArgument) {
2576 5 : HandleAndZoneScope handles;
2577 5 : Isolate* isolate = handles.main_isolate();
2578 :
2579 : std::string source(
2580 : "function counter(arg0) { this.count = 17; this.x = arg0; }\n"
2581 15 : "function " +
2582 : InterpreterTester::function_name() +
2583 : "() {\n"
2584 : " var c = new counter(3);\n"
2585 : " return c.x;\n"
2586 : "}");
2587 10 : InterpreterTester tester(isolate, source.c_str());
2588 : auto callable = tester.GetCallable<>();
2589 :
2590 : Handle<Object> return_val = callable().ToHandleChecked();
2591 20 : CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(3));
2592 5 : }
2593 :
2594 25880 : TEST(InterpreterConstructWithArguments) {
2595 5 : HandleAndZoneScope handles;
2596 5 : Isolate* isolate = handles.main_isolate();
2597 :
2598 : std::string source(
2599 : "function counter(arg0, arg1) {\n"
2600 : " this.count = 7; this.x = arg0; this.y = arg1;\n"
2601 : "}\n"
2602 15 : "function " +
2603 : InterpreterTester::function_name() +
2604 : "() {\n"
2605 : " var c = new counter(3, 5);\n"
2606 : " return c.count + c.x + c.y;\n"
2607 : "}");
2608 10 : InterpreterTester tester(isolate, source.c_str());
2609 : auto callable = tester.GetCallable<>();
2610 :
2611 : Handle<Object> return_val = callable().ToHandleChecked();
2612 20 : CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(15));
2613 5 : }
2614 :
2615 25880 : TEST(InterpreterContextVariables) {
2616 5 : HandleAndZoneScope handles;
2617 5 : Isolate* isolate = handles.main_isolate();
2618 :
2619 10 : std::ostringstream unique_vars;
2620 1255 : for (int i = 0; i < 250; i++) {
2621 1250 : unique_vars << "var a" << i << " = 0;";
2622 : }
2623 : std::pair<std::string, Handle<Object>> context_vars[] = {
2624 : std::make_pair("var a; (function() { a = 1; })(); return a;",
2625 : handle(Smi::FromInt(1), isolate)),
2626 : std::make_pair("var a = 10; (function() { a; })(); return a;",
2627 : handle(Smi::FromInt(10), isolate)),
2628 : std::make_pair("var a = 20; var b = 30;\n"
2629 : "return (function() { return a + b; })();",
2630 : handle(Smi::FromInt(50), isolate)),
2631 : std::make_pair("'use strict'; let a = 1;\n"
2632 : "{ let b = 2; return (function() { return a + b; })(); }",
2633 : handle(Smi::FromInt(3), isolate)),
2634 : std::make_pair("'use strict'; let a = 10;\n"
2635 : "{ let b = 20; var c = function() { [a, b] };\n"
2636 : " return a + b; }",
2637 : handle(Smi::FromInt(30), isolate)),
2638 10 : std::make_pair("'use strict';" + unique_vars.str() +
2639 : "eval(); var b = 100; return b;",
2640 : handle(Smi::FromInt(100), isolate)),
2641 35 : };
2642 :
2643 35 : for (size_t i = 0; i < arraysize(context_vars); i++) {
2644 : std::string source(
2645 60 : InterpreterTester::SourceForBody(context_vars[i].first.c_str()));
2646 60 : InterpreterTester tester(isolate, source.c_str());
2647 : auto callable = tester.GetCallable<>();
2648 :
2649 : Handle<i::Object> return_value = callable().ToHandleChecked();
2650 60 : CHECK(return_value->SameValue(*context_vars[i].second));
2651 5 : }
2652 5 : }
2653 :
2654 25880 : TEST(InterpreterContextParameters) {
2655 5 : HandleAndZoneScope handles;
2656 5 : Isolate* isolate = handles.main_isolate();
2657 :
2658 : std::pair<const char*, Handle<Object>> context_params[] = {
2659 : std::make_pair("return (function() { return arg1; })();",
2660 : handle(Smi::FromInt(1), isolate)),
2661 : std::make_pair("(function() { arg1 = 4; })(); return arg1;",
2662 : handle(Smi::FromInt(4), isolate)),
2663 : std::make_pair("(function() { arg3 = arg2 - arg1; })(); return arg3;",
2664 : handle(Smi::FromInt(1), isolate)),
2665 : };
2666 :
2667 20 : for (size_t i = 0; i < arraysize(context_params); i++) {
2668 60 : std::string source = "function " + InterpreterTester::function_name() +
2669 30 : "(arg1, arg2, arg3) {" + context_params[i].first + "}";
2670 30 : InterpreterTester tester(isolate, source.c_str());
2671 : auto callable =
2672 : tester.GetCallable<Handle<Object>, Handle<Object>, Handle<Object>>();
2673 :
2674 : Handle<Object> a1 = handle(Smi::FromInt(1), isolate);
2675 : Handle<Object> a2 = handle(Smi::FromInt(2), isolate);
2676 : Handle<Object> a3 = handle(Smi::FromInt(3), isolate);
2677 : Handle<i::Object> return_value = callable(a1, a2, a3).ToHandleChecked();
2678 30 : CHECK(return_value->SameValue(*context_params[i].second));
2679 5 : }
2680 5 : }
2681 :
2682 25880 : TEST(InterpreterOuterContextVariables) {
2683 5 : HandleAndZoneScope handles;
2684 5 : Isolate* isolate = handles.main_isolate();
2685 :
2686 : std::pair<const char*, Handle<Object>> context_vars[] = {
2687 : std::make_pair("return outerVar * innerArg;",
2688 : handle(Smi::FromInt(200), isolate)),
2689 : std::make_pair("outerVar = innerArg; return outerVar",
2690 : handle(Smi::FromInt(20), isolate)),
2691 : };
2692 :
2693 : std::string header(
2694 : "function Outer() {"
2695 : " var outerVar = 10;"
2696 : " function Inner(innerArg) {"
2697 5 : " this.innerFunc = function() { ");
2698 : std::string footer(
2699 : " }}"
2700 : " this.getInnerFunc = function() { return new Inner(20).innerFunc; }"
2701 : "}"
2702 5 : "var f = new Outer().getInnerFunc();");
2703 :
2704 15 : for (size_t i = 0; i < arraysize(context_vars); i++) {
2705 20 : std::string source = header + context_vars[i].first + footer;
2706 20 : InterpreterTester tester(isolate, source.c_str(), "*");
2707 : auto callable = tester.GetCallable<>();
2708 :
2709 : Handle<i::Object> return_value = callable().ToHandleChecked();
2710 20 : CHECK(return_value->SameValue(*context_vars[i].second));
2711 5 : }
2712 5 : }
2713 :
2714 25880 : TEST(InterpreterComma) {
2715 5 : HandleAndZoneScope handles;
2716 5 : Isolate* isolate = handles.main_isolate();
2717 : Factory* factory = isolate->factory();
2718 :
2719 : std::pair<const char*, Handle<Object>> literals[] = {
2720 : std::make_pair("var a; return 0, a;\n", factory->undefined_value()),
2721 : std::make_pair("return 'a', 2.2, 3;\n",
2722 : handle(Smi::FromInt(3), isolate)),
2723 : std::make_pair("return 'a', 'b', 'c';\n",
2724 10 : factory->NewStringFromStaticChars("c")),
2725 10 : std::make_pair("return 3.2, 2.3, 4.5;\n", factory->NewNumber(4.5)),
2726 : std::make_pair("var a = 10; return b = a, b = b+1;\n",
2727 : handle(Smi::FromInt(11), isolate)),
2728 : std::make_pair("var a = 10; return b = a, b = b+1, b + 10;\n",
2729 5 : handle(Smi::FromInt(21), isolate))};
2730 :
2731 35 : for (size_t i = 0; i < arraysize(literals); i++) {
2732 30 : std::string source(InterpreterTester::SourceForBody(literals[i].first));
2733 60 : InterpreterTester tester(isolate, source.c_str());
2734 : auto callable = tester.GetCallable<>();
2735 :
2736 : Handle<i::Object> return_value = callable().ToHandleChecked();
2737 60 : CHECK(return_value->SameValue(*literals[i].second));
2738 5 : }
2739 5 : }
2740 :
2741 25880 : TEST(InterpreterLogicalOr) {
2742 5 : HandleAndZoneScope handles;
2743 5 : Isolate* isolate = handles.main_isolate();
2744 : Factory* factory = isolate->factory();
2745 :
2746 : std::pair<const char*, Handle<Object>> literals[] = {
2747 : std::make_pair("var a, b; return a || b;\n", factory->undefined_value()),
2748 : std::make_pair("var a, b = 10; return a || b;\n",
2749 : handle(Smi::FromInt(10), isolate)),
2750 : std::make_pair("var a = '0', b = 10; return a || b;\n",
2751 10 : factory->NewStringFromStaticChars("0")),
2752 10 : std::make_pair("return 0 || 3.2;\n", factory->NewNumber(3.2)),
2753 : std::make_pair("return 'a' || 0;\n",
2754 10 : factory->NewStringFromStaticChars("a")),
2755 : std::make_pair("var a = '0', b = 10; return (a == 0) || b;\n",
2756 5 : factory->true_value())};
2757 :
2758 35 : for (size_t i = 0; i < arraysize(literals); i++) {
2759 30 : std::string source(InterpreterTester::SourceForBody(literals[i].first));
2760 60 : InterpreterTester tester(isolate, source.c_str());
2761 : auto callable = tester.GetCallable<>();
2762 :
2763 : Handle<i::Object> return_value = callable().ToHandleChecked();
2764 60 : CHECK(return_value->SameValue(*literals[i].second));
2765 5 : }
2766 5 : }
2767 :
2768 25880 : TEST(InterpreterLogicalAnd) {
2769 5 : HandleAndZoneScope handles;
2770 5 : Isolate* isolate = handles.main_isolate();
2771 : Factory* factory = isolate->factory();
2772 :
2773 : std::pair<const char*, Handle<Object>> literals[] = {
2774 : std::make_pair("var a, b = 10; return a && b;\n",
2775 : factory->undefined_value()),
2776 : std::make_pair("var a = 0, b = 10; return a && b / a;\n",
2777 : handle(Smi::kZero, isolate)),
2778 : std::make_pair("var a = '0', b = 10; return a && b;\n",
2779 : handle(Smi::FromInt(10), isolate)),
2780 : std::make_pair("return 0.0 && 3.2;\n", handle(Smi::kZero, isolate)),
2781 : std::make_pair("return 'a' && 'b';\n",
2782 10 : factory->NewStringFromStaticChars("b")),
2783 : std::make_pair("return 'a' && 0 || 'b', 'c';\n",
2784 10 : factory->NewStringFromStaticChars("c")),
2785 : std::make_pair("var x = 1, y = 3; return x && 0 + 1 || y;\n",
2786 : handle(Smi::FromInt(1), isolate)),
2787 : std::make_pair("var x = 1, y = 3; return (x == 1) && (3 == 3) || y;\n",
2788 10 : factory->true_value())};
2789 :
2790 45 : for (size_t i = 0; i < arraysize(literals); i++) {
2791 40 : std::string source(InterpreterTester::SourceForBody(literals[i].first));
2792 80 : InterpreterTester tester(isolate, source.c_str());
2793 : auto callable = tester.GetCallable<>();
2794 :
2795 : Handle<i::Object> return_value = callable().ToHandleChecked();
2796 80 : CHECK(return_value->SameValue(*literals[i].second));
2797 5 : }
2798 5 : }
2799 :
2800 25880 : TEST(InterpreterTryCatch) {
2801 5 : HandleAndZoneScope handles;
2802 5 : Isolate* isolate = handles.main_isolate();
2803 :
2804 : std::pair<const char*, Handle<Object>> catches[] = {
2805 : std::make_pair("var a = 1; try { a = 2 } catch(e) { a = 3 }; return a;",
2806 : handle(Smi::FromInt(2), isolate)),
2807 : std::make_pair("var a; try { undef.x } catch(e) { a = 2 }; return a;",
2808 : handle(Smi::FromInt(2), isolate)),
2809 : std::make_pair("var a; try { throw 1 } catch(e) { a = e + 2 }; return a;",
2810 : handle(Smi::FromInt(3), isolate)),
2811 : std::make_pair("var a; try { throw 1 } catch(e) { a = e + 2 };"
2812 : " try { throw a } catch(e) { a = e + 3 }; return a;",
2813 : handle(Smi::FromInt(6), isolate)),
2814 : };
2815 :
2816 25 : for (size_t i = 0; i < arraysize(catches); i++) {
2817 20 : std::string source(InterpreterTester::SourceForBody(catches[i].first));
2818 40 : InterpreterTester tester(isolate, source.c_str());
2819 : auto callable = tester.GetCallable<>();
2820 :
2821 : Handle<i::Object> return_value = callable().ToHandleChecked();
2822 40 : CHECK(return_value->SameValue(*catches[i].second));
2823 5 : }
2824 5 : }
2825 :
2826 25880 : TEST(InterpreterTryFinally) {
2827 5 : HandleAndZoneScope handles;
2828 5 : Isolate* isolate = handles.main_isolate();
2829 : Factory* factory = isolate->factory();
2830 :
2831 : std::pair<const char*, Handle<Object>> finallies[] = {
2832 : std::make_pair(
2833 : "var a = 1; try { a = a + 1; } finally { a = a + 2; }; return a;",
2834 10 : factory->NewStringFromStaticChars("R4")),
2835 : std::make_pair(
2836 : "var a = 1; try { a = 2; return 23; } finally { a = 3 }; return a;",
2837 10 : factory->NewStringFromStaticChars("R23")),
2838 : std::make_pair(
2839 : "var a = 1; try { a = 2; throw 23; } finally { a = 3 }; return a;",
2840 10 : factory->NewStringFromStaticChars("E23")),
2841 : std::make_pair(
2842 : "var a = 1; try { a = 2; throw 23; } finally { return a; };",
2843 10 : factory->NewStringFromStaticChars("R2")),
2844 : std::make_pair(
2845 : "var a = 1; try { a = 2; throw 23; } finally { throw 42; };",
2846 10 : factory->NewStringFromStaticChars("E42")),
2847 : std::make_pair("var a = 1; for (var i = 10; i < 20; i += 5) {"
2848 : " try { a = 2; break; } finally { a = 3; }"
2849 : "} return a + i;",
2850 10 : factory->NewStringFromStaticChars("R13")),
2851 : std::make_pair("var a = 1; for (var i = 10; i < 20; i += 5) {"
2852 : " try { a = 2; continue; } finally { a = 3; }"
2853 : "} return a + i;",
2854 10 : factory->NewStringFromStaticChars("R23")),
2855 : std::make_pair("var a = 1; try { a = 2;"
2856 : " try { a = 3; throw 23; } finally { a = 4; }"
2857 : "} catch(e) { a = a + e; } return a;",
2858 10 : factory->NewStringFromStaticChars("R27")),
2859 : std::make_pair("var func_name;"
2860 : "function tcf2(a) {"
2861 : " try { throw new Error('boom');} "
2862 : " catch(e) {return 153; } "
2863 : " finally {func_name = tcf2.name;}"
2864 : "}"
2865 : "tcf2();"
2866 : "return func_name;",
2867 10 : factory->NewStringFromStaticChars("Rtcf2")),
2868 : };
2869 :
2870 : const char* try_wrapper =
2871 : "(function() { try { return 'R' + f() } catch(e) { return 'E' + e }})()";
2872 :
2873 50 : for (size_t i = 0; i < arraysize(finallies); i++) {
2874 45 : std::string source(InterpreterTester::SourceForBody(finallies[i].first));
2875 90 : InterpreterTester tester(isolate, source.c_str());
2876 : tester.GetCallable<>();
2877 : Handle<Object> wrapped = v8::Utils::OpenHandle(*CompileRun(try_wrapper));
2878 90 : CHECK(wrapped->SameValue(*finallies[i].second));
2879 5 : }
2880 5 : }
2881 :
2882 25880 : TEST(InterpreterThrow) {
2883 5 : HandleAndZoneScope handles;
2884 5 : Isolate* isolate = handles.main_isolate();
2885 : Factory* factory = isolate->factory();
2886 :
2887 : std::pair<const char*, Handle<Object>> throws[] = {
2888 : std::make_pair("throw undefined;\n",
2889 : factory->undefined_value()),
2890 : std::make_pair("throw 1;\n",
2891 : handle(Smi::FromInt(1), isolate)),
2892 : std::make_pair("throw 'Error';\n",
2893 10 : factory->NewStringFromStaticChars("Error")),
2894 : std::make_pair("var a = true; if (a) { throw 'Error'; }\n",
2895 10 : factory->NewStringFromStaticChars("Error")),
2896 : std::make_pair("var a = false; if (a) { throw 'Error'; }\n",
2897 : factory->undefined_value()),
2898 : std::make_pair("throw 'Error1'; throw 'Error2'\n",
2899 10 : factory->NewStringFromStaticChars("Error1")),
2900 : };
2901 :
2902 : const char* try_wrapper =
2903 : "(function() { try { f(); } catch(e) { return e; }})()";
2904 :
2905 35 : for (size_t i = 0; i < arraysize(throws); i++) {
2906 30 : std::string source(InterpreterTester::SourceForBody(throws[i].first));
2907 60 : InterpreterTester tester(isolate, source.c_str());
2908 : tester.GetCallable<>();
2909 : Handle<Object> thrown_obj = v8::Utils::OpenHandle(*CompileRun(try_wrapper));
2910 60 : CHECK(thrown_obj->SameValue(*throws[i].second));
2911 5 : }
2912 5 : }
2913 :
2914 25880 : TEST(InterpreterCountOperators) {
2915 5 : HandleAndZoneScope handles;
2916 5 : Isolate* isolate = handles.main_isolate();
2917 : Factory* factory = isolate->factory();
2918 :
2919 : std::pair<const char*, Handle<Object>> count_ops[] = {
2920 : std::make_pair("var a = 1; return ++a;",
2921 : handle(Smi::FromInt(2), isolate)),
2922 : std::make_pair("var a = 1; return a++;",
2923 : handle(Smi::FromInt(1), isolate)),
2924 : std::make_pair("var a = 5; return --a;",
2925 : handle(Smi::FromInt(4), isolate)),
2926 : std::make_pair("var a = 5; return a--;",
2927 : handle(Smi::FromInt(5), isolate)),
2928 10 : std::make_pair("var a = 5.2; return --a;", factory->NewHeapNumber(4.2)),
2929 : std::make_pair("var a = 'string'; return ++a;", factory->nan_value()),
2930 : std::make_pair("var a = 'string'; return a--;", factory->nan_value()),
2931 : std::make_pair("var a = true; return ++a;",
2932 : handle(Smi::FromInt(2), isolate)),
2933 : std::make_pair("var a = false; return a--;", handle(Smi::kZero, isolate)),
2934 : std::make_pair("var a = { val: 11 }; return ++a.val;",
2935 : handle(Smi::FromInt(12), isolate)),
2936 : std::make_pair("var a = { val: 11 }; return a.val--;",
2937 : handle(Smi::FromInt(11), isolate)),
2938 : std::make_pair("var a = { val: 11 }; return ++a.val;",
2939 : handle(Smi::FromInt(12), isolate)),
2940 : std::make_pair("var name = 'val'; var a = { val: 22 }; return --a[name];",
2941 : handle(Smi::FromInt(21), isolate)),
2942 : std::make_pair("var name = 'val'; var a = { val: 22 }; return a[name]++;",
2943 : handle(Smi::FromInt(22), isolate)),
2944 : std::make_pair("var a = 1; (function() { a = 2 })(); return ++a;",
2945 : handle(Smi::FromInt(3), isolate)),
2946 : std::make_pair("var a = 1; (function() { a = 2 })(); return a--;",
2947 : handle(Smi::FromInt(2), isolate)),
2948 : std::make_pair("var i = 5; while(i--) {}; return i;",
2949 : handle(Smi::FromInt(-1), isolate)),
2950 : std::make_pair("var i = 1; if(i--) { return 1; } else { return 2; };",
2951 : handle(Smi::FromInt(1), isolate)),
2952 : std::make_pair("var i = -2; do {} while(i++) {}; return i;",
2953 : handle(Smi::FromInt(1), isolate)),
2954 : std::make_pair("var i = -1; for(; i++; ) {}; return i",
2955 : handle(Smi::FromInt(1), isolate)),
2956 : std::make_pair("var i = 20; switch(i++) {\n"
2957 : " case 20: return 1;\n"
2958 : " default: return 2;\n"
2959 : "}",
2960 : handle(Smi::FromInt(1), isolate)),
2961 5 : };
2962 :
2963 110 : for (size_t i = 0; i < arraysize(count_ops); i++) {
2964 105 : std::string source(InterpreterTester::SourceForBody(count_ops[i].first));
2965 210 : InterpreterTester tester(isolate, source.c_str());
2966 : auto callable = tester.GetCallable<>();
2967 :
2968 : Handle<i::Object> return_value = callable().ToHandleChecked();
2969 210 : CHECK(return_value->SameValue(*count_ops[i].second));
2970 5 : }
2971 5 : }
2972 :
2973 25880 : TEST(InterpreterGlobalCountOperators) {
2974 5 : HandleAndZoneScope handles;
2975 5 : Isolate* isolate = handles.main_isolate();
2976 :
2977 : std::pair<const char*, Handle<Object>> count_ops[] = {
2978 : std::make_pair("var global = 100;function f(){ return ++global; }",
2979 : handle(Smi::FromInt(101), isolate)),
2980 : std::make_pair("var global = 100; function f(){ return --global; }",
2981 : handle(Smi::FromInt(99), isolate)),
2982 : std::make_pair("var global = 100; function f(){ return global++; }",
2983 : handle(Smi::FromInt(100), isolate)),
2984 : std::make_pair("unallocated = 200; function f(){ return ++unallocated; }",
2985 : handle(Smi::FromInt(201), isolate)),
2986 : std::make_pair("unallocated = 200; function f(){ return --unallocated; }",
2987 : handle(Smi::FromInt(199), isolate)),
2988 : std::make_pair("unallocated = 200; function f(){ return unallocated++; }",
2989 : handle(Smi::FromInt(200), isolate)),
2990 : };
2991 :
2992 35 : for (size_t i = 0; i < arraysize(count_ops); i++) {
2993 30 : InterpreterTester tester(isolate, count_ops[i].first);
2994 : auto callable = tester.GetCallable<>();
2995 :
2996 : Handle<i::Object> return_value = callable().ToHandleChecked();
2997 60 : CHECK(return_value->SameValue(*count_ops[i].second));
2998 35 : }
2999 5 : }
3000 :
3001 25880 : TEST(InterpreterCompoundExpressions) {
3002 5 : HandleAndZoneScope handles;
3003 5 : Isolate* isolate = handles.main_isolate();
3004 : Factory* factory = isolate->factory();
3005 :
3006 : std::pair<const char*, Handle<Object>> compound_expr[] = {
3007 : std::make_pair("var a = 1; a += 2; return a;",
3008 : Handle<Object>(Smi::FromInt(3), isolate)),
3009 : std::make_pair("var a = 10; a /= 2; return a;",
3010 : Handle<Object>(Smi::FromInt(5), isolate)),
3011 : std::make_pair("var a = 'test'; a += 'ing'; return a;",
3012 10 : factory->NewStringFromStaticChars("testing")),
3013 : std::make_pair("var a = { val: 2 }; a.val *= 2; return a.val;",
3014 : Handle<Object>(Smi::FromInt(4), isolate)),
3015 : std::make_pair("var a = 1; (function f() { a = 2; })(); a += 24;"
3016 : "return a;",
3017 : Handle<Object>(Smi::FromInt(26), isolate)),
3018 20 : };
3019 :
3020 30 : for (size_t i = 0; i < arraysize(compound_expr); i++) {
3021 : std::string source(
3022 25 : InterpreterTester::SourceForBody(compound_expr[i].first));
3023 50 : InterpreterTester tester(isolate, source.c_str());
3024 : auto callable = tester.GetCallable<>();
3025 :
3026 : Handle<i::Object> return_value = callable().ToHandleChecked();
3027 50 : CHECK(return_value->SameValue(*compound_expr[i].second));
3028 5 : }
3029 5 : }
3030 :
3031 25880 : TEST(InterpreterGlobalCompoundExpressions) {
3032 5 : HandleAndZoneScope handles;
3033 5 : Isolate* isolate = handles.main_isolate();
3034 :
3035 : std::pair<const char*, Handle<Object>> compound_expr[2] = {
3036 : std::make_pair("var global = 100;"
3037 : "function f() { global += 20; return global; }",
3038 : Handle<Object>(Smi::FromInt(120), isolate)),
3039 : std::make_pair("unallocated = 100;"
3040 : "function f() { unallocated -= 20; return unallocated; }",
3041 : Handle<Object>(Smi::FromInt(80), isolate)),
3042 10 : };
3043 :
3044 15 : for (size_t i = 0; i < arraysize(compound_expr); i++) {
3045 10 : InterpreterTester tester(isolate, compound_expr[i].first);
3046 : auto callable = tester.GetCallable<>();
3047 :
3048 : Handle<i::Object> return_value = callable().ToHandleChecked();
3049 20 : CHECK(return_value->SameValue(*compound_expr[i].second));
3050 15 : }
3051 5 : }
3052 :
3053 25880 : TEST(InterpreterCreateArguments) {
3054 5 : HandleAndZoneScope handles;
3055 5 : Isolate* isolate = handles.main_isolate();
3056 : Factory* factory = isolate->factory();
3057 :
3058 : std::pair<const char*, int> create_args[] = {
3059 : std::make_pair("function f() { return arguments[0]; }", 0),
3060 : std::make_pair("function f(a) { return arguments[0]; }", 0),
3061 : std::make_pair("function f() { return arguments[2]; }", 2),
3062 : std::make_pair("function f(a) { return arguments[2]; }", 2),
3063 : std::make_pair("function f(a, b, c, d) { return arguments[2]; }", 2),
3064 : std::make_pair("function f(a) {"
3065 : "'use strict'; return arguments[0]; }",
3066 : 0),
3067 : std::make_pair("function f(a, b, c, d) {"
3068 : "'use strict'; return arguments[2]; }",
3069 : 2),
3070 : // Check arguments are mapped in sloppy mode and unmapped in strict.
3071 : std::make_pair("function f(a, b, c, d) {"
3072 : " c = b; return arguments[2]; }",
3073 : 1),
3074 : std::make_pair("function f(a, b, c, d) {"
3075 : " 'use strict'; c = b; return arguments[2]; }",
3076 : 2),
3077 : // Check arguments for duplicate parameters in sloppy mode.
3078 : std::make_pair("function f(a, a, b) { return arguments[1]; }", 1),
3079 : // check rest parameters
3080 : std::make_pair("function f(...restArray) { return restArray[0]; }", 0),
3081 : std::make_pair("function f(a, ...restArray) { return restArray[0]; }", 1),
3082 : std::make_pair("function f(a, ...restArray) { return arguments[0]; }", 0),
3083 : std::make_pair("function f(a, ...restArray) { return arguments[1]; }", 1),
3084 : std::make_pair("function f(a, ...restArray) { return restArray[1]; }", 2),
3085 : std::make_pair("function f(a, ...arguments) { return arguments[0]; }", 1),
3086 : std::make_pair("function f(a, b, ...restArray) { return restArray[0]; }",
3087 : 2),
3088 5 : };
3089 :
3090 : // Test passing no arguments.
3091 90 : for (size_t i = 0; i < arraysize(create_args); i++) {
3092 85 : InterpreterTester tester(isolate, create_args[i].first);
3093 : auto callable = tester.GetCallable<>();
3094 : Handle<Object> return_val = callable().ToHandleChecked();
3095 85 : CHECK(return_val.is_identical_to(factory->undefined_value()));
3096 85 : }
3097 :
3098 : // Test passing one argument.
3099 85 : for (size_t i = 0; i < arraysize(create_args); i++) {
3100 85 : InterpreterTester tester(isolate, create_args[i].first);
3101 : auto callable = tester.GetCallable<Handle<Object>>();
3102 : Handle<Object> return_val =
3103 : callable(handle(Smi::FromInt(40), isolate)).ToHandleChecked();
3104 85 : if (create_args[i].second == 0) {
3105 75 : CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(40));
3106 : } else {
3107 60 : CHECK(return_val.is_identical_to(factory->undefined_value()));
3108 : }
3109 85 : }
3110 :
3111 : // Test passing three argument.
3112 85 : for (size_t i = 0; i < arraysize(create_args); i++) {
3113 : Handle<Object> args[3] = {
3114 : handle(Smi::FromInt(40), isolate),
3115 : handle(Smi::FromInt(60), isolate),
3116 : handle(Smi::FromInt(80), isolate),
3117 : };
3118 :
3119 85 : InterpreterTester tester(isolate, create_args[i].first);
3120 : auto callable =
3121 : tester.GetCallable<Handle<Object>, Handle<Object>, Handle<Object>>();
3122 : Handle<Object> return_val =
3123 : callable(args[0], args[1], args[2]).ToHandleChecked();
3124 170 : CHECK(return_val->SameValue(*args[create_args[i].second]));
3125 90 : }
3126 5 : }
3127 :
3128 25880 : TEST(InterpreterConditional) {
3129 5 : HandleAndZoneScope handles;
3130 5 : Isolate* isolate = handles.main_isolate();
3131 :
3132 : std::pair<const char*, Handle<Object>> conditional[] = {
3133 : std::make_pair("return true ? 2 : 3;",
3134 : handle(Smi::FromInt(2), isolate)),
3135 : std::make_pair("return false ? 2 : 3;",
3136 : handle(Smi::FromInt(3), isolate)),
3137 : std::make_pair("var a = 1; return a ? 20 : 30;",
3138 : handle(Smi::FromInt(20), isolate)),
3139 : std::make_pair("var a = 1; return a ? 20 : 30;",
3140 : handle(Smi::FromInt(20), isolate)),
3141 : std::make_pair("var a = 'string'; return a ? 20 : 30;",
3142 : handle(Smi::FromInt(20), isolate)),
3143 : std::make_pair("var a = undefined; return a ? 20 : 30;",
3144 : handle(Smi::FromInt(30), isolate)),
3145 : std::make_pair("return 1 ? 2 ? 3 : 4 : 5;",
3146 : handle(Smi::FromInt(3), isolate)),
3147 : std::make_pair("return 0 ? 2 ? 3 : 4 : 5;",
3148 : handle(Smi::FromInt(5), isolate)),
3149 : };
3150 :
3151 45 : for (size_t i = 0; i < arraysize(conditional); i++) {
3152 40 : std::string source(InterpreterTester::SourceForBody(conditional[i].first));
3153 80 : InterpreterTester tester(isolate, source.c_str());
3154 : auto callable = tester.GetCallable<>();
3155 :
3156 : Handle<i::Object> return_value = callable().ToHandleChecked();
3157 80 : CHECK(return_value->SameValue(*conditional[i].second));
3158 5 : }
3159 5 : }
3160 :
3161 25880 : TEST(InterpreterDelete) {
3162 5 : HandleAndZoneScope handles;
3163 5 : Isolate* isolate = handles.main_isolate();
3164 : Factory* factory = isolate->factory();
3165 :
3166 : // Tests for delete for local variables that work both in strict
3167 : // and sloppy modes
3168 : std::pair<const char*, Handle<Object>> test_delete[] = {
3169 : std::make_pair(
3170 : "var a = { x:10, y:'abc', z:30.2}; delete a.x; return a.x;\n",
3171 : factory->undefined_value()),
3172 : std::make_pair(
3173 : "var b = { x:10, y:'abc', z:30.2}; delete b.x; return b.y;\n",
3174 10 : factory->NewStringFromStaticChars("abc")),
3175 : std::make_pair("var c = { x:10, y:'abc', z:30.2}; var d = c; delete d.x; "
3176 : "return c.x;\n",
3177 : factory->undefined_value()),
3178 : std::make_pair("var e = { x:10, y:'abc', z:30.2}; var g = e; delete g.x; "
3179 : "return e.y;\n",
3180 10 : factory->NewStringFromStaticChars("abc")),
3181 : std::make_pair("var a = { x:10, y:'abc', z:30.2};\n"
3182 : "var b = a;"
3183 : "delete b.x;"
3184 : "return b.x;\n",
3185 : factory->undefined_value()),
3186 : std::make_pair("var a = {1:10};\n"
3187 : "(function f1() {return a;});"
3188 : "return delete a[1];",
3189 10 : factory->ToBoolean(true)),
3190 10 : std::make_pair("return delete this;", factory->ToBoolean(true)),
3191 20 : std::make_pair("return delete 'test';", factory->ToBoolean(true))};
3192 :
3193 : // Test delete in sloppy mode
3194 45 : for (size_t i = 0; i < arraysize(test_delete); i++) {
3195 40 : std::string source(InterpreterTester::SourceForBody(test_delete[i].first));
3196 80 : InterpreterTester tester(isolate, source.c_str());
3197 : auto callable = tester.GetCallable<>();
3198 :
3199 : Handle<i::Object> return_value = callable().ToHandleChecked();
3200 80 : CHECK(return_value->SameValue(*test_delete[i].second));
3201 : }
3202 :
3203 : // Test delete in strict mode
3204 40 : for (size_t i = 0; i < arraysize(test_delete); i++) {
3205 : std::string strict_test =
3206 80 : "'use strict'; " + std::string(test_delete[i].first);
3207 40 : std::string source(InterpreterTester::SourceForBody(strict_test.c_str()));
3208 80 : InterpreterTester tester(isolate, source.c_str());
3209 : auto callable = tester.GetCallable<>();
3210 :
3211 : Handle<i::Object> return_value = callable().ToHandleChecked();
3212 80 : CHECK(return_value->SameValue(*test_delete[i].second));
3213 5 : }
3214 5 : }
3215 :
3216 25880 : TEST(InterpreterDeleteSloppyUnqualifiedIdentifier) {
3217 5 : HandleAndZoneScope handles;
3218 5 : Isolate* isolate = handles.main_isolate();
3219 : Factory* factory = isolate->factory();
3220 :
3221 : // These tests generate a syntax error for strict mode. We don't
3222 : // test for it here.
3223 : std::pair<const char*, Handle<Object>> test_delete[] = {
3224 : std::make_pair("var sloppy_a = { x:10, y:'abc'};\n"
3225 : "var sloppy_b = delete sloppy_a;\n"
3226 : "if (delete sloppy_a) {\n"
3227 : " return undefined;\n"
3228 : "} else {\n"
3229 : " return sloppy_a.x;\n"
3230 : "}\n",
3231 : Handle<Object>(Smi::FromInt(10), isolate)),
3232 : // TODO(mythria) When try-catch is implemented change the tests to check
3233 : // if delete actually deletes
3234 : std::make_pair("sloppy_a = { x:10, y:'abc'};\n"
3235 : "var sloppy_b = delete sloppy_a;\n"
3236 : // "try{return a.x;} catch(e) {return b;}\n"
3237 : "return sloppy_b;",
3238 10 : factory->ToBoolean(true)),
3239 : std::make_pair("sloppy_a = { x:10, y:'abc'};\n"
3240 : "var sloppy_b = delete sloppy_c;\n"
3241 : "return sloppy_b;",
3242 20 : factory->ToBoolean(true))};
3243 :
3244 20 : for (size_t i = 0; i < arraysize(test_delete); i++) {
3245 15 : std::string source(InterpreterTester::SourceForBody(test_delete[i].first));
3246 30 : InterpreterTester tester(isolate, source.c_str());
3247 : auto callable = tester.GetCallable<>();
3248 :
3249 : Handle<i::Object> return_value = callable().ToHandleChecked();
3250 30 : CHECK(return_value->SameValue(*test_delete[i].second));
3251 5 : }
3252 5 : }
3253 :
3254 25880 : TEST(InterpreterGlobalDelete) {
3255 5 : HandleAndZoneScope handles;
3256 5 : Isolate* isolate = handles.main_isolate();
3257 : Factory* factory = isolate->factory();
3258 :
3259 : std::pair<const char*, Handle<Object>> test_global_delete[] = {
3260 : std::make_pair("var a = { x:10, y:'abc', z:30.2 };\n"
3261 : "function f() {\n"
3262 : " delete a.x;\n"
3263 : " return a.x;\n"
3264 : "}\n"
3265 : "f();\n",
3266 : factory->undefined_value()),
3267 : std::make_pair("var b = {1:10, 2:'abc', 3:30.2 };\n"
3268 : "function f() {\n"
3269 : " delete b[2];\n"
3270 : " return b[1];\n"
3271 : " }\n"
3272 : "f();\n",
3273 : Handle<Object>(Smi::FromInt(10), isolate)),
3274 : std::make_pair("var c = { x:10, y:'abc', z:30.2 };\n"
3275 : "function f() {\n"
3276 : " var d = c;\n"
3277 : " delete d.y;\n"
3278 : " return d.x;\n"
3279 : "}\n"
3280 : "f();\n",
3281 : Handle<Object>(Smi::FromInt(10), isolate)),
3282 : std::make_pair("e = { x:10, y:'abc' };\n"
3283 : "function f() {\n"
3284 : " return delete e;\n"
3285 : "}\n"
3286 : "f();\n",
3287 10 : factory->ToBoolean(true)),
3288 : std::make_pair("var g = { x:10, y:'abc' };\n"
3289 : "function f() {\n"
3290 : " return delete g;\n"
3291 : "}\n"
3292 : "f();\n",
3293 10 : factory->ToBoolean(false)),
3294 : std::make_pair("function f() {\n"
3295 : " var obj = {h:10, f1() {return delete this;}};\n"
3296 : " return obj.f1();\n"
3297 : "}\n"
3298 : "f();",
3299 10 : factory->ToBoolean(true)),
3300 : std::make_pair("function f() {\n"
3301 : " var obj = {h:10,\n"
3302 : " f1() {\n"
3303 : " 'use strict';\n"
3304 : " return delete this.h;}};\n"
3305 : " return obj.f1();\n"
3306 : "}\n"
3307 : "f();",
3308 35 : factory->ToBoolean(true))};
3309 :
3310 40 : for (size_t i = 0; i < arraysize(test_global_delete); i++) {
3311 35 : InterpreterTester tester(isolate, test_global_delete[i].first);
3312 : auto callable = tester.GetCallable<>();
3313 :
3314 : Handle<i::Object> return_value = callable().ToHandleChecked();
3315 70 : CHECK(return_value->SameValue(*test_global_delete[i].second));
3316 40 : }
3317 5 : }
3318 :
3319 25880 : TEST(InterpreterBasicLoops) {
3320 5 : HandleAndZoneScope handles;
3321 5 : Isolate* isolate = handles.main_isolate();
3322 : Factory* factory = isolate->factory();
3323 :
3324 : std::pair<const char*, Handle<Object>> loops[] = {
3325 : std::make_pair("var a = 10; var b = 1;\n"
3326 : "while (a) {\n"
3327 : " b = b * 2;\n"
3328 : " a = a - 1;\n"
3329 : "};\n"
3330 : "return b;\n",
3331 10 : factory->NewHeapNumber(1024)),
3332 : std::make_pair("var a = 1; var b = 1;\n"
3333 : "do {\n"
3334 : " b = b * 2;\n"
3335 : " --a;\n"
3336 : "} while(a);\n"
3337 : "return b;\n",
3338 : handle(Smi::FromInt(2), isolate)),
3339 : std::make_pair("var b = 1;\n"
3340 : "for ( var a = 10; a; a--) {\n"
3341 : " b *= 2;\n"
3342 : "}\n"
3343 : "return b;",
3344 10 : factory->NewHeapNumber(1024)),
3345 : std::make_pair("var a = 10; var b = 1;\n"
3346 : "while (a > 0) {\n"
3347 : " b = b * 2;\n"
3348 : " a = a - 1;\n"
3349 : "};\n"
3350 : "return b;\n",
3351 10 : factory->NewHeapNumber(1024)),
3352 : std::make_pair("var a = 1; var b = 1;\n"
3353 : "do {\n"
3354 : " b = b * 2;\n"
3355 : " --a;\n"
3356 : "} while(a);\n"
3357 : "return b;\n",
3358 : handle(Smi::FromInt(2), isolate)),
3359 : std::make_pair("var b = 1;\n"
3360 : "for ( var a = 10; a > 0; a--) {\n"
3361 : " b *= 2;\n"
3362 : "}\n"
3363 : "return b;",
3364 10 : factory->NewHeapNumber(1024)),
3365 : std::make_pair("var a = 10; var b = 1;\n"
3366 : "while (false) {\n"
3367 : " b = b * 2;\n"
3368 : " a = a - 1;\n"
3369 : "}\n"
3370 : "return b;\n",
3371 : Handle<Object>(Smi::FromInt(1), isolate)),
3372 : std::make_pair("var a = 10; var b = 1;\n"
3373 : "while (true) {\n"
3374 : " b = b * 2;\n"
3375 : " a = a - 1;\n"
3376 : " if (a == 0) break;"
3377 : " continue;"
3378 : "}\n"
3379 : "return b;\n",
3380 10 : factory->NewHeapNumber(1024)),
3381 : std::make_pair("var a = 10; var b = 1;\n"
3382 : "do {\n"
3383 : " b = b * 2;\n"
3384 : " a = a - 1;\n"
3385 : " if (a == 0) break;"
3386 : "} while(true);\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(false);\n"
3395 : "return b;\n",
3396 : Handle<Object>(Smi::FromInt(2), isolate)),
3397 : std::make_pair("var a = 10; var b = 1;\n"
3398 : "for ( a = 1, b = 30; false; ) {\n"
3399 : " b = b * 2;\n"
3400 : "}\n"
3401 : "return b;\n",
3402 15 : Handle<Object>(Smi::FromInt(30), isolate))};
3403 :
3404 60 : for (size_t i = 0; i < arraysize(loops); i++) {
3405 55 : std::string source(InterpreterTester::SourceForBody(loops[i].first));
3406 110 : InterpreterTester tester(isolate, source.c_str());
3407 : auto callable = tester.GetCallable<>();
3408 :
3409 : Handle<i::Object> return_value = callable().ToHandleChecked();
3410 110 : CHECK(return_value->SameValue(*loops[i].second));
3411 5 : }
3412 5 : }
3413 :
3414 25880 : TEST(InterpreterForIn) {
3415 : std::pair<const char*, int> for_in_samples[] = {
3416 : {"var r = -1;\n"
3417 : "for (var a in null) { r = a; }\n"
3418 : "return r;\n",
3419 : -1},
3420 : {"var r = -1;\n"
3421 : "for (var a in undefined) { r = a; }\n"
3422 : "return r;\n",
3423 : -1},
3424 : {"var r = 0;\n"
3425 : "for (var a in [0,6,7,9]) { r = r + (1 << a); }\n"
3426 : "return r;\n",
3427 : 0xF},
3428 : {"var r = 0;\n"
3429 : "for (var a in [0,6,7,9]) { r = r + (1 << a); }\n"
3430 : "var r = 0;\n"
3431 : "for (var a in [0,6,7,9]) { r = r + (1 << a); }\n"
3432 : "return r;\n",
3433 : 0xF},
3434 : {"var r = 0;\n"
3435 : "for (var a in 'foobar') { r = r + (1 << a); }\n"
3436 : "return r;\n",
3437 : 0x3F},
3438 : {"var r = 0;\n"
3439 : "for (var a in {1:0, 10:1, 100:2, 1000:3}) {\n"
3440 : " r = r + Number(a);\n"
3441 : " }\n"
3442 : " return r;\n",
3443 : 1111},
3444 : {"var r = 0;\n"
3445 : "var data = {1:0, 10:1, 100:2, 1000:3};\n"
3446 : "for (var a in data) {\n"
3447 : " if (a == 1) delete data[1];\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 == 10) delete data[100];\n"
3456 : " r = r + Number(a);\n"
3457 : " }\n"
3458 : " return r;\n",
3459 : 1011},
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) data[10000] = 4;\n"
3464 : " r = r + Number(a);\n"
3465 : " }\n"
3466 : " return r;\n",
3467 : 1111},
3468 : {"var r = 0;\n"
3469 : "var input = 'foobar';\n"
3470 : "for (var a in input) {\n"
3471 : " if (input[a] == 'b') break;\n"
3472 : " r = r + (1 << a);\n"
3473 : "}\n"
3474 : "return r;\n",
3475 : 0x7},
3476 : {"var r = 0;\n"
3477 : "var input = 'foobar';\n"
3478 : "for (var a in input) {\n"
3479 : " if (input[a] == 'b') continue;\n"
3480 : " r = r + (1 << a);\n"
3481 : "}\n"
3482 : "return r;\n",
3483 : 0x37},
3484 : {"var r = 0;\n"
3485 : "var data = {1:0, 10:1, 100:2, 1000:3};\n"
3486 : "for (var a in data) {\n"
3487 : " if (a == 10) {\n"
3488 : " data[10000] = 4;\n"
3489 : " }\n"
3490 : " r = r + Number(a);\n"
3491 : "}\n"
3492 : "return r;\n",
3493 : 1111},
3494 : {"var r = [ 3 ];\n"
3495 : "var data = {1:0, 10:1, 100:2, 1000:3};\n"
3496 : "for (r[10] in data) {\n"
3497 : "}\n"
3498 : "return Number(r[10]);\n",
3499 : 1000},
3500 : {"var r = [ 3 ];\n"
3501 : "var data = {1:0, 10:1, 100:2, 1000:3};\n"
3502 : "for (r['100'] in data) {\n"
3503 : "}\n"
3504 : "return Number(r['100']);\n",
3505 : 1000},
3506 : {"var obj = {}\n"
3507 : "var descObj = new Boolean(false);\n"
3508 : "var accessed = 0;\n"
3509 : "descObj.enumerable = true;\n"
3510 : "Object.defineProperties(obj, { prop:descObj });\n"
3511 : "for (var p in obj) {\n"
3512 : " if (p === 'prop') { accessed = 1; }\n"
3513 : "}\n"
3514 : "return accessed;",
3515 : 1},
3516 : {"var appointment = {};\n"
3517 : "Object.defineProperty(appointment, 'startTime', {\n"
3518 : " value: 1001,\n"
3519 : " writable: false,\n"
3520 : " enumerable: false,\n"
3521 : " configurable: true\n"
3522 : "});\n"
3523 : "Object.defineProperty(appointment, 'name', {\n"
3524 : " value: 'NAME',\n"
3525 : " writable: false,\n"
3526 : " enumerable: false,\n"
3527 : " configurable: true\n"
3528 : "});\n"
3529 : "var meeting = Object.create(appointment);\n"
3530 : "Object.defineProperty(meeting, 'conferenceCall', {\n"
3531 : " value: 'In-person meeting',\n"
3532 : " writable: false,\n"
3533 : " enumerable: false,\n"
3534 : " configurable: true\n"
3535 : "});\n"
3536 : "\n"
3537 : "var teamMeeting = Object.create(meeting);\n"
3538 : "\n"
3539 : "var flags = 0;\n"
3540 : "for (var p in teamMeeting) {\n"
3541 : " if (p === 'startTime') {\n"
3542 : " flags |= 1;\n"
3543 : " }\n"
3544 : " if (p === 'name') {\n"
3545 : " flags |= 2;\n"
3546 : " }\n"
3547 : " if (p === 'conferenceCall') {\n"
3548 : " flags |= 4;\n"
3549 : " }\n"
3550 : "}\n"
3551 : "\n"
3552 : "var hasOwnProperty = !teamMeeting.hasOwnProperty('name') &&\n"
3553 : " !teamMeeting.hasOwnProperty('startTime') &&\n"
3554 : " !teamMeeting.hasOwnProperty('conferenceCall');\n"
3555 : "if (!hasOwnProperty) {\n"
3556 : " flags |= 8;\n"
3557 : "}\n"
3558 : "return flags;\n",
3559 : 0},
3560 : {"var data = {x:23, y:34};\n"
3561 : " var result = 0;\n"
3562 : "var o = {};\n"
3563 : "var arr = [o];\n"
3564 : "for (arr[0].p in data)\n" // This is to test if value is loaded
3565 : " result += data[arr[0].p];\n" // back from accumulator before storing
3566 : "return result;\n", // named properties.
3567 : 57},
3568 : {"var data = {x:23, y:34};\n"
3569 : "var result = 0;\n"
3570 : "var o = {};\n"
3571 : "var i = 0;\n"
3572 : "for (o[i++] in data)\n" // This is to test if value is loaded
3573 : " result += data[o[i-1]];\n" // back from accumulator before
3574 : "return result;\n", // storing keyed properties.
3575 5 : 57}};
3576 :
3577 : // Two passes are made for this test. On the first, 8-bit register
3578 : // operands are employed, and on the 16-bit register operands are
3579 : // used.
3580 15 : for (int pass = 0; pass < 2; pass++) {
3581 10 : HandleAndZoneScope handles;
3582 10 : Isolate* isolate = handles.main_isolate();
3583 20 : std::ostringstream wide_os;
3584 10 : if (pass == 1) {
3585 1000 : for (int i = 0; i < 200; i++) {
3586 1000 : wide_os << "var local" << i << " = 0;\n";
3587 : }
3588 : }
3589 :
3590 180 : for (size_t i = 0; i < arraysize(for_in_samples); i++) {
3591 180 : std::ostringstream body_os;
3592 540 : body_os << wide_os.str() << for_in_samples[i].first;
3593 : std::string body(body_os.str());
3594 180 : std::string function = InterpreterTester::SourceForBody(body.c_str());
3595 360 : InterpreterTester tester(isolate, function.c_str());
3596 : auto callable = tester.GetCallable<>();
3597 180 : Handle<Object> return_val = callable().ToHandleChecked();
3598 360 : CHECK_EQ(Handle<Smi>::cast(return_val)->value(),
3599 : for_in_samples[i].second);
3600 180 : }
3601 10 : }
3602 5 : }
3603 :
3604 25880 : TEST(InterpreterForOf) {
3605 5 : HandleAndZoneScope handles;
3606 5 : Isolate* isolate = handles.main_isolate();
3607 : Factory* factory = isolate->factory();
3608 :
3609 : std::pair<const char*, Handle<Object>> for_of[] = {
3610 : {"function f() {\n"
3611 : " var r = 0;\n"
3612 : " for (var a of [0,6,7,9]) { r += a; }\n"
3613 : " return r;\n"
3614 : "}",
3615 : handle(Smi::FromInt(22), isolate)},
3616 : {"function f() {\n"
3617 : " var r = '';\n"
3618 : " for (var a of 'foobar') { r = a + r; }\n"
3619 : " return r;\n"
3620 : "}",
3621 : factory->NewStringFromStaticChars("raboof")},
3622 : {"function f() {\n"
3623 : " var a = [1, 2, 3];\n"
3624 : " a.name = 4;\n"
3625 : " var r = 0;\n"
3626 : " for (var x of a) { r += x; }\n"
3627 : " return r;\n"
3628 : "}",
3629 : handle(Smi::FromInt(6), isolate)},
3630 : {"function f() {\n"
3631 : " var r = '';\n"
3632 : " var data = [1, 2, 3]; \n"
3633 : " for (a of data) { delete data[0]; r += a; } return r; }",
3634 : factory->NewStringFromStaticChars("123")},
3635 : {"function f() {\n"
3636 : " var r = '';\n"
3637 : " var data = [1, 2, 3]; \n"
3638 : " for (a of data) { delete data[2]; r += a; } return r; }",
3639 : factory->NewStringFromStaticChars("12undefined")},
3640 : {"function f() {\n"
3641 : " var r = '';\n"
3642 : " var data = [1, 2, 3]; \n"
3643 : " for (a of data) { delete data; r += a; } return r; }",
3644 : factory->NewStringFromStaticChars("123")},
3645 : {"function f() {\n"
3646 : " var r = '';\n"
3647 : " var input = 'foobar';\n"
3648 : " for (var a of input) {\n"
3649 : " if (a == 'b') break;\n"
3650 : " r += a;\n"
3651 : " }\n"
3652 : " return r;\n"
3653 : "}",
3654 : factory->NewStringFromStaticChars("foo")},
3655 : {"function f() {\n"
3656 : " var r = '';\n"
3657 : " var input = 'foobar';\n"
3658 : " for (var a of input) {\n"
3659 : " if (a == 'b') continue;\n"
3660 : " r += a;\n"
3661 : " }\n"
3662 : " return r;\n"
3663 : "}",
3664 : factory->NewStringFromStaticChars("fooar")},
3665 : {"function f() {\n"
3666 : " var r = '';\n"
3667 : " var data = [1, 2, 3, 4]; \n"
3668 : " for (a of data) { data[2] = 567; r += a; }\n"
3669 : " return r;\n"
3670 : "}",
3671 : factory->NewStringFromStaticChars("125674")},
3672 : {"function f() {\n"
3673 : " var r = '';\n"
3674 : " var data = [1, 2, 3, 4]; \n"
3675 : " for (a of data) { data[4] = 567; r += a; }\n"
3676 : " return r;\n"
3677 : "}",
3678 : factory->NewStringFromStaticChars("1234567")},
3679 : {"function f() {\n"
3680 : " var r = '';\n"
3681 : " var data = [1, 2, 3, 4]; \n"
3682 : " for (a of data) { data[5] = 567; r += a; }\n"
3683 : " return r;\n"
3684 : "}",
3685 : factory->NewStringFromStaticChars("1234undefined567")},
3686 : {"function f() {\n"
3687 : " var r = '';\n"
3688 : " var obj = new Object();\n"
3689 : " obj[Symbol.iterator] = function() { return {\n"
3690 : " index: 3,\n"
3691 : " data: ['a', 'b', 'c', 'd'],"
3692 : " next: function() {"
3693 : " return {"
3694 : " done: this.index == -1,\n"
3695 : " value: this.index < 0 ? undefined : this.data[this.index--]\n"
3696 : " }\n"
3697 : " }\n"
3698 : " }}\n"
3699 : " for (a of obj) { r += a }\n"
3700 : " return r;\n"
3701 : "}",
3702 : factory->NewStringFromStaticChars("dcba")},
3703 60 : };
3704 :
3705 65 : for (size_t i = 0; i < arraysize(for_of); i++) {
3706 60 : InterpreterTester tester(isolate, for_of[i].first);
3707 : auto callable = tester.GetCallable<>();
3708 : Handle<Object> return_val = callable().ToHandleChecked();
3709 120 : CHECK(return_val->SameValue(*for_of[i].second));
3710 65 : }
3711 5 : }
3712 :
3713 25880 : TEST(InterpreterSwitch) {
3714 5 : HandleAndZoneScope handles;
3715 5 : Isolate* isolate = handles.main_isolate();
3716 : Factory* factory = isolate->factory();
3717 :
3718 : std::pair<const char*, Handle<Object>> switch_ops[] = {
3719 : std::make_pair("var a = 1;\n"
3720 : "switch(a) {\n"
3721 : " case 1: return 2;\n"
3722 : " case 2: return 3;\n"
3723 : "}\n",
3724 : handle(Smi::FromInt(2), isolate)),
3725 : std::make_pair("var a = 1;\n"
3726 : "switch(a) {\n"
3727 : " case 2: a = 2; break;\n"
3728 : " case 1: a = 3; break;\n"
3729 : "}\n"
3730 : "return a;",
3731 : handle(Smi::FromInt(3), isolate)),
3732 : std::make_pair("var a = 1;\n"
3733 : "switch(a) {\n"
3734 : " case 1: a = 2; // fall-through\n"
3735 : " case 2: a = 3; break;\n"
3736 : "}\n"
3737 : "return a;",
3738 : handle(Smi::FromInt(3), isolate)),
3739 : std::make_pair("var a = 100;\n"
3740 : "switch(a) {\n"
3741 : " case 1: return 100;\n"
3742 : " case 2: return 200;\n"
3743 : "}\n"
3744 : "return undefined;",
3745 : factory->undefined_value()),
3746 : std::make_pair("var a = 100;\n"
3747 : "switch(a) {\n"
3748 : " case 1: return 100;\n"
3749 : " case 2: return 200;\n"
3750 : " default: return 300;\n"
3751 : "}\n"
3752 : "return undefined;",
3753 : handle(Smi::FromInt(300), isolate)),
3754 : std::make_pair("var a = 100;\n"
3755 : "switch(typeof(a)) {\n"
3756 : " case 'string': return 1;\n"
3757 : " case 'number': return 2;\n"
3758 : " default: return 3;\n"
3759 : "}\n",
3760 : handle(Smi::FromInt(2), isolate)),
3761 : std::make_pair("var a = 100;\n"
3762 : "switch(a) {\n"
3763 : " case a += 20: return 1;\n"
3764 : " case a -= 10: return 2;\n"
3765 : " case a -= 10: return 3;\n"
3766 : " default: return 3;\n"
3767 : "}\n",
3768 : handle(Smi::FromInt(3), isolate)),
3769 : std::make_pair("var a = 1;\n"
3770 : "switch(a) {\n"
3771 : " case 1: \n"
3772 : " switch(a + 1) {\n"
3773 : " case 2 : a += 1; break;\n"
3774 : " default : a += 2; break;\n"
3775 : " } // fall-through\n"
3776 : " case 2: a += 3;\n"
3777 : "}\n"
3778 : "return a;",
3779 : handle(Smi::FromInt(5), isolate)),
3780 : };
3781 :
3782 45 : for (size_t i = 0; i < arraysize(switch_ops); i++) {
3783 40 : std::string source(InterpreterTester::SourceForBody(switch_ops[i].first));
3784 80 : InterpreterTester tester(isolate, source.c_str());
3785 : auto callable = tester.GetCallable<>();
3786 :
3787 : Handle<i::Object> return_value = callable().ToHandleChecked();
3788 80 : CHECK(return_value->SameValue(*switch_ops[i].second));
3789 5 : }
3790 5 : }
3791 :
3792 25880 : TEST(InterpreterSloppyThis) {
3793 5 : HandleAndZoneScope handles;
3794 5 : Isolate* isolate = handles.main_isolate();
3795 : Factory* factory = isolate->factory();
3796 :
3797 : std::pair<const char*, Handle<Object>> sloppy_this[] = {
3798 : std::make_pair("var global_val = 100;\n"
3799 : "function f() { return this.global_val; }\n",
3800 : handle(Smi::FromInt(100), isolate)),
3801 : std::make_pair("var global_val = 110;\n"
3802 : "function g() { return this.global_val; };"
3803 : "function f() { return g(); }\n",
3804 : handle(Smi::FromInt(110), isolate)),
3805 : std::make_pair("var global_val = 110;\n"
3806 : "function g() { return this.global_val };"
3807 : "function f() { 'use strict'; return g(); }\n",
3808 : handle(Smi::FromInt(110), isolate)),
3809 : std::make_pair("function f() { 'use strict'; return this; }\n",
3810 : factory->undefined_value()),
3811 : std::make_pair("function g() { 'use strict'; return this; };"
3812 : "function f() { return g(); }\n",
3813 : factory->undefined_value()),
3814 : };
3815 :
3816 30 : for (size_t i = 0; i < arraysize(sloppy_this); i++) {
3817 25 : InterpreterTester tester(isolate, sloppy_this[i].first);
3818 : auto callable = tester.GetCallable<>();
3819 :
3820 : Handle<i::Object> return_value = callable().ToHandleChecked();
3821 50 : CHECK(return_value->SameValue(*sloppy_this[i].second));
3822 30 : }
3823 5 : }
3824 :
3825 25880 : TEST(InterpreterThisFunction) {
3826 5 : HandleAndZoneScope handles;
3827 5 : Isolate* isolate = handles.main_isolate();
3828 : Factory* factory = isolate->factory();
3829 :
3830 : InterpreterTester tester(isolate,
3831 10 : "var f;\n f = function f() { return f.name; }");
3832 : auto callable = tester.GetCallable<>();
3833 :
3834 : Handle<i::Object> return_value = callable().ToHandleChecked();
3835 20 : CHECK(return_value->SameValue(*factory->NewStringFromStaticChars("f")));
3836 5 : }
3837 :
3838 25880 : TEST(InterpreterNewTarget) {
3839 5 : HandleAndZoneScope handles;
3840 5 : Isolate* isolate = handles.main_isolate();
3841 : Factory* factory = isolate->factory();
3842 :
3843 : // TODO(rmcilroy): Add tests that we get the original constructor for
3844 : // superclass constructors once we have class support.
3845 10 : InterpreterTester tester(isolate, "function f() { this.a = new.target; }");
3846 : auto callable = tester.GetCallable<>();
3847 : callable().ToHandleChecked();
3848 :
3849 : Handle<Object> new_target_name = v8::Utils::OpenHandle(
3850 : *CompileRun("(function() { return (new f()).a.name; })();"));
3851 20 : CHECK(new_target_name->SameValue(*factory->NewStringFromStaticChars("f")));
3852 5 : }
3853 :
3854 25880 : TEST(InterpreterAssignmentInExpressions) {
3855 5 : HandleAndZoneScope handles;
3856 5 : Isolate* isolate = handles.main_isolate();
3857 :
3858 : std::pair<const char*, int> samples[] = {
3859 : {"function f() {\n"
3860 : " var x = 7;\n"
3861 : " var y = x + (x = 1) + (x = 2);\n"
3862 : " return y;\n"
3863 : "}",
3864 : 10},
3865 : {"function f() {\n"
3866 : " var x = 7;\n"
3867 : " var y = x + (x = 1) + (x = 2);\n"
3868 : " return x;\n"
3869 : "}",
3870 : 2},
3871 : {"function f() {\n"
3872 : " var x = 55;\n"
3873 : " x = x + (x = 100) + (x = 101);\n"
3874 : " return x;\n"
3875 : "}",
3876 : 256},
3877 : {"function f() {\n"
3878 : " var x = 7;\n"
3879 : " return ++x + x + x++;\n"
3880 : "}",
3881 : 24},
3882 : {"function f() {\n"
3883 : " var x = 7;\n"
3884 : " var y = 1 + ++x + x + x++;\n"
3885 : " return x;\n"
3886 : "}",
3887 : 9},
3888 : {"function f() {\n"
3889 : " var x = 7;\n"
3890 : " var y = ++x + x + x++;\n"
3891 : " return x;\n"
3892 : "}",
3893 : 9},
3894 : {"function f() {\n"
3895 : " var x = 7, y = 100, z = 1000;\n"
3896 : " return x + (x += 3) + y + (y *= 10) + (z *= 7) + z;\n"
3897 : "}",
3898 : 15117},
3899 : {"function f() {\n"
3900 : " var inner = function (x) { return x + (x = 2) + (x = 4) + x; };\n"
3901 : " return inner(1);\n"
3902 : "}",
3903 : 11},
3904 : {"function f() {\n"
3905 : " var x = 1, y = 2;\n"
3906 : " x = x + (x = 3) + y + (y = 4), y = y + (y = 5) + y + x;\n"
3907 : " return x + y;\n"
3908 : "}",
3909 : 10 + 24},
3910 : {"function f() {\n"
3911 : " var x = 0;\n"
3912 : " var y = x | (x = 1) | (x = 2);\n"
3913 : " return x;\n"
3914 : "}",
3915 : 2},
3916 : {"function f() {\n"
3917 : " var x = 0;\n"
3918 : " var y = x || (x = 1);\n"
3919 : " return x;\n"
3920 : "}",
3921 : 1},
3922 : {"function f() {\n"
3923 : " var x = 1;\n"
3924 : " var y = x && (x = 2) && (x = 3);\n"
3925 : " return x;\n"
3926 : "}",
3927 : 3},
3928 : {"function f() {\n"
3929 : " var x = 1;\n"
3930 : " var y = x || (x = 2);\n"
3931 : " return x;\n"
3932 : "}",
3933 : 1},
3934 : {"function f() {\n"
3935 : " var x = 1;\n"
3936 : " x = (x << (x = 3)) | (x = 16);\n"
3937 : " return x;\n"
3938 : "}",
3939 : 24},
3940 : {"function f() {\n"
3941 : " var r = 7;\n"
3942 : " var s = 11;\n"
3943 : " var t = 13;\n"
3944 : " var u = r + s + t + (r = 10) + (s = 20) +"
3945 : " (t = (r + s)) + r + s + t;\n"
3946 : " return r + s + t + u;\n"
3947 : "}",
3948 : 211},
3949 : {"function f() {\n"
3950 : " var r = 7;\n"
3951 : " var s = 11;\n"
3952 : " var t = 13;\n"
3953 : " return r > (3 * s * (s = 1)) ? (t + (t += 1)) : (r + (r = 4));\n"
3954 : "}",
3955 : 11},
3956 : {"function f() {\n"
3957 : " var r = 7;\n"
3958 : " var s = 11;\n"
3959 : " var t = 13;\n"
3960 : " return r > (3 * s * (s = 0)) ? (t + (t += 1)) : (r + (r = 4));\n"
3961 : "}",
3962 : 27},
3963 : {"function f() {\n"
3964 : " var r = 7;\n"
3965 : " var s = 11;\n"
3966 : " var t = 13;\n"
3967 : " return (r + (r = 5)) > s ? r : t;\n"
3968 : "}",
3969 : 5},
3970 : {"function f(a) {\n"
3971 : " return a + (arguments[0] = 10);\n"
3972 : "}",
3973 : 50},
3974 : {"function f(a) {\n"
3975 : " return a + (arguments[0] = 10) + a;\n"
3976 : "}",
3977 : 60},
3978 : {"function f(a) {\n"
3979 : " return a + (arguments[0] = 10) + arguments[0];\n"
3980 : "}",
3981 : 60},
3982 5 : };
3983 :
3984 : const int arg_value = 40;
3985 110 : for (size_t i = 0; i < arraysize(samples); i++) {
3986 105 : InterpreterTester tester(isolate, samples[i].first);
3987 : auto callable = tester.GetCallable<Handle<Object>>();
3988 : Handle<Object> return_val =
3989 105 : callable(handle(Smi::FromInt(arg_value), handles.main_isolate()))
3990 105 : .ToHandleChecked();
3991 210 : CHECK_EQ(Handle<Smi>::cast(return_val)->value(), samples[i].second);
3992 110 : }
3993 5 : }
3994 :
3995 25880 : TEST(InterpreterToName) {
3996 5 : HandleAndZoneScope handles;
3997 5 : Isolate* isolate = handles.main_isolate();
3998 : Factory* factory = isolate->factory();
3999 :
4000 : std::pair<const char*, Handle<Object>> to_name_tests[] = {
4001 : {"var a = 'val'; var obj = {[a] : 10}; return obj.val;",
4002 : factory->NewNumberFromInt(10)},
4003 : {"var a = 20; var obj = {[a] : 10}; return obj['20'];",
4004 : factory->NewNumberFromInt(10)},
4005 : {"var a = 20; var obj = {[a] : 10}; return obj[20];",
4006 : factory->NewNumberFromInt(10)},
4007 : {"var a = {val:23}; var obj = {[a] : 10}; return obj[a];",
4008 : factory->NewNumberFromInt(10)},
4009 : {"var a = {val:23}; var obj = {[a] : 10};\n"
4010 : "return obj['[object Object]'];",
4011 : factory->NewNumberFromInt(10)},
4012 : {"var a = {toString : function() { return 'x'}};\n"
4013 : "var obj = {[a] : 10};\n"
4014 : "return obj.x;",
4015 : factory->NewNumberFromInt(10)},
4016 : {"var a = {valueOf : function() { return 'x'}};\n"
4017 : "var obj = {[a] : 10};\n"
4018 : "return obj.x;",
4019 : factory->undefined_value()},
4020 : {"var a = {[Symbol.toPrimitive] : function() { return 'x'}};\n"
4021 : "var obj = {[a] : 10};\n"
4022 : "return obj.x;",
4023 : factory->NewNumberFromInt(10)},
4024 45 : };
4025 :
4026 45 : for (size_t i = 0; i < arraysize(to_name_tests); i++) {
4027 : std::string source(
4028 40 : InterpreterTester::SourceForBody(to_name_tests[i].first));
4029 80 : InterpreterTester tester(isolate, source.c_str());
4030 : auto callable = tester.GetCallable<>();
4031 :
4032 : Handle<i::Object> return_value = callable().ToHandleChecked();
4033 80 : CHECK(return_value->SameValue(*to_name_tests[i].second));
4034 5 : }
4035 5 : }
4036 :
4037 25880 : TEST(TemporaryRegisterAllocation) {
4038 5 : HandleAndZoneScope handles;
4039 5 : Isolate* isolate = handles.main_isolate();
4040 : Factory* factory = isolate->factory();
4041 :
4042 : std::pair<const char*, Handle<Object>> reg_tests[] = {
4043 : {"function add(a, b, c) {"
4044 : " return a + b + c;"
4045 : "}"
4046 : "function f() {"
4047 : " var a = 10, b = 10;"
4048 : " return add(a, b++, b);"
4049 : "}",
4050 : factory->NewNumberFromInt(31)},
4051 : {"function add(a, b, c, d) {"
4052 : " return a + b + c + d;"
4053 : "}"
4054 : "function f() {"
4055 : " var x = 10, y = 20, z = 30;"
4056 : " return x + add(x, (y= x++), x, z);"
4057 : "}",
4058 : factory->NewNumberFromInt(71)},
4059 15 : };
4060 :
4061 15 : for (size_t i = 0; i < arraysize(reg_tests); i++) {
4062 10 : InterpreterTester tester(isolate, reg_tests[i].first);
4063 : auto callable = tester.GetCallable<>();
4064 :
4065 : Handle<i::Object> return_value = callable().ToHandleChecked();
4066 20 : CHECK(return_value->SameValue(*reg_tests[i].second));
4067 15 : }
4068 5 : }
4069 :
4070 25880 : TEST(InterpreterLookupSlot) {
4071 5 : HandleAndZoneScope handles;
4072 5 : Isolate* isolate = handles.main_isolate();
4073 : Factory* factory = isolate->factory();
4074 :
4075 : // TODO(mythria): Add more tests when we have support for eval/with.
4076 : const char* function_prologue = "var f;"
4077 : "var x = 1;"
4078 : "function f1() {"
4079 : " eval(\"function t() {";
4080 : const char* function_epilogue = " }; f = t;\");"
4081 : "}"
4082 : "f1();";
4083 :
4084 :
4085 : std::pair<const char*, Handle<Object>> lookup_slot[] = {
4086 : {"return x;", handle(Smi::FromInt(1), isolate)},
4087 : {"return typeof x;", factory->NewStringFromStaticChars("number")},
4088 : {"return typeof dummy;", factory->NewStringFromStaticChars("undefined")},
4089 : {"x = 10; return x;", handle(Smi::FromInt(10), isolate)},
4090 : {"'use strict'; x = 20; return x;", handle(Smi::FromInt(20), isolate)},
4091 15 : };
4092 :
4093 30 : for (size_t i = 0; i < arraysize(lookup_slot); i++) {
4094 100 : std::string script = std::string(function_prologue) +
4095 : std::string(lookup_slot[i].first) +
4096 75 : std::string(function_epilogue);
4097 :
4098 50 : InterpreterTester tester(isolate, script.c_str(), "t");
4099 : auto callable = tester.GetCallable<>();
4100 :
4101 : Handle<i::Object> return_value = callable().ToHandleChecked();
4102 50 : CHECK(return_value->SameValue(*lookup_slot[i].second));
4103 5 : }
4104 5 : }
4105 :
4106 25880 : TEST(InterpreterLookupContextSlot) {
4107 5 : HandleAndZoneScope handles;
4108 5 : Isolate* isolate = handles.main_isolate();
4109 :
4110 : const char* inner_function_prologue = "function inner() {";
4111 : const char* inner_function_epilogue = "};";
4112 : const char* outer_function_epilogue = "return inner();";
4113 :
4114 : std::tuple<const char*, const char*, Handle<Object>> lookup_slot[] = {
4115 : // Eval in inner context.
4116 : std::make_tuple("var x = 0;", "eval(''); return x;",
4117 : handle(Smi::kZero, isolate)),
4118 : std::make_tuple("var x = 0;", "eval('var x = 1'); return x;",
4119 : handle(Smi::FromInt(1), isolate)),
4120 : std::make_tuple("var x = 0;",
4121 : "'use strict'; eval('var x = 1'); return x;",
4122 : handle(Smi::kZero, isolate)),
4123 : // Eval in outer 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("'use strict'; var x = 0; eval('var x = 1');",
4129 : "return x;", handle(Smi::kZero, isolate)),
4130 : };
4131 :
4132 35 : for (size_t i = 0; i < arraysize(lookup_slot); i++) {
4133 120 : std::string body = std::string(std::get<0>(lookup_slot[i])) +
4134 120 : std::string(inner_function_prologue) +
4135 120 : std::string(std::get<1>(lookup_slot[i])) +
4136 : std::string(inner_function_epilogue) +
4137 90 : std::string(outer_function_epilogue);
4138 30 : std::string script = InterpreterTester::SourceForBody(body.c_str());
4139 :
4140 60 : InterpreterTester tester(isolate, script.c_str());
4141 : auto callable = tester.GetCallable<>();
4142 :
4143 : Handle<i::Object> return_value = callable().ToHandleChecked();
4144 30 : CHECK(return_value->SameValue(*std::get<2>(lookup_slot[i])));
4145 5 : }
4146 5 : }
4147 :
4148 25880 : TEST(InterpreterLookupGlobalSlot) {
4149 5 : HandleAndZoneScope handles;
4150 5 : Isolate* isolate = handles.main_isolate();
4151 :
4152 : const char* inner_function_prologue = "function inner() {";
4153 : const char* inner_function_epilogue = "};";
4154 : const char* outer_function_epilogue = "return inner();";
4155 :
4156 : std::tuple<const char*, const char*, Handle<Object>> lookup_slot[] = {
4157 : // Eval in inner context.
4158 : std::make_tuple("x = 0;", "eval(''); return x;",
4159 : handle(Smi::kZero, isolate)),
4160 : std::make_tuple("x = 0;", "eval('var x = 1'); return x;",
4161 : handle(Smi::FromInt(1), isolate)),
4162 : std::make_tuple("x = 0;", "'use strict'; eval('var x = 1'); return x;",
4163 : handle(Smi::kZero, isolate)),
4164 : // Eval in outer context.
4165 : std::make_tuple("x = 0; eval('');", "return x;",
4166 : handle(Smi::kZero, isolate)),
4167 : std::make_tuple("x = 0; eval('var x = 1');", "return x;",
4168 : handle(Smi::FromInt(1), isolate)),
4169 : std::make_tuple("'use strict'; x = 0; eval('var x = 1');", "return x;",
4170 : handle(Smi::kZero, isolate)),
4171 : };
4172 :
4173 35 : for (size_t i = 0; i < arraysize(lookup_slot); i++) {
4174 120 : std::string body = std::string(std::get<0>(lookup_slot[i])) +
4175 120 : std::string(inner_function_prologue) +
4176 120 : std::string(std::get<1>(lookup_slot[i])) +
4177 : std::string(inner_function_epilogue) +
4178 90 : std::string(outer_function_epilogue);
4179 30 : std::string script = InterpreterTester::SourceForBody(body.c_str());
4180 :
4181 60 : InterpreterTester tester(isolate, script.c_str());
4182 : auto callable = tester.GetCallable<>();
4183 :
4184 : Handle<i::Object> return_value = callable().ToHandleChecked();
4185 30 : CHECK(return_value->SameValue(*std::get<2>(lookup_slot[i])));
4186 5 : }
4187 5 : }
4188 :
4189 25880 : TEST(InterpreterCallLookupSlot) {
4190 5 : HandleAndZoneScope handles;
4191 5 : Isolate* isolate = handles.main_isolate();
4192 :
4193 : std::pair<const char*, Handle<Object>> call_lookup[] = {
4194 : {"g = function(){ return 2 }; eval(''); return g();",
4195 : handle(Smi::FromInt(2), isolate)},
4196 : {"g = function(){ return 2 }; eval('g = function() {return 3}');\n"
4197 : "return g();",
4198 : handle(Smi::FromInt(3), isolate)},
4199 : {"g = { x: function(){ return this.y }, y: 20 };\n"
4200 : "eval('g = { x: g.x, y: 30 }');\n"
4201 : "return g.x();",
4202 : handle(Smi::FromInt(30), isolate)},
4203 : };
4204 :
4205 20 : for (size_t i = 0; i < arraysize(call_lookup); i++) {
4206 15 : std::string source(InterpreterTester::SourceForBody(call_lookup[i].first));
4207 30 : InterpreterTester tester(isolate, source.c_str());
4208 : auto callable = tester.GetCallable<>();
4209 :
4210 : Handle<i::Object> return_value = callable().ToHandleChecked();
4211 30 : CHECK(return_value->SameValue(*call_lookup[i].second));
4212 5 : }
4213 5 : }
4214 :
4215 25880 : TEST(InterpreterLookupSlotWide) {
4216 5 : HandleAndZoneScope handles;
4217 5 : Isolate* isolate = handles.main_isolate();
4218 : Factory* factory = isolate->factory();
4219 :
4220 : const char* function_prologue =
4221 : "var f;"
4222 : "var x = 1;"
4223 : "function f1() {"
4224 : " eval(\"function t() {";
4225 : const char* function_epilogue =
4226 : " }; f = t;\");"
4227 : "}"
4228 : "f1();";
4229 10 : std::ostringstream str;
4230 5 : str << "var y = 2.3;";
4231 1280 : for (int i = 1; i < 256; i++) {
4232 2550 : str << "y = " << 2.3 + i << ";";
4233 : }
4234 : std::string init_function_body = str.str();
4235 :
4236 : std::pair<std::string, Handle<Object>> lookup_slot[] = {
4237 5 : {init_function_body + "return x;", handle(Smi::FromInt(1), isolate)},
4238 5 : {init_function_body + "return typeof x;",
4239 : factory->NewStringFromStaticChars("number")},
4240 5 : {init_function_body + "return x = 10;",
4241 : handle(Smi::FromInt(10), isolate)},
4242 10 : {"'use strict';" + init_function_body + "x = 20; return x;",
4243 : handle(Smi::FromInt(20), isolate)},
4244 35 : };
4245 :
4246 25 : for (size_t i = 0; i < arraysize(lookup_slot); i++) {
4247 60 : std::string script = std::string(function_prologue) + lookup_slot[i].first +
4248 60 : std::string(function_epilogue);
4249 :
4250 40 : InterpreterTester tester(isolate, script.c_str(), "t");
4251 : auto callable = tester.GetCallable<>();
4252 :
4253 : Handle<i::Object> return_value = callable().ToHandleChecked();
4254 40 : CHECK(return_value->SameValue(*lookup_slot[i].second));
4255 5 : }
4256 5 : }
4257 :
4258 25880 : TEST(InterpreterDeleteLookupSlot) {
4259 5 : HandleAndZoneScope handles;
4260 5 : Isolate* isolate = handles.main_isolate();
4261 : Factory* factory = isolate->factory();
4262 :
4263 : // TODO(mythria): Add more tests when we have support for eval/with.
4264 : const char* function_prologue = "var f;"
4265 : "var x = 1;"
4266 : "y = 10;"
4267 : "var obj = {val:10};"
4268 : "var z = 30;"
4269 : "function f1() {"
4270 : " var z = 20;"
4271 : " eval(\"function t() {";
4272 : const char* function_epilogue = " }; f = t;\");"
4273 : "}"
4274 : "f1();";
4275 :
4276 :
4277 : std::pair<const char*, Handle<Object>> delete_lookup_slot[] = {
4278 : {"return delete x;", factory->false_value()},
4279 : {"return delete y;", factory->true_value()},
4280 : {"return delete z;", factory->false_value()},
4281 : {"return delete obj.val;", factory->true_value()},
4282 : {"'use strict'; return delete obj.val;", factory->true_value()},
4283 : };
4284 :
4285 30 : for (size_t i = 0; i < arraysize(delete_lookup_slot); i++) {
4286 100 : std::string script = std::string(function_prologue) +
4287 : std::string(delete_lookup_slot[i].first) +
4288 75 : std::string(function_epilogue);
4289 :
4290 50 : InterpreterTester tester(isolate, script.c_str(), "t");
4291 : auto callable = tester.GetCallable<>();
4292 :
4293 : Handle<i::Object> return_value = callable().ToHandleChecked();
4294 50 : CHECK(return_value->SameValue(*delete_lookup_slot[i].second));
4295 5 : }
4296 5 : }
4297 :
4298 25880 : TEST(JumpWithConstantsAndWideConstants) {
4299 5 : HandleAndZoneScope handles;
4300 5 : Isolate* isolate = handles.main_isolate();
4301 : Factory* factory = isolate->factory();
4302 : const int kStep = 13;
4303 115 : for (int constants = 11; constants < 256 + 3 * kStep; constants += kStep) {
4304 110 : std::ostringstream filler_os;
4305 : // Generate a string that consumes constant pool entries and
4306 : // spread out branch distances in script below.
4307 16335 : for (int i = 0; i < constants; i++) {
4308 16225 : filler_os << "var x_ = 'x_" << i << "';\n";
4309 : }
4310 : std::string filler(filler_os.str());
4311 220 : std::ostringstream script_os;
4312 330 : script_os << "function " << InterpreterTester::function_name() << "(a) {\n";
4313 110 : script_os << " " << filler;
4314 110 : script_os << " for (var i = a; i < 2; i++) {\n";
4315 110 : script_os << " " << filler;
4316 220 : script_os << " if (i == 0) { " << filler << "i = 10; continue; }\n";
4317 220 : script_os << " else if (i == a) { " << filler << "i = 12; break; }\n";
4318 220 : script_os << " else { " << filler << " }\n";
4319 110 : script_os << " }\n";
4320 110 : script_os << " return i;\n";
4321 110 : script_os << "}\n";
4322 : std::string script(script_os.str());
4323 440 : for (int a = 0; a < 3; a++) {
4324 330 : InterpreterTester tester(isolate, script.c_str());
4325 : auto callable = tester.GetCallable<Handle<Object>>();
4326 330 : Handle<Object> argument = factory->NewNumberFromInt(a);
4327 330 : Handle<Object> return_val = callable(argument).ToHandleChecked();
4328 : static const int results[] = {11, 12, 2};
4329 660 : CHECK_EQ(Handle<Smi>::cast(return_val)->value(), results[a]);
4330 330 : }
4331 115 : }
4332 5 : }
4333 :
4334 25880 : TEST(InterpreterEval) {
4335 5 : HandleAndZoneScope handles;
4336 5 : Isolate* isolate = handles.main_isolate();
4337 : Factory* factory = isolate->factory();
4338 :
4339 : std::pair<const char*, Handle<Object>> eval[] = {
4340 : {"return eval('1;');", handle(Smi::FromInt(1), isolate)},
4341 : {"return eval('100 * 20;');", handle(Smi::FromInt(2000), isolate)},
4342 : {"var x = 10; return eval('x + 20;');",
4343 : handle(Smi::FromInt(30), isolate)},
4344 : {"var x = 10; eval('x = 33;'); return x;",
4345 : handle(Smi::FromInt(33), isolate)},
4346 : {"'use strict'; var x = 20; var z = 0;\n"
4347 : "eval('var x = 33; z = x;'); return x + z;",
4348 : handle(Smi::FromInt(53), isolate)},
4349 : {"eval('var x = 33;'); eval('var y = x + 20'); return x + y;",
4350 : handle(Smi::FromInt(86), isolate)},
4351 : {"var x = 1; eval('for(i = 0; i < 10; i++) x = x + 1;'); return x",
4352 : handle(Smi::FromInt(11), isolate)},
4353 : {"var x = 10; eval('var x = 20;'); return x;",
4354 : handle(Smi::FromInt(20), isolate)},
4355 : {"var x = 1; eval('\"use strict\"; var x = 2;'); return x;",
4356 : handle(Smi::FromInt(1), isolate)},
4357 : {"'use strict'; var x = 1; eval('var x = 2;'); return x;",
4358 : handle(Smi::FromInt(1), isolate)},
4359 : {"var x = 10; eval('x + 20;'); return typeof x;",
4360 : factory->NewStringFromStaticChars("number")},
4361 : {"eval('var y = 10;'); return typeof unallocated;",
4362 : factory->NewStringFromStaticChars("undefined")},
4363 : {"'use strict'; eval('var y = 10;'); return typeof unallocated;",
4364 : factory->NewStringFromStaticChars("undefined")},
4365 : {"eval('var x = 10;'); return typeof x;",
4366 : factory->NewStringFromStaticChars("number")},
4367 : {"var x = {}; eval('var x = 10;'); return typeof x;",
4368 : factory->NewStringFromStaticChars("number")},
4369 : {"'use strict'; var x = {}; eval('var x = 10;'); return typeof x;",
4370 : factory->NewStringFromStaticChars("object")},
4371 35 : };
4372 :
4373 85 : for (size_t i = 0; i < arraysize(eval); i++) {
4374 80 : std::string source(InterpreterTester::SourceForBody(eval[i].first));
4375 160 : InterpreterTester tester(isolate, source.c_str());
4376 : auto callable = tester.GetCallable<>();
4377 : Handle<i::Object> return_value = callable().ToHandleChecked();
4378 160 : CHECK(return_value->SameValue(*eval[i].second));
4379 5 : }
4380 5 : }
4381 :
4382 25880 : TEST(InterpreterEvalParams) {
4383 5 : HandleAndZoneScope handles;
4384 5 : Isolate* isolate = handles.main_isolate();
4385 :
4386 : std::pair<const char*, Handle<Object>> eval_params[] = {
4387 : {"var x = 10; return eval('x + p1;');",
4388 : handle(Smi::FromInt(30), isolate)},
4389 : {"var x = 10; eval('p1 = x;'); return p1;",
4390 : handle(Smi::FromInt(10), isolate)},
4391 : {"var a = 10;"
4392 : "function inner() { return eval('a + p1;');}"
4393 : "return inner();",
4394 : handle(Smi::FromInt(30), isolate)},
4395 : };
4396 :
4397 20 : for (size_t i = 0; i < arraysize(eval_params); i++) {
4398 60 : std::string source = "function " + InterpreterTester::function_name() +
4399 30 : "(p1) {" + eval_params[i].first + "}";
4400 30 : InterpreterTester tester(isolate, source.c_str());
4401 : auto callable = tester.GetCallable<Handle<Object>>();
4402 :
4403 : Handle<i::Object> return_value =
4404 : callable(handle(Smi::FromInt(20), isolate)).ToHandleChecked();
4405 30 : CHECK(return_value->SameValue(*eval_params[i].second));
4406 5 : }
4407 5 : }
4408 :
4409 25880 : TEST(InterpreterEvalGlobal) {
4410 5 : HandleAndZoneScope handles;
4411 5 : Isolate* isolate = handles.main_isolate();
4412 : Factory* factory = isolate->factory();
4413 :
4414 : std::pair<const char*, Handle<Object>> eval_global[] = {
4415 : {"function add_global() { eval('function test() { z = 33; }; test()'); };"
4416 : "function f() { add_global(); return z; }; f();",
4417 : handle(Smi::FromInt(33), isolate)},
4418 : {"function add_global() {\n"
4419 : " eval('\"use strict\"; function test() { y = 33; };"
4420 : " try { test() } catch(e) {}');\n"
4421 : "}\n"
4422 : "function f() { add_global(); return typeof y; } f();",
4423 : factory->NewStringFromStaticChars("undefined")},
4424 10 : };
4425 :
4426 15 : for (size_t i = 0; i < arraysize(eval_global); i++) {
4427 10 : InterpreterTester tester(isolate, eval_global[i].first, "test");
4428 : auto callable = tester.GetCallable<>();
4429 :
4430 : Handle<i::Object> return_value = callable().ToHandleChecked();
4431 20 : CHECK(return_value->SameValue(*eval_global[i].second));
4432 15 : }
4433 5 : }
4434 :
4435 25880 : TEST(InterpreterEvalVariableDecl) {
4436 5 : HandleAndZoneScope handles;
4437 5 : Isolate* isolate = handles.main_isolate();
4438 : Factory* factory = isolate->factory();
4439 :
4440 : std::pair<const char*, Handle<Object>> eval_global[] = {
4441 : {"function f() { eval('var x = 10; x++;'); return x; }",
4442 : handle(Smi::FromInt(11), isolate)},
4443 : {"function f() { var x = 20; eval('var x = 10; x++;'); return x; }",
4444 : handle(Smi::FromInt(11), isolate)},
4445 : {"function f() {"
4446 : " var x = 20;"
4447 : " eval('\"use strict\"; var x = 10; x++;');"
4448 : " return x; }",
4449 : handle(Smi::FromInt(20), isolate)},
4450 : {"function f() {"
4451 : " var y = 30;"
4452 : " eval('var x = {1:20}; x[2]=y;');"
4453 : " return x[2]; }",
4454 : handle(Smi::FromInt(30), isolate)},
4455 : {"function f() {"
4456 : " eval('var x = {name:\"test\"};');"
4457 : " return x.name; }",
4458 : factory->NewStringFromStaticChars("test")},
4459 : {"function f() {"
4460 : " eval('var x = [{name:\"test\"}, {type:\"cc\"}];');"
4461 : " return x[1].type+x[0].name; }",
4462 : factory->NewStringFromStaticChars("cctest")},
4463 : {"function f() {\n"
4464 : " var x = 3;\n"
4465 : " var get_eval_x;\n"
4466 : " eval('\"use strict\"; "
4467 : " var x = 20; "
4468 : " get_eval_x = function func() {return x;};');\n"
4469 : " return get_eval_x() + x;\n"
4470 : "}",
4471 : handle(Smi::FromInt(23), isolate)},
4472 : // TODO(mythria): Add tests with const declarations.
4473 15 : };
4474 :
4475 40 : for (size_t i = 0; i < arraysize(eval_global); i++) {
4476 35 : InterpreterTester tester(isolate, eval_global[i].first, "*");
4477 : auto callable = tester.GetCallable<>();
4478 :
4479 : Handle<i::Object> return_value = callable().ToHandleChecked();
4480 70 : CHECK(return_value->SameValue(*eval_global[i].second));
4481 40 : }
4482 5 : }
4483 :
4484 25880 : TEST(InterpreterEvalFunctionDecl) {
4485 5 : HandleAndZoneScope handles;
4486 5 : Isolate* isolate = handles.main_isolate();
4487 :
4488 : std::pair<const char*, Handle<Object>> eval_func_decl[] = {
4489 : {"function f() {\n"
4490 : " var x = 3;\n"
4491 : " eval('var x = 20;"
4492 : " function get_x() {return x;};');\n"
4493 : " return get_x() + x;\n"
4494 : "}",
4495 : handle(Smi::FromInt(40), isolate)},
4496 : };
4497 :
4498 10 : for (size_t i = 0; i < arraysize(eval_func_decl); i++) {
4499 5 : InterpreterTester tester(isolate, eval_func_decl[i].first, "*");
4500 : auto callable = tester.GetCallable<>();
4501 :
4502 : Handle<i::Object> return_value = callable().ToHandleChecked();
4503 10 : CHECK(return_value->SameValue(*eval_func_decl[i].second));
4504 10 : }
4505 5 : }
4506 :
4507 25880 : TEST(InterpreterWideRegisterArithmetic) {
4508 5 : HandleAndZoneScope handles;
4509 5 : Isolate* isolate = handles.main_isolate();
4510 :
4511 : static const size_t kMaxRegisterForTest = 150;
4512 10 : std::ostringstream os;
4513 15 : os << "function " << InterpreterTester::function_name() << "(arg) {\n";
4514 5 : os << " var retval = -77;\n";
4515 755 : for (size_t i = 0; i < kMaxRegisterForTest; i++) {
4516 2250 : os << " var x" << i << " = " << i << ";\n";
4517 : }
4518 375 : for (size_t i = 0; i < kMaxRegisterForTest / 2; i++) {
4519 375 : size_t j = kMaxRegisterForTest - i - 1;
4520 750 : os << " var tmp = x" << j << ";\n";
4521 1125 : os << " var x" << j << " = x" << i << ";\n";
4522 750 : os << " var x" << i << " = tmp;\n";
4523 : }
4524 375 : for (size_t i = 0; i < kMaxRegisterForTest / 2; i++) {
4525 375 : size_t j = kMaxRegisterForTest - i - 1;
4526 750 : os << " var tmp = x" << j << ";\n";
4527 1125 : os << " var x" << j << " = x" << i << ";\n";
4528 750 : os << " var x" << i << " = tmp;\n";
4529 : }
4530 750 : for (size_t i = 0; i < kMaxRegisterForTest; i++) {
4531 1500 : os << " if (arg == " << i << ") {\n" //
4532 1500 : << " retval = x" << i << ";\n" //
4533 750 : << " }\n"; //
4534 : }
4535 5 : os << " return retval;\n";
4536 5 : os << "}\n";
4537 :
4538 : std::string source = os.str();
4539 10 : InterpreterTester tester(isolate, source.c_str());
4540 : auto callable = tester.GetCallable<Handle<Object>>();
4541 755 : for (size_t i = 0; i < kMaxRegisterForTest; i++) {
4542 750 : Handle<Object> arg = handle(Smi::FromInt(static_cast<int>(i)), isolate);
4543 : Handle<Object> return_value = callable(arg).ToHandleChecked();
4544 750 : CHECK(return_value->SameValue(*arg));
4545 5 : }
4546 5 : }
4547 :
4548 25880 : TEST(InterpreterCallWideRegisters) {
4549 : static const int kPeriod = 25;
4550 : static const int kLength = 512;
4551 : static const int kStartChar = 65;
4552 :
4553 5 : HandleAndZoneScope handles;
4554 5 : Isolate* isolate = handles.main_isolate();
4555 :
4556 20 : for (int pass = 0; pass < 3; pass += 1) {
4557 15 : std::ostringstream os;
4558 1470 : for (int i = 0; i < pass * 97; i += 1) {
4559 1455 : os << "var x" << i << " = " << i << "\n";
4560 : }
4561 15 : os << "return String.fromCharCode(";
4562 15 : os << kStartChar;
4563 7680 : for (int i = 1; i < kLength; i += 1) {
4564 7665 : os << "," << kStartChar + (i % kPeriod);
4565 : }
4566 15 : os << ");";
4567 30 : std::string source = InterpreterTester::SourceForBody(os.str().c_str());
4568 30 : InterpreterTester tester(isolate, source.c_str());
4569 : auto callable = tester.GetCallable();
4570 15 : Handle<Object> return_val = callable().ToHandleChecked();
4571 15 : Handle<String> return_string = Handle<String>::cast(return_val);
4572 15 : CHECK_EQ(return_string->length(), kLength);
4573 7680 : for (int i = 0; i < kLength; i += 1) {
4574 23040 : CHECK_EQ(return_string->Get(i), 65 + (i % kPeriod));
4575 : }
4576 20 : }
4577 5 : }
4578 :
4579 25880 : TEST(InterpreterWideParametersPickOne) {
4580 5 : HandleAndZoneScope handles;
4581 5 : Isolate* isolate = handles.main_isolate();
4582 : static const int kParameterCount = 130;
4583 55 : for (int parameter = 0; parameter < 10; parameter++) {
4584 50 : std::ostringstream os;
4585 150 : os << "function " << InterpreterTester::function_name() << "(arg) {\n";
4586 50 : os << " function selector(i";
4587 6550 : for (int i = 0; i < kParameterCount; i++) {
4588 6500 : os << ","
4589 6500 : << "a" << i;
4590 : }
4591 50 : os << ") {\n";
4592 50 : os << " return a" << parameter << ";\n";
4593 50 : os << " };\n";
4594 50 : os << " return selector(arg";
4595 6550 : for (int i = 0; i < kParameterCount; i++) {
4596 6500 : os << "," << i;
4597 : }
4598 50 : os << ");";
4599 50 : os << "}\n";
4600 :
4601 : std::string source = os.str();
4602 100 : InterpreterTester tester(isolate, source.c_str(), "*");
4603 : auto callable = tester.GetCallable<Handle<Object>>();
4604 : Handle<Object> arg = handle(Smi::FromInt(0xAA55), isolate);
4605 50 : Handle<Object> return_value = callable(arg).ToHandleChecked();
4606 50 : Handle<Smi> actual = Handle<Smi>::cast(return_value);
4607 50 : CHECK_EQ(actual->value(), parameter);
4608 55 : }
4609 5 : }
4610 :
4611 25880 : TEST(InterpreterWideParametersSummation) {
4612 : static int kParameterCount = 200;
4613 : static int kBaseValue = 17000;
4614 5 : HandleAndZoneScope handles;
4615 5 : Isolate* isolate = handles.main_isolate();
4616 10 : std::ostringstream os;
4617 15 : os << "function " << InterpreterTester::function_name() << "(arg) {\n";
4618 5 : os << " function summation(i";
4619 1005 : for (int i = 0; i < kParameterCount; i++) {
4620 1000 : os << ","
4621 1000 : << "a" << i;
4622 : }
4623 5 : os << ") {\n";
4624 5 : os << " var sum = " << kBaseValue << ";\n";
4625 5 : os << " switch(i) {\n";
4626 1005 : for (int i = 0; i < kParameterCount; i++) {
4627 1000 : int j = kParameterCount - i - 1;
4628 1000 : os << " case " << j << ": sum += a" << j << ";\n";
4629 : }
4630 5 : os << " }\n";
4631 5 : os << " return sum;\n";
4632 5 : os << " };\n";
4633 5 : os << " return summation(arg";
4634 1005 : for (int i = 0; i < kParameterCount; i++) {
4635 1000 : os << "," << i;
4636 : }
4637 5 : os << ");";
4638 5 : os << "}\n";
4639 :
4640 : std::string source = os.str();
4641 10 : InterpreterTester tester(isolate, source.c_str(), "*");
4642 : auto callable = tester.GetCallable<Handle<Object>>();
4643 1010 : for (int i = 0; i < kParameterCount; i++) {
4644 : Handle<Object> arg = handle(Smi::FromInt(i), isolate);
4645 1000 : Handle<Object> return_value = callable(arg).ToHandleChecked();
4646 1000 : int expected = kBaseValue + i * (i + 1) / 2;
4647 1000 : Handle<Smi> actual = Handle<Smi>::cast(return_value);
4648 1000 : CHECK_EQ(actual->value(), expected);
4649 5 : }
4650 5 : }
4651 :
4652 25880 : TEST(InterpreterWithStatement) {
4653 5 : HandleAndZoneScope handles;
4654 5 : Isolate* isolate = handles.main_isolate();
4655 :
4656 : std::pair<const char*, Handle<Object>> with_stmt[] = {
4657 : {"with({x:42}) return x;", handle(Smi::FromInt(42), isolate)},
4658 : {"with({}) { var y = 10; return y;}", handle(Smi::FromInt(10), isolate)},
4659 : {"var y = {x:42};"
4660 : " function inner() {"
4661 : " var x = 20;"
4662 : " with(y) return x;"
4663 : "}"
4664 : "return inner();",
4665 : handle(Smi::FromInt(42), isolate)},
4666 : {"var y = {x:42};"
4667 : " function inner(o) {"
4668 : " var x = 20;"
4669 : " with(o) return x;"
4670 : "}"
4671 : "return inner(y);",
4672 : handle(Smi::FromInt(42), isolate)},
4673 : };
4674 :
4675 25 : for (size_t i = 0; i < arraysize(with_stmt); i++) {
4676 20 : std::string source(InterpreterTester::SourceForBody(with_stmt[i].first));
4677 40 : InterpreterTester tester(isolate, source.c_str());
4678 : auto callable = tester.GetCallable<>();
4679 :
4680 : Handle<i::Object> return_value = callable().ToHandleChecked();
4681 40 : CHECK(return_value->SameValue(*with_stmt[i].second));
4682 5 : }
4683 5 : }
4684 :
4685 25880 : TEST(InterpreterClassLiterals) {
4686 5 : HandleAndZoneScope handles;
4687 5 : Isolate* isolate = handles.main_isolate();
4688 : std::pair<const char*, Handle<Object>> examples[] = {
4689 : {"class C {\n"
4690 : " constructor(x) { this.x_ = x; }\n"
4691 : " method() { return this.x_; }\n"
4692 : "}\n"
4693 : "return new C(99).method();",
4694 : handle(Smi::FromInt(99), isolate)},
4695 : {"class C {\n"
4696 : " constructor(x) { this.x_ = x; }\n"
4697 : " static static_method(x) { return x; }\n"
4698 : "}\n"
4699 : "return C.static_method(101);",
4700 : handle(Smi::FromInt(101), isolate)},
4701 : {"class C {\n"
4702 : " get x() { return 102; }\n"
4703 : "}\n"
4704 : "return new C().x",
4705 : handle(Smi::FromInt(102), isolate)},
4706 : {"class C {\n"
4707 : " static get x() { return 103; }\n"
4708 : "}\n"
4709 : "return C.x",
4710 : handle(Smi::FromInt(103), isolate)},
4711 : {"class C {\n"
4712 : " constructor() { this.x_ = 0; }"
4713 : " set x(value) { this.x_ = value; }\n"
4714 : " get x() { return this.x_; }\n"
4715 : "}\n"
4716 : "var c = new C();"
4717 : "c.x = 104;"
4718 : "return c.x;",
4719 : handle(Smi::FromInt(104), isolate)},
4720 : {"var x = 0;"
4721 : "class C {\n"
4722 : " static set x(value) { x = value; }\n"
4723 : " static get x() { return x; }\n"
4724 : "}\n"
4725 : "C.x = 105;"
4726 : "return C.x;",
4727 : handle(Smi::FromInt(105), isolate)},
4728 : {"var method = 'f';"
4729 : "class C {\n"
4730 : " [method]() { return 106; }\n"
4731 : "}\n"
4732 : "return new C().f();",
4733 : handle(Smi::FromInt(106), isolate)},
4734 : };
4735 :
4736 40 : for (size_t i = 0; i < arraysize(examples); ++i) {
4737 35 : std::string source(InterpreterTester::SourceForBody(examples[i].first));
4738 70 : InterpreterTester tester(isolate, source.c_str(), "*");
4739 : auto callable = tester.GetCallable<>();
4740 :
4741 : Handle<i::Object> return_value = callable().ToHandleChecked();
4742 70 : CHECK(return_value->SameValue(*examples[i].second));
4743 5 : }
4744 5 : }
4745 :
4746 25880 : TEST(InterpreterClassAndSuperClass) {
4747 5 : HandleAndZoneScope handles;
4748 5 : Isolate* isolate = handles.main_isolate();
4749 : std::pair<const char*, Handle<Object>> examples[] = {
4750 : {"class A {\n"
4751 : " constructor(x) { this.x_ = x; }\n"
4752 : " method() { return this.x_; }\n"
4753 : "}\n"
4754 : "class B extends A {\n"
4755 : " constructor(x, y) { super(x); this.y_ = y; }\n"
4756 : " method() { return super.method() + 1; }\n"
4757 : "}\n"
4758 : "return new B(998, 0).method();\n",
4759 : handle(Smi::FromInt(999), isolate)},
4760 : {"class A {\n"
4761 : " constructor() { this.x_ = 2; this.y_ = 3; }\n"
4762 : "}\n"
4763 : "class B extends A {\n"
4764 : " constructor() { super(); }"
4765 : " method() { this.x_++; this.y_++; return this.x_ + this.y_; }\n"
4766 : "}\n"
4767 : "return new B().method();\n",
4768 : handle(Smi::FromInt(7), isolate)},
4769 : {"var calls = 0;\n"
4770 : "class B {}\n"
4771 : "B.prototype.x = 42;\n"
4772 : "class C extends B {\n"
4773 : " constructor() {\n"
4774 : " super();\n"
4775 : " calls++;\n"
4776 : " }\n"
4777 : "}\n"
4778 : "new C;\n"
4779 : "return calls;\n",
4780 : handle(Smi::FromInt(1), isolate)},
4781 : {"class A {\n"
4782 : " method() { return 1; }\n"
4783 : " get x() { return 2; }\n"
4784 : "}\n"
4785 : "class B extends A {\n"
4786 : " method() { return super.x === 2 ? super.method() : -1; }\n"
4787 : "}\n"
4788 : "return new B().method();\n",
4789 : handle(Smi::FromInt(1), isolate)},
4790 : {"var object = { setY(v) { super.y = v; }};\n"
4791 : "object.setY(10);\n"
4792 : "return object.y;\n",
4793 : handle(Smi::FromInt(10), isolate)},
4794 : };
4795 :
4796 30 : for (size_t i = 0; i < arraysize(examples); ++i) {
4797 25 : std::string source(InterpreterTester::SourceForBody(examples[i].first));
4798 50 : InterpreterTester tester(isolate, source.c_str(), "*");
4799 : auto callable = tester.GetCallable<>();
4800 : Handle<i::Object> return_value = callable().ToHandleChecked();
4801 50 : CHECK(return_value->SameValue(*examples[i].second));
4802 5 : }
4803 5 : }
4804 :
4805 25880 : TEST(InterpreterConstDeclaration) {
4806 5 : HandleAndZoneScope handles;
4807 5 : Isolate* isolate = handles.main_isolate();
4808 : Factory* factory = isolate->factory();
4809 :
4810 : std::pair<const char*, Handle<Object>> const_decl[] = {
4811 : {"const x = 3; return x;", handle(Smi::FromInt(3), isolate)},
4812 : {"let x = 10; x = x + 20; return x;", handle(Smi::FromInt(30), isolate)},
4813 : {"let x = 10; x = 20; return x;", handle(Smi::FromInt(20), isolate)},
4814 : {"let x; x = 20; return x;", handle(Smi::FromInt(20), isolate)},
4815 : {"let x; return x;", factory->undefined_value()},
4816 : {"var x = 10; { let x = 30; } return x;",
4817 : handle(Smi::FromInt(10), isolate)},
4818 : {"let x = 10; { let x = 20; } return x;",
4819 : handle(Smi::FromInt(10), isolate)},
4820 : {"var x = 10; eval('let x = 20;'); return x;",
4821 : handle(Smi::FromInt(10), isolate)},
4822 : {"var x = 10; eval('const x = 20;'); return x;",
4823 : handle(Smi::FromInt(10), isolate)},
4824 : {"var x = 10; { const x = 20; } return x;",
4825 : handle(Smi::FromInt(10), isolate)},
4826 : {"var x = 10; { const x = 20; return x;} return -1;",
4827 : handle(Smi::FromInt(20), isolate)},
4828 : {"var a = 10;\n"
4829 : "for (var i = 0; i < 10; ++i) {\n"
4830 : " const x = i;\n" // const declarations are block scoped.
4831 : " a = a + x;\n"
4832 : "}\n"
4833 : "return a;\n",
4834 : handle(Smi::FromInt(55), isolate)},
4835 : };
4836 :
4837 : // Tests for sloppy mode.
4838 65 : for (size_t i = 0; i < arraysize(const_decl); i++) {
4839 60 : std::string source(InterpreterTester::SourceForBody(const_decl[i].first));
4840 120 : InterpreterTester tester(isolate, source.c_str());
4841 : auto callable = tester.GetCallable<>();
4842 :
4843 : Handle<i::Object> return_value = callable().ToHandleChecked();
4844 120 : CHECK(return_value->SameValue(*const_decl[i].second));
4845 : }
4846 :
4847 : // Tests for strict mode.
4848 60 : for (size_t i = 0; i < arraysize(const_decl); i++) {
4849 : std::string strict_body =
4850 120 : "'use strict'; " + std::string(const_decl[i].first);
4851 60 : std::string source(InterpreterTester::SourceForBody(strict_body.c_str()));
4852 120 : InterpreterTester tester(isolate, source.c_str());
4853 : auto callable = tester.GetCallable<>();
4854 :
4855 : Handle<i::Object> return_value = callable().ToHandleChecked();
4856 120 : CHECK(return_value->SameValue(*const_decl[i].second));
4857 5 : }
4858 5 : }
4859 :
4860 25880 : TEST(InterpreterConstDeclarationLookupSlots) {
4861 5 : HandleAndZoneScope handles;
4862 5 : Isolate* isolate = handles.main_isolate();
4863 : Factory* factory = isolate->factory();
4864 :
4865 : std::pair<const char*, Handle<Object>> const_decl[] = {
4866 : {"const x = 3; function f1() {return x;}; return x;",
4867 : handle(Smi::FromInt(3), isolate)},
4868 : {"let x = 10; x = x + 20; function f1() {return x;}; return x;",
4869 : handle(Smi::FromInt(30), isolate)},
4870 : {"let x; x = 20; function f1() {return x;}; return x;",
4871 : handle(Smi::FromInt(20), isolate)},
4872 : {"let x; function f1() {return x;}; return x;",
4873 : factory->undefined_value()},
4874 : };
4875 :
4876 : // Tests for sloppy mode.
4877 25 : for (size_t i = 0; i < arraysize(const_decl); i++) {
4878 20 : std::string source(InterpreterTester::SourceForBody(const_decl[i].first));
4879 40 : InterpreterTester tester(isolate, source.c_str());
4880 : auto callable = tester.GetCallable<>();
4881 :
4882 : Handle<i::Object> return_value = callable().ToHandleChecked();
4883 40 : CHECK(return_value->SameValue(*const_decl[i].second));
4884 : }
4885 :
4886 : // Tests for strict mode.
4887 20 : for (size_t i = 0; i < arraysize(const_decl); i++) {
4888 : std::string strict_body =
4889 40 : "'use strict'; " + std::string(const_decl[i].first);
4890 20 : std::string source(InterpreterTester::SourceForBody(strict_body.c_str()));
4891 40 : InterpreterTester tester(isolate, source.c_str());
4892 : auto callable = tester.GetCallable<>();
4893 :
4894 : Handle<i::Object> return_value = callable().ToHandleChecked();
4895 40 : CHECK(return_value->SameValue(*const_decl[i].second));
4896 5 : }
4897 5 : }
4898 :
4899 25880 : TEST(InterpreterConstInLookupContextChain) {
4900 5 : HandleAndZoneScope handles;
4901 5 : Isolate* isolate = handles.main_isolate();
4902 :
4903 : const char* prologue =
4904 : "function OuterMost() {\n"
4905 : " const outerConst = 10;\n"
4906 : " let outerLet = 20;\n"
4907 : " function Outer() {\n"
4908 : " function Inner() {\n"
4909 : " this.innerFunc = function() { ";
4910 : const char* epilogue =
4911 : " }\n"
4912 : " }\n"
4913 : " this.getInnerFunc ="
4914 : " function() {return new Inner().innerFunc;}\n"
4915 : " }\n"
4916 : " this.getOuterFunc ="
4917 : " function() {return new Outer().getInnerFunc();}"
4918 : "}\n"
4919 : "var f = new OuterMost().getOuterFunc();\n"
4920 : "f();\n";
4921 : std::pair<const char*, Handle<Object>> const_decl[] = {
4922 : {"return outerConst;", handle(Smi::FromInt(10), isolate)},
4923 : {"return outerLet;", handle(Smi::FromInt(20), isolate)},
4924 : {"outerLet = 30; return outerLet;", handle(Smi::FromInt(30), isolate)},
4925 : {"var outerLet = 40; return outerLet;",
4926 : handle(Smi::FromInt(40), isolate)},
4927 : {"var outerConst = 50; return outerConst;",
4928 : handle(Smi::FromInt(50), isolate)},
4929 : {"try { outerConst = 30 } catch(e) { return -1; }",
4930 : handle(Smi::FromInt(-1), isolate)}};
4931 :
4932 35 : for (size_t i = 0; i < arraysize(const_decl); i++) {
4933 120 : std::string script = std::string(prologue) +
4934 : std::string(const_decl[i].first) +
4935 90 : std::string(epilogue);
4936 60 : InterpreterTester tester(isolate, script.c_str(), "*");
4937 : auto callable = tester.GetCallable<>();
4938 :
4939 : Handle<i::Object> return_value = callable().ToHandleChecked();
4940 60 : CHECK(return_value->SameValue(*const_decl[i].second));
4941 5 : }
4942 5 : }
4943 :
4944 25880 : TEST(InterpreterIllegalConstDeclaration) {
4945 5 : HandleAndZoneScope handles;
4946 5 : Isolate* isolate = handles.main_isolate();
4947 :
4948 : std::pair<const char*, const char*> const_decl[] = {
4949 : {"const x = x = 10 + 3; return x;",
4950 : "Uncaught ReferenceError: Cannot access 'x' before initialization"},
4951 : {"const x = 10; x = 20; return x;",
4952 : "Uncaught TypeError: Assignment to constant variable."},
4953 : {"const x = 10; { x = 20; } return x;",
4954 : "Uncaught TypeError: Assignment to constant variable."},
4955 : {"const x = 10; eval('x = 20;'); return x;",
4956 : "Uncaught TypeError: Assignment to constant variable."},
4957 : {"let x = x + 10; return x;",
4958 : "Uncaught ReferenceError: Cannot access 'x' before initialization"},
4959 : {"'use strict'; (function f1() { f1 = 123; })() ",
4960 : "Uncaught TypeError: Assignment to constant variable."},
4961 5 : };
4962 :
4963 : // Tests for sloppy mode.
4964 35 : for (size_t i = 0; i < arraysize(const_decl); i++) {
4965 30 : std::string source(InterpreterTester::SourceForBody(const_decl[i].first));
4966 60 : InterpreterTester tester(isolate, source.c_str());
4967 60 : v8::Local<v8::String> message = tester.CheckThrowsReturnMessage()->Get();
4968 30 : v8::Local<v8::String> expected_string = v8_str(const_decl[i].second);
4969 90 : CHECK(
4970 : message->Equals(CcTest::isolate()->GetCurrentContext(), expected_string)
4971 : .FromJust());
4972 : }
4973 :
4974 : // Tests for strict mode.
4975 30 : for (size_t i = 0; i < arraysize(const_decl); i++) {
4976 : std::string strict_body =
4977 60 : "'use strict'; " + std::string(const_decl[i].first);
4978 30 : std::string source(InterpreterTester::SourceForBody(strict_body.c_str()));
4979 60 : InterpreterTester tester(isolate, source.c_str());
4980 60 : v8::Local<v8::String> message = tester.CheckThrowsReturnMessage()->Get();
4981 30 : v8::Local<v8::String> expected_string = v8_str(const_decl[i].second);
4982 90 : CHECK(
4983 : message->Equals(CcTest::isolate()->GetCurrentContext(), expected_string)
4984 : .FromJust());
4985 5 : }
4986 5 : }
4987 :
4988 25880 : TEST(InterpreterGenerators) {
4989 5 : HandleAndZoneScope handles;
4990 5 : Isolate* isolate = handles.main_isolate();
4991 : Factory* factory = isolate->factory();
4992 :
4993 : std::pair<const char*, Handle<Object>> tests[] = {
4994 : {"function* f() { }; return f().next().value",
4995 : factory->undefined_value()},
4996 : {"function* f() { yield 42 }; return f().next().value",
4997 : factory->NewNumberFromInt(42)},
4998 : {"function* f() { for (let x of [42]) yield x}; return f().next().value",
4999 : factory->NewNumberFromInt(42)},
5000 15 : };
5001 :
5002 20 : for (size_t i = 0; i < arraysize(tests); i++) {
5003 15 : std::string source(InterpreterTester::SourceForBody(tests[i].first));
5004 30 : InterpreterTester tester(isolate, source.c_str());
5005 : auto callable = tester.GetCallable<>();
5006 :
5007 : Handle<i::Object> return_value = callable().ToHandleChecked();
5008 30 : CHECK(return_value->SameValue(*tests[i].second));
5009 5 : }
5010 5 : }
5011 :
5012 : #ifndef V8_TARGET_ARCH_ARM
5013 25880 : TEST(InterpreterWithNativeStack) {
5014 5 : i::FLAG_interpreted_frames_native_stack = true;
5015 :
5016 5 : HandleAndZoneScope handles;
5017 5 : i::Isolate* isolate = handles.main_isolate();
5018 :
5019 : const char* source_text =
5020 : "function testInterpreterWithNativeStack(a,b) { return a + b };";
5021 :
5022 : i::Handle<i::Object> o = v8::Utils::OpenHandle(*v8_compile(source_text));
5023 5 : i::Handle<i::JSFunction> f = i::Handle<i::JSFunction>::cast(o);
5024 :
5025 5 : CHECK(f->shared()->HasBytecodeArray());
5026 5 : i::Code code = f->shared()->GetCode();
5027 : i::Handle<i::Code> interpreter_entry_trampoline =
5028 5 : BUILTIN_CODE(isolate, InterpreterEntryTrampoline);
5029 :
5030 5 : CHECK(code->IsCode());
5031 5 : CHECK(code->is_interpreter_trampoline_builtin());
5032 5 : CHECK_NE(code->address(), interpreter_entry_trampoline->address());
5033 5 : }
5034 : #endif // V8_TARGET_ARCH_ARM
5035 :
5036 25880 : TEST(InterpreterGetBytecodeHandler) {
5037 5 : HandleAndZoneScope handles;
5038 5 : Isolate* isolate = handles.main_isolate();
5039 : Interpreter* interpreter = isolate->interpreter();
5040 :
5041 : // Test that single-width bytecode handlers deserializer correctly.
5042 : Code wide_handler =
5043 5 : interpreter->GetBytecodeHandler(Bytecode::kWide, OperandScale::kSingle);
5044 :
5045 5 : CHECK_EQ(wide_handler->builtin_index(), Builtins::kWideHandler);
5046 :
5047 : Code add_handler =
5048 5 : interpreter->GetBytecodeHandler(Bytecode::kAdd, OperandScale::kSingle);
5049 :
5050 5 : CHECK_EQ(add_handler->builtin_index(), Builtins::kAddHandler);
5051 :
5052 : // Test that double-width bytecode handlers deserializer correctly, including
5053 : // an illegal bytecode handler since there is no Wide.Wide handler.
5054 : Code wide_wide_handler =
5055 5 : interpreter->GetBytecodeHandler(Bytecode::kWide, OperandScale::kDouble);
5056 :
5057 5 : CHECK_EQ(wide_wide_handler->builtin_index(), Builtins::kIllegalHandler);
5058 :
5059 : Code add_wide_handler =
5060 5 : interpreter->GetBytecodeHandler(Bytecode::kAdd, OperandScale::kDouble);
5061 :
5062 5 : CHECK_EQ(add_wide_handler->builtin_index(), Builtins::kAddWideHandler);
5063 5 : }
5064 :
5065 25880 : TEST(InterpreterCollectSourcePositions) {
5066 5 : FLAG_enable_lazy_source_positions = true;
5067 5 : HandleAndZoneScope handles;
5068 5 : Isolate* isolate = handles.main_isolate();
5069 :
5070 : const char* source =
5071 : "(function () {\n"
5072 : " return 1;\n"
5073 : "})";
5074 :
5075 : Handle<JSFunction> function = Handle<JSFunction>::cast(v8::Utils::OpenHandle(
5076 5 : *v8::Local<v8::Function>::Cast(CompileRun(source))));
5077 :
5078 10 : Handle<SharedFunctionInfo> sfi = handle(function->shared(), isolate);
5079 : Handle<BytecodeArray> bytecode_array =
5080 10 : handle(sfi->GetBytecodeArray(), isolate);
5081 5 : ByteArray source_position_table = bytecode_array->SourcePositionTable();
5082 5 : CHECK_EQ(source_position_table->length(), 0);
5083 :
5084 5 : Compiler::CollectSourcePositions(isolate, sfi);
5085 :
5086 5 : source_position_table = bytecode_array->SourcePositionTable();
5087 5 : CHECK_GT(source_position_table->length(), 0);
5088 5 : }
5089 :
5090 : namespace {
5091 :
5092 5 : void CheckStringEqual(const char* expected_ptr, Handle<Object> actual_handle) {
5093 : v8::String::Utf8Value utf8(
5094 : v8::Isolate::GetCurrent(),
5095 10 : v8::Utils::ToLocal(Handle<String>::cast(actual_handle)));
5096 5 : std::string expected(expected_ptr);
5097 5 : std::string actual(*utf8);
5098 10 : CHECK_EQ(expected, actual);
5099 5 : }
5100 :
5101 : } // namespace
5102 :
5103 25880 : TEST(InterpreterCollectSourcePositions_GenerateStackTrace) {
5104 5 : FLAG_enable_lazy_source_positions = true;
5105 5 : HandleAndZoneScope handles;
5106 5 : Isolate* isolate = handles.main_isolate();
5107 :
5108 : const char* source =
5109 : R"javascript(
5110 : (function () {
5111 : try {
5112 : throw new Error();
5113 : } catch (e) {
5114 : return e.stack;
5115 : }
5116 : });
5117 : )javascript";
5118 :
5119 : Handle<JSFunction> function = Handle<JSFunction>::cast(v8::Utils::OpenHandle(
5120 5 : *v8::Local<v8::Function>::Cast(CompileRun(source))));
5121 :
5122 10 : Handle<SharedFunctionInfo> sfi = handle(function->shared(), isolate);
5123 : Handle<BytecodeArray> bytecode_array =
5124 10 : handle(sfi->GetBytecodeArray(), isolate);
5125 5 : ByteArray source_position_table = bytecode_array->SourcePositionTable();
5126 5 : CHECK_EQ(source_position_table->length(), 0);
5127 :
5128 : {
5129 : Handle<Object> result =
5130 : Execution::Call(isolate, function,
5131 : ReadOnlyRoots(isolate).undefined_value_handle(), 0,
5132 5 : nullptr)
5133 10 : .ToHandleChecked();
5134 5 : CheckStringEqual("Error\n at <anonymous>:4:17", result);
5135 : }
5136 :
5137 5 : source_position_table = bytecode_array->SourcePositionTable();
5138 5 : CHECK_GT(source_position_table->length(), 0);
5139 5 : }
5140 :
5141 : } // namespace interpreter
5142 : } // namespace internal
5143 77625 : } // namespace v8
|