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