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