blob: 506cf00cd045dc91af041451c8a613608852c793 [file] [log] [blame]
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001// 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 "src/v8.h"
6
7#include "src/execution.h"
8#include "src/handles.h"
9#include "src/interpreter/bytecode-array-builder.h"
10#include "src/interpreter/interpreter.h"
11#include "test/cctest/cctest.h"
12#include "test/cctest/test-feedback-vector.h"
13
14namespace v8 {
15namespace internal {
16namespace interpreter {
17
18
19static MaybeHandle<Object> CallInterpreter(Isolate* isolate,
20 Handle<JSFunction> function) {
21 return Execution::Call(isolate, function,
22 isolate->factory()->undefined_value(), 0, nullptr);
23}
24
25
26template <class... A>
27static MaybeHandle<Object> CallInterpreter(Isolate* isolate,
28 Handle<JSFunction> function,
29 A... args) {
30 Handle<Object> argv[] = { args... };
31 return Execution::Call(isolate, function,
32 isolate->factory()->undefined_value(), sizeof...(args),
33 argv);
34}
35
36
37template <class... A>
38class InterpreterCallable {
39 public:
40 InterpreterCallable(Isolate* isolate, Handle<JSFunction> function)
41 : isolate_(isolate), function_(function) {}
42 virtual ~InterpreterCallable() {}
43
44 MaybeHandle<Object> operator()(A... args) {
45 return CallInterpreter(isolate_, function_, args...);
46 }
47
48 private:
49 Isolate* isolate_;
50 Handle<JSFunction> function_;
51};
52
53
54static const char* kFunctionName = "f";
55
56
57class InterpreterTester {
58 public:
59 InterpreterTester(Isolate* isolate, const char* source,
60 MaybeHandle<BytecodeArray> bytecode,
61 MaybeHandle<TypeFeedbackVector> feedback_vector,
62 const char* filter)
63 : isolate_(isolate),
64 source_(source),
65 bytecode_(bytecode),
66 feedback_vector_(feedback_vector) {
67 i::FLAG_ignition = true;
68 i::FLAG_ignition_fake_try_catch = true;
69 i::FLAG_ignition_fallback_on_eval_and_catch = false;
70 i::FLAG_always_opt = false;
71 // Set ignition filter flag via SetFlagsFromString to avoid double-free
72 // (or potential leak with StrDup() based on ownership confusion).
73 ScopedVector<char> ignition_filter(64);
74 SNPrintF(ignition_filter, "--ignition-filter=%s", filter);
75 FlagList::SetFlagsFromString(ignition_filter.start(),
76 ignition_filter.length());
77 // Ensure handler table is generated.
78 isolate->interpreter()->Initialize();
79 }
80
81 InterpreterTester(Isolate* isolate, Handle<BytecodeArray> bytecode,
82 MaybeHandle<TypeFeedbackVector> feedback_vector =
83 MaybeHandle<TypeFeedbackVector>(),
84 const char* filter = kFunctionName)
85 : InterpreterTester(isolate, nullptr, bytecode, feedback_vector, filter) {
86 }
87
88
89 InterpreterTester(Isolate* isolate, const char* source,
90 const char* filter = kFunctionName)
91 : InterpreterTester(isolate, source, MaybeHandle<BytecodeArray>(),
92 MaybeHandle<TypeFeedbackVector>(), filter) {}
93
94 virtual ~InterpreterTester() {}
95
96 template <class... A>
97 InterpreterCallable<A...> GetCallable() {
98 return InterpreterCallable<A...>(isolate_, GetBytecodeFunction<A...>());
99 }
100
101 static Handle<Object> NewObject(const char* script) {
102 return v8::Utils::OpenHandle(*CompileRun(script));
103 }
104
105 static Handle<String> GetName(Isolate* isolate, const char* name) {
106 Handle<String> result = isolate->factory()->NewStringFromAsciiChecked(name);
107 return isolate->factory()->string_table()->LookupString(isolate, result);
108 }
109
110 static std::string SourceForBody(const char* body) {
111 return "function " + function_name() + "() {\n" + std::string(body) + "\n}";
112 }
113
114 static std::string function_name() {
115 return std::string(kFunctionName);
116 }
117
118 private:
119 Isolate* isolate_;
120 const char* source_;
121 MaybeHandle<BytecodeArray> bytecode_;
122 MaybeHandle<TypeFeedbackVector> feedback_vector_;
123
124 template <class... A>
125 Handle<JSFunction> GetBytecodeFunction() {
126 Handle<JSFunction> function;
127 if (source_) {
128 CompileRun(source_);
129 v8::Local<v8::Context> context =
130 v8::Isolate::GetCurrent()->GetCurrentContext();
131 Local<Function> api_function =
132 Local<Function>::Cast(CcTest::global()
133 ->Get(context, v8_str(kFunctionName))
134 .ToLocalChecked());
135 function = Handle<JSFunction>::cast(v8::Utils::OpenHandle(*api_function));
136 } else {
137 int arg_count = sizeof...(A);
138 std::string source("(function " + function_name() + "(");
139 for (int i = 0; i < arg_count; i++) {
140 source += i == 0 ? "a" : ", a";
141 }
142 source += "){})";
143 function = Handle<JSFunction>::cast(v8::Utils::OpenHandle(
144 *v8::Local<v8::Function>::Cast(CompileRun(source.c_str()))));
145 function->ReplaceCode(
146 *isolate_->builtins()->InterpreterEntryTrampoline());
147 }
148
149 if (!bytecode_.is_null()) {
150 function->shared()->set_function_data(*bytecode_.ToHandleChecked());
151 }
152 if (!feedback_vector_.is_null()) {
153 function->shared()->set_feedback_vector(
154 *feedback_vector_.ToHandleChecked());
155 }
156 return function;
157 }
158
159 DISALLOW_COPY_AND_ASSIGN(InterpreterTester);
160};
161
162
163TEST(InterpreterReturn) {
164 HandleAndZoneScope handles;
165 Handle<Object> undefined_value =
166 handles.main_isolate()->factory()->undefined_value();
167
168 BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
169 builder.set_locals_count(0);
170 builder.set_context_count(0);
171 builder.set_parameter_count(1);
172 builder.Return();
173 Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
174
175 InterpreterTester tester(handles.main_isolate(), bytecode_array);
176 auto callable = tester.GetCallable<>();
177 Handle<Object> return_val = callable().ToHandleChecked();
178 CHECK(return_val.is_identical_to(undefined_value));
179}
180
181
182TEST(InterpreterLoadUndefined) {
183 HandleAndZoneScope handles;
184 Handle<Object> undefined_value =
185 handles.main_isolate()->factory()->undefined_value();
186
187 BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
188 builder.set_locals_count(0);
189 builder.set_context_count(0);
190 builder.set_parameter_count(1);
191 builder.LoadUndefined().Return();
192 Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
193
194 InterpreterTester tester(handles.main_isolate(), bytecode_array);
195 auto callable = tester.GetCallable<>();
196 Handle<Object> return_val = callable().ToHandleChecked();
197 CHECK(return_val.is_identical_to(undefined_value));
198}
199
200
201TEST(InterpreterLoadNull) {
202 HandleAndZoneScope handles;
203 Handle<Object> null_value = handles.main_isolate()->factory()->null_value();
204
205 BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
206 builder.set_locals_count(0);
207 builder.set_context_count(0);
208 builder.set_parameter_count(1);
209 builder.LoadNull().Return();
210 Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
211
212 InterpreterTester tester(handles.main_isolate(), bytecode_array);
213 auto callable = tester.GetCallable<>();
214 Handle<Object> return_val = callable().ToHandleChecked();
215 CHECK(return_val.is_identical_to(null_value));
216}
217
218
219TEST(InterpreterLoadTheHole) {
220 HandleAndZoneScope handles;
221 Handle<Object> the_hole_value =
222 handles.main_isolate()->factory()->the_hole_value();
223
224 BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
225 builder.set_locals_count(0);
226 builder.set_context_count(0);
227 builder.set_parameter_count(1);
228 builder.LoadTheHole().Return();
229 Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
230
231 InterpreterTester tester(handles.main_isolate(), bytecode_array);
232 auto callable = tester.GetCallable<>();
233 Handle<Object> return_val = callable().ToHandleChecked();
234 CHECK(return_val.is_identical_to(the_hole_value));
235}
236
237
238TEST(InterpreterLoadTrue) {
239 HandleAndZoneScope handles;
240 Handle<Object> true_value = handles.main_isolate()->factory()->true_value();
241
242 BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
243 builder.set_locals_count(0);
244 builder.set_context_count(0);
245 builder.set_parameter_count(1);
246 builder.LoadTrue().Return();
247 Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
248
249 InterpreterTester tester(handles.main_isolate(), bytecode_array);
250 auto callable = tester.GetCallable<>();
251 Handle<Object> return_val = callable().ToHandleChecked();
252 CHECK(return_val.is_identical_to(true_value));
253}
254
255
256TEST(InterpreterLoadFalse) {
257 HandleAndZoneScope handles;
258 Handle<Object> false_value = handles.main_isolate()->factory()->false_value();
259
260 BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
261 builder.set_locals_count(0);
262 builder.set_context_count(0);
263 builder.set_parameter_count(1);
264 builder.LoadFalse().Return();
265 Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
266
267 InterpreterTester tester(handles.main_isolate(), bytecode_array);
268 auto callable = tester.GetCallable<>();
269 Handle<Object> return_val = callable().ToHandleChecked();
270 CHECK(return_val.is_identical_to(false_value));
271}
272
273
274TEST(InterpreterLoadLiteral) {
275 HandleAndZoneScope handles;
276 i::Factory* factory = handles.main_isolate()->factory();
277
278 // Small Smis.
279 for (int i = -128; i < 128; i++) {
280 BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
281 builder.set_locals_count(0);
282 builder.set_context_count(0);
283 builder.set_parameter_count(1);
284 builder.LoadLiteral(Smi::FromInt(i)).Return();
285 Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
286
287 InterpreterTester tester(handles.main_isolate(), bytecode_array);
288 auto callable = tester.GetCallable<>();
289 Handle<Object> return_val = callable().ToHandleChecked();
290 CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(i));
291 }
292
293 // Large Smis.
294 {
295 BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
296 builder.set_locals_count(0);
297 builder.set_context_count(0);
298 builder.set_parameter_count(1);
299 builder.LoadLiteral(Smi::FromInt(0x12345678)).Return();
300 Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
301
302 InterpreterTester tester(handles.main_isolate(), bytecode_array);
303 auto callable = tester.GetCallable<>();
304 Handle<Object> return_val = callable().ToHandleChecked();
305 CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(0x12345678));
306 }
307
308 // Heap numbers.
309 {
310 BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
311 builder.set_locals_count(0);
312 builder.set_context_count(0);
313 builder.set_parameter_count(1);
314 builder.LoadLiteral(factory->NewHeapNumber(-2.1e19)).Return();
315 Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
316
317 InterpreterTester tester(handles.main_isolate(), bytecode_array);
318 auto callable = tester.GetCallable<>();
319 Handle<Object> return_val = callable().ToHandleChecked();
320 CHECK_EQ(i::HeapNumber::cast(*return_val)->value(), -2.1e19);
321 }
322
323 // Strings.
324 {
325 BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
326 builder.set_locals_count(0);
327 builder.set_context_count(0);
328 builder.set_parameter_count(1);
329 Handle<i::String> string = factory->NewStringFromAsciiChecked("String");
330 builder.LoadLiteral(string).Return();
331 Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
332
333 InterpreterTester tester(handles.main_isolate(), bytecode_array);
334 auto callable = tester.GetCallable<>();
335 Handle<Object> return_val = callable().ToHandleChecked();
336 CHECK(i::String::cast(*return_val)->Equals(*string));
337 }
338}
339
340
341TEST(InterpreterLoadStoreRegisters) {
342 HandleAndZoneScope handles;
343 Handle<Object> true_value = handles.main_isolate()->factory()->true_value();
344 for (int i = 0; i <= kMaxInt8; i++) {
345 BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
346 builder.set_locals_count(i + 1);
347 builder.set_context_count(0);
348 builder.set_parameter_count(1);
349 Register reg(i);
350 builder.LoadTrue()
351 .StoreAccumulatorInRegister(reg)
352 .LoadFalse()
353 .LoadAccumulatorWithRegister(reg)
354 .Return();
355 Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
356
357 InterpreterTester tester(handles.main_isolate(), bytecode_array);
358 auto callable = tester.GetCallable<>();
359 Handle<Object> return_val = callable().ToHandleChecked();
360 CHECK(return_val.is_identical_to(true_value));
361 }
362}
363
364
365TEST(InterpreterExchangeRegisters) {
366 for (int locals_count = 2; locals_count < 300; locals_count += 126) {
367 HandleAndZoneScope handles;
368 for (int exchanges = 1; exchanges < 4; exchanges++) {
369 BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
370 builder.set_locals_count(locals_count);
371 builder.set_context_count(0);
372 builder.set_parameter_count(0);
373
374 Register r0(0);
375 Register r1(locals_count - 1);
376 builder.LoadTrue();
377 builder.StoreAccumulatorInRegister(r0);
378 builder.ExchangeRegisters(r0, r1);
379 builder.LoadFalse();
380 builder.StoreAccumulatorInRegister(r0);
381
382 bool expected = false;
383 for (int i = 0; i < exchanges; i++) {
384 builder.ExchangeRegisters(r0, r1);
385 expected = !expected;
386 }
387 builder.LoadAccumulatorWithRegister(r0);
388 builder.Return();
389 Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
390 InterpreterTester tester(handles.main_isolate(), bytecode_array);
391 auto callable = tester.GetCallable<>();
392 Handle<Object> return_val = callable().ToHandleChecked();
393 Handle<Object> expected_val =
394 handles.main_isolate()->factory()->ToBoolean(expected);
395 CHECK(return_val.is_identical_to(expected_val));
396 }
397 }
398}
399
400
401TEST(InterpreterExchangeRegistersWithParameter) {
402 for (int locals_count = 2; locals_count < 300; locals_count += 126) {
403 HandleAndZoneScope handles;
404 for (int exchanges = 1; exchanges < 4; exchanges++) {
405 BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
406 builder.set_locals_count(locals_count);
407 builder.set_context_count(0);
408 builder.set_parameter_count(3);
409
410 Register r0 = Register::FromParameterIndex(2, 3);
411 Register r1(locals_count - 1);
412 builder.LoadTrue();
413 builder.StoreAccumulatorInRegister(r0);
414 builder.ExchangeRegisters(r0, r1);
415 builder.LoadFalse();
416 builder.StoreAccumulatorInRegister(r0);
417
418 bool expected = false;
419 for (int i = 0; i < exchanges; i++) {
420 builder.ExchangeRegisters(r0, r1);
421 expected = !expected;
422 }
423 builder.LoadAccumulatorWithRegister(r0);
424 builder.Return();
425 Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
426 InterpreterTester tester(handles.main_isolate(), bytecode_array);
427 auto callable = tester.GetCallable<>();
428 Handle<Object> return_val = callable().ToHandleChecked();
429 Handle<Object> expected_val =
430 handles.main_isolate()->factory()->ToBoolean(expected);
431 CHECK(return_val.is_identical_to(expected_val));
432 }
433 }
434}
435
436
437TEST(InterpreterExchangeWideRegisters) {
438 for (int locals_count = 3; locals_count < 300; locals_count += 126) {
439 HandleAndZoneScope handles;
440 for (int exchanges = 0; exchanges < 7; exchanges++) {
441 BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
442 builder.set_locals_count(locals_count);
443 builder.set_context_count(0);
444 builder.set_parameter_count(0);
445
446 Register r0(0);
447 Register r1(locals_count - 1);
448 Register r2(locals_count - 2);
449 builder.LoadLiteral(Smi::FromInt(200));
450 builder.StoreAccumulatorInRegister(r0);
451 builder.ExchangeRegisters(r0, r1);
452 builder.LoadLiteral(Smi::FromInt(100));
453 builder.StoreAccumulatorInRegister(r0);
454 builder.ExchangeRegisters(r0, r2);
455 builder.LoadLiteral(Smi::FromInt(0));
456 builder.StoreAccumulatorInRegister(r0);
457 for (int i = 0; i < exchanges; i++) {
458 builder.ExchangeRegisters(r1, r2);
459 builder.ExchangeRegisters(r0, r1);
460 }
461 builder.LoadAccumulatorWithRegister(r0);
462 builder.Return();
463 Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
464 InterpreterTester tester(handles.main_isolate(), bytecode_array);
465 auto callable = tester.GetCallable<>();
466 Handle<Object> return_val = callable().ToHandleChecked();
467 Handle<Object> expected_val =
468 handles.main_isolate()->factory()->NewNumberFromInt(100 *
469 (exchanges % 3));
470 CHECK(return_val.is_identical_to(expected_val));
471 }
472 }
473}
474
475
476static const Token::Value kShiftOperators[] = {
477 Token::Value::SHL, Token::Value::SAR, Token::Value::SHR};
478
479
480static const Token::Value kArithmeticOperators[] = {
481 Token::Value::BIT_OR, Token::Value::BIT_XOR, Token::Value::BIT_AND,
482 Token::Value::SHL, Token::Value::SAR, Token::Value::SHR,
483 Token::Value::ADD, Token::Value::SUB, Token::Value::MUL,
484 Token::Value::DIV, Token::Value::MOD};
485
486
487static double BinaryOpC(Token::Value op, double lhs, double rhs) {
488 switch (op) {
489 case Token::Value::ADD:
490 return lhs + rhs;
491 case Token::Value::SUB:
492 return lhs - rhs;
493 case Token::Value::MUL:
494 return lhs * rhs;
495 case Token::Value::DIV:
496 return lhs / rhs;
497 case Token::Value::MOD:
498 return std::fmod(lhs, rhs);
499 case Token::Value::BIT_OR:
500 return (v8::internal::DoubleToInt32(lhs) |
501 v8::internal::DoubleToInt32(rhs));
502 case Token::Value::BIT_XOR:
503 return (v8::internal::DoubleToInt32(lhs) ^
504 v8::internal::DoubleToInt32(rhs));
505 case Token::Value::BIT_AND:
506 return (v8::internal::DoubleToInt32(lhs) &
507 v8::internal::DoubleToInt32(rhs));
508 case Token::Value::SHL: {
509 int32_t val = v8::internal::DoubleToInt32(lhs);
510 uint32_t count = v8::internal::DoubleToUint32(rhs) & 0x1F;
511 int32_t result = val << count;
512 return result;
513 }
514 case Token::Value::SAR: {
515 int32_t val = v8::internal::DoubleToInt32(lhs);
516 uint32_t count = v8::internal::DoubleToUint32(rhs) & 0x1F;
517 int32_t result = val >> count;
518 return result;
519 }
520 case Token::Value::SHR: {
521 uint32_t val = v8::internal::DoubleToUint32(lhs);
522 uint32_t count = v8::internal::DoubleToUint32(rhs) & 0x1F;
523 uint32_t result = val >> count;
524 return result;
525 }
526 default:
527 UNREACHABLE();
528 return std::numeric_limits<double>::min();
529 }
530}
531
532
533TEST(InterpreterShiftOpsSmi) {
534 int lhs_inputs[] = {0, -17, -182, 1073741823, -1};
535 int rhs_inputs[] = {5, 2, 1, -1, -2, 0, 31, 32, -32, 64, 37};
536 for (size_t l = 0; l < arraysize(lhs_inputs); l++) {
537 for (size_t r = 0; r < arraysize(rhs_inputs); r++) {
538 for (size_t o = 0; o < arraysize(kShiftOperators); o++) {
539 HandleAndZoneScope handles;
540 i::Factory* factory = handles.main_isolate()->factory();
541 BytecodeArrayBuilder builder(handles.main_isolate(),
542 handles.main_zone());
543 builder.set_locals_count(1);
544 builder.set_context_count(0);
545 builder.set_parameter_count(1);
546 Register reg(0);
547 int lhs = lhs_inputs[l];
548 int rhs = rhs_inputs[r];
549 builder.LoadLiteral(Smi::FromInt(lhs))
550 .StoreAccumulatorInRegister(reg)
551 .LoadLiteral(Smi::FromInt(rhs))
552 .BinaryOperation(kShiftOperators[o], reg, Strength::WEAK)
553 .Return();
554 Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
555
556 InterpreterTester tester(handles.main_isolate(), bytecode_array);
557 auto callable = tester.GetCallable<>();
558 Handle<Object> return_value = callable().ToHandleChecked();
559 Handle<Object> expected_value =
560 factory->NewNumber(BinaryOpC(kShiftOperators[o], lhs, rhs));
561 CHECK(return_value->SameValue(*expected_value));
562 }
563 }
564 }
565}
566
567
568TEST(InterpreterBinaryOpsSmi) {
569 int lhs_inputs[] = {3266, 1024, 0, -17, -18000};
570 int rhs_inputs[] = {3266, 5, 4, 3, 2, 1, -1, -2};
571 for (size_t l = 0; l < arraysize(lhs_inputs); l++) {
572 for (size_t r = 0; r < arraysize(rhs_inputs); r++) {
573 for (size_t o = 0; o < arraysize(kArithmeticOperators); o++) {
574 HandleAndZoneScope handles;
575 i::Factory* factory = handles.main_isolate()->factory();
576 BytecodeArrayBuilder builder(handles.main_isolate(),
577 handles.main_zone());
578 builder.set_locals_count(1);
579 builder.set_context_count(0);
580 builder.set_parameter_count(1);
581 Register reg(0);
582 int lhs = lhs_inputs[l];
583 int rhs = rhs_inputs[r];
584 builder.LoadLiteral(Smi::FromInt(lhs))
585 .StoreAccumulatorInRegister(reg)
586 .LoadLiteral(Smi::FromInt(rhs))
587 .BinaryOperation(kArithmeticOperators[o], reg, Strength::WEAK)
588 .Return();
589 Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
590
591 InterpreterTester tester(handles.main_isolate(), bytecode_array);
592 auto callable = tester.GetCallable<>();
593 Handle<Object> return_value = callable().ToHandleChecked();
594 Handle<Object> expected_value =
595 factory->NewNumber(BinaryOpC(kArithmeticOperators[o], lhs, rhs));
596 CHECK(return_value->SameValue(*expected_value));
597 }
598 }
599 }
600}
601
602
603TEST(InterpreterBinaryOpsHeapNumber) {
604 double lhs_inputs[] = {3266.101, 1024.12, 0.01, -17.99, -18000.833, 9.1e17};
605 double rhs_inputs[] = {3266.101, 5.999, 4.778, 3.331, 2.643,
606 1.1, -1.8, -2.9, 8.3e-27};
607 for (size_t l = 0; l < arraysize(lhs_inputs); l++) {
608 for (size_t r = 0; r < arraysize(rhs_inputs); r++) {
609 for (size_t o = 0; o < arraysize(kArithmeticOperators); o++) {
610 HandleAndZoneScope handles;
611 i::Factory* factory = handles.main_isolate()->factory();
612 BytecodeArrayBuilder builder(handles.main_isolate(),
613 handles.main_zone());
614 builder.set_locals_count(1);
615 builder.set_context_count(0);
616 builder.set_parameter_count(1);
617 Register reg(0);
618 double lhs = lhs_inputs[l];
619 double rhs = rhs_inputs[r];
620 builder.LoadLiteral(factory->NewNumber(lhs))
621 .StoreAccumulatorInRegister(reg)
622 .LoadLiteral(factory->NewNumber(rhs))
623 .BinaryOperation(kArithmeticOperators[o], reg, Strength::WEAK)
624 .Return();
625 Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
626
627 InterpreterTester tester(handles.main_isolate(), bytecode_array);
628 auto callable = tester.GetCallable<>();
629 Handle<Object> return_value = callable().ToHandleChecked();
630 Handle<Object> expected_value =
631 factory->NewNumber(BinaryOpC(kArithmeticOperators[o], lhs, rhs));
632 CHECK(return_value->SameValue(*expected_value));
633 }
634 }
635 }
636}
637
638
639TEST(InterpreterStringAdd) {
640 HandleAndZoneScope handles;
641 i::Factory* factory = handles.main_isolate()->factory();
642
643 struct TestCase {
644 Handle<Object> lhs;
645 Handle<Object> rhs;
646 Handle<Object> expected_value;
647 } test_cases[] = {
648 {factory->NewStringFromStaticChars("a"),
649 factory->NewStringFromStaticChars("b"),
650 factory->NewStringFromStaticChars("ab")},
651 {factory->NewStringFromStaticChars("aaaaaa"),
652 factory->NewStringFromStaticChars("b"),
653 factory->NewStringFromStaticChars("aaaaaab")},
654 {factory->NewStringFromStaticChars("aaa"),
655 factory->NewStringFromStaticChars("bbbbb"),
656 factory->NewStringFromStaticChars("aaabbbbb")},
657 {factory->NewStringFromStaticChars(""),
658 factory->NewStringFromStaticChars("b"),
659 factory->NewStringFromStaticChars("b")},
660 {factory->NewStringFromStaticChars("a"),
661 factory->NewStringFromStaticChars(""),
662 factory->NewStringFromStaticChars("a")},
663 {factory->NewStringFromStaticChars("1.11"), factory->NewHeapNumber(2.5),
664 factory->NewStringFromStaticChars("1.112.5")},
665 {factory->NewStringFromStaticChars("-1.11"), factory->NewHeapNumber(2.56),
666 factory->NewStringFromStaticChars("-1.112.56")},
667 {factory->NewStringFromStaticChars(""), factory->NewHeapNumber(2.5),
668 factory->NewStringFromStaticChars("2.5")},
669 };
670
671 for (size_t i = 0; i < arraysize(test_cases); i++) {
672 BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
673 builder.set_locals_count(1);
674 builder.set_context_count(0);
675 builder.set_parameter_count(1);
676 Register reg(0);
677 builder.LoadLiteral(test_cases[i].lhs)
678 .StoreAccumulatorInRegister(reg)
679 .LoadLiteral(test_cases[i].rhs)
680 .BinaryOperation(Token::Value::ADD, reg, Strength::WEAK)
681 .Return();
682 Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
683
684 InterpreterTester tester(handles.main_isolate(), bytecode_array);
685 auto callable = tester.GetCallable<>();
686 Handle<Object> return_value = callable().ToHandleChecked();
687 CHECK(return_value->SameValue(*test_cases[i].expected_value));
688 }
689}
690
691
692TEST(InterpreterParameter1) {
693 HandleAndZoneScope handles;
694 BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
695 builder.set_locals_count(0);
696 builder.set_context_count(0);
697 builder.set_parameter_count(1);
698 builder.LoadAccumulatorWithRegister(builder.Parameter(0)).Return();
699 Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
700
701 InterpreterTester tester(handles.main_isolate(), bytecode_array);
702 auto callable = tester.GetCallable<Handle<Object>>();
703
704 // Check for heap objects.
705 Handle<Object> true_value = handles.main_isolate()->factory()->true_value();
706 Handle<Object> return_val = callable(true_value).ToHandleChecked();
707 CHECK(return_val.is_identical_to(true_value));
708
709 // Check for Smis.
710 return_val = callable(Handle<Smi>(Smi::FromInt(3), handles.main_isolate()))
711 .ToHandleChecked();
712 CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(3));
713}
714
715
716TEST(InterpreterParameter8) {
717 HandleAndZoneScope handles;
718 BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
719 builder.set_locals_count(0);
720 builder.set_context_count(0);
721 builder.set_parameter_count(8);
722 builder.LoadAccumulatorWithRegister(builder.Parameter(0))
723 .BinaryOperation(Token::Value::ADD, builder.Parameter(1), Strength::WEAK)
724 .BinaryOperation(Token::Value::ADD, builder.Parameter(2), Strength::WEAK)
725 .BinaryOperation(Token::Value::ADD, builder.Parameter(3), Strength::WEAK)
726 .BinaryOperation(Token::Value::ADD, builder.Parameter(4), Strength::WEAK)
727 .BinaryOperation(Token::Value::ADD, builder.Parameter(5), Strength::WEAK)
728 .BinaryOperation(Token::Value::ADD, builder.Parameter(6), Strength::WEAK)
729 .BinaryOperation(Token::Value::ADD, builder.Parameter(7), Strength::WEAK)
730 .Return();
731 Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
732
733 InterpreterTester tester(handles.main_isolate(), bytecode_array);
734 typedef Handle<Object> H;
735 auto callable = tester.GetCallable<H, H, H, H, H, H, H, H>();
736
737 Handle<Smi> arg1 = Handle<Smi>(Smi::FromInt(1), handles.main_isolate());
738 Handle<Smi> arg2 = Handle<Smi>(Smi::FromInt(2), handles.main_isolate());
739 Handle<Smi> arg3 = Handle<Smi>(Smi::FromInt(3), handles.main_isolate());
740 Handle<Smi> arg4 = Handle<Smi>(Smi::FromInt(4), handles.main_isolate());
741 Handle<Smi> arg5 = Handle<Smi>(Smi::FromInt(5), handles.main_isolate());
742 Handle<Smi> arg6 = Handle<Smi>(Smi::FromInt(6), handles.main_isolate());
743 Handle<Smi> arg7 = Handle<Smi>(Smi::FromInt(7), handles.main_isolate());
744 Handle<Smi> arg8 = Handle<Smi>(Smi::FromInt(8), handles.main_isolate());
745 // Check for Smis.
746 Handle<Object> return_val =
747 callable(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8)
748 .ToHandleChecked();
749 CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(36));
750}
751
752
753TEST(InterpreterParameter1Assign) {
754 HandleAndZoneScope handles;
755 BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
756 builder.set_locals_count(0);
757 builder.set_context_count(0);
758 builder.set_parameter_count(1);
759 builder.LoadLiteral(Smi::FromInt(5))
760 .StoreAccumulatorInRegister(builder.Parameter(0))
761 .LoadAccumulatorWithRegister(builder.Parameter(0))
762 .Return();
763 Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
764
765 InterpreterTester tester(handles.main_isolate(), bytecode_array);
766 auto callable = tester.GetCallable<Handle<Object>>();
767
768 Handle<Object> return_val =
769 callable(Handle<Smi>(Smi::FromInt(3), handles.main_isolate()))
770 .ToHandleChecked();
771 CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(5));
772}
773
774
775TEST(InterpreterLoadGlobal) {
776 HandleAndZoneScope handles;
777
778 // Test loading a global.
779 std::string source(
780 "var global = 321;\n"
781 "function " + InterpreterTester::function_name() + "() {\n"
782 " return global;\n"
783 "}");
784 InterpreterTester tester(handles.main_isolate(), source.c_str());
785 auto callable = tester.GetCallable<>();
786
787 Handle<Object> return_val = callable().ToHandleChecked();
788 CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(321));
789}
790
791
792TEST(InterpreterStoreGlobal) {
793 HandleAndZoneScope handles;
794 i::Isolate* isolate = handles.main_isolate();
795 i::Factory* factory = isolate->factory();
796
797 // Test storing to a global.
798 std::string source(
799 "var global = 321;\n"
800 "function " + InterpreterTester::function_name() + "() {\n"
801 " global = 999;\n"
802 "}");
803 InterpreterTester tester(handles.main_isolate(), source.c_str());
804 auto callable = tester.GetCallable<>();
805
806 callable().ToHandleChecked();
807 Handle<i::String> name = factory->InternalizeUtf8String("global");
808 Handle<i::Object> global_obj =
809 Object::GetProperty(isolate->global_object(), name).ToHandleChecked();
810 CHECK_EQ(Smi::cast(*global_obj), Smi::FromInt(999));
811}
812
813
814TEST(InterpreterCallGlobal) {
815 HandleAndZoneScope handles;
816
817 // Test calling a global function.
818 std::string source(
819 "function g_add(a, b) { return a + b; }\n"
820 "function " + InterpreterTester::function_name() + "() {\n"
821 " return g_add(5, 10);\n"
822 "}");
823 InterpreterTester tester(handles.main_isolate(), source.c_str());
824 auto callable = tester.GetCallable<>();
825
826 Handle<Object> return_val = callable().ToHandleChecked();
827 CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(15));
828}
829
830
831TEST(InterpreterLoadUnallocated) {
832 HandleAndZoneScope handles;
833
834 // Test loading an unallocated global.
835 std::string source(
836 "unallocated = 123;\n"
837 "function " + InterpreterTester::function_name() + "() {\n"
838 " return unallocated;\n"
839 "}");
840 InterpreterTester tester(handles.main_isolate(), source.c_str());
841 auto callable = tester.GetCallable<>();
842
843 Handle<Object> return_val = callable().ToHandleChecked();
844 CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(123));
845}
846
847
848TEST(InterpreterStoreUnallocated) {
849 HandleAndZoneScope handles;
850 i::Isolate* isolate = handles.main_isolate();
851 i::Factory* factory = isolate->factory();
852
853 // Test storing to an unallocated global.
854 std::string source(
855 "unallocated = 321;\n"
856 "function " + InterpreterTester::function_name() + "() {\n"
857 " unallocated = 999;\n"
858 "}");
859 InterpreterTester tester(handles.main_isolate(), source.c_str());
860 auto callable = tester.GetCallable<>();
861
862 callable().ToHandleChecked();
863 Handle<i::String> name = factory->InternalizeUtf8String("unallocated");
864 Handle<i::Object> global_obj =
865 Object::GetProperty(isolate->global_object(), name).ToHandleChecked();
866 CHECK_EQ(Smi::cast(*global_obj), Smi::FromInt(999));
867}
868
869
870TEST(InterpreterLoadNamedProperty) {
871 HandleAndZoneScope handles;
872 i::Isolate* isolate = handles.main_isolate();
873 i::Factory* factory = isolate->factory();
874 i::Zone zone;
875
876 i::FeedbackVectorSpec feedback_spec(&zone);
877 i::FeedbackVectorSlot slot = feedback_spec.AddLoadICSlot();
878
879 Handle<i::TypeFeedbackVector> vector =
880 i::NewTypeFeedbackVector(isolate, &feedback_spec);
881
882 Handle<i::String> name = factory->NewStringFromAsciiChecked("val");
883 name = factory->string_table()->LookupString(isolate, name);
884
885 BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
886 builder.set_locals_count(0);
887 builder.set_context_count(0);
888 builder.set_parameter_count(1);
889 builder.LoadNamedProperty(builder.Parameter(0), name, vector->GetIndex(slot),
890 i::SLOPPY)
891 .Return();
892 Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
893
894 InterpreterTester tester(handles.main_isolate(), bytecode_array, vector);
895 auto callable = tester.GetCallable<Handle<Object>>();
896
897 Handle<Object> object = InterpreterTester::NewObject("({ val : 123 })");
898 // Test IC miss.
899 Handle<Object> return_val = callable(object).ToHandleChecked();
900 CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(123));
901
902 // Test transition to monomorphic IC.
903 return_val = callable(object).ToHandleChecked();
904 CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(123));
905
906 // Test transition to polymorphic IC.
907 Handle<Object> object2 =
908 InterpreterTester::NewObject("({ val : 456, other : 123 })");
909 return_val = callable(object2).ToHandleChecked();
910 CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(456));
911
912 // Test transition to megamorphic IC.
913 Handle<Object> object3 =
914 InterpreterTester::NewObject("({ val : 789, val2 : 123 })");
915 callable(object3).ToHandleChecked();
916 Handle<Object> object4 =
917 InterpreterTester::NewObject("({ val : 789, val3 : 123 })");
918 callable(object4).ToHandleChecked();
919 Handle<Object> object5 =
920 InterpreterTester::NewObject("({ val : 789, val4 : 123 })");
921 return_val = callable(object5).ToHandleChecked();
922 CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(789));
923}
924
925
926TEST(InterpreterLoadKeyedProperty) {
927 HandleAndZoneScope handles;
928 i::Isolate* isolate = handles.main_isolate();
929 i::Factory* factory = isolate->factory();
930 i::Zone zone;
931
932 i::FeedbackVectorSpec feedback_spec(&zone);
933 i::FeedbackVectorSlot slot = feedback_spec.AddKeyedLoadICSlot();
934
935 Handle<i::TypeFeedbackVector> vector =
936 i::NewTypeFeedbackVector(isolate, &feedback_spec);
937
938 Handle<i::String> key = factory->NewStringFromAsciiChecked("key");
939 key = factory->string_table()->LookupString(isolate, key);
940
941 BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
942 builder.set_locals_count(1);
943 builder.set_context_count(0);
944 builder.set_parameter_count(1);
945 builder.LoadLiteral(key)
946 .LoadKeyedProperty(builder.Parameter(0), vector->GetIndex(slot),
947 i::STRICT)
948 .Return();
949 Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
950
951 InterpreterTester tester(handles.main_isolate(), bytecode_array, vector);
952 auto callable = tester.GetCallable<Handle<Object>>();
953
954 Handle<Object> object = InterpreterTester::NewObject("({ key : 123 })");
955 // Test IC miss.
956 Handle<Object> return_val = callable(object).ToHandleChecked();
957 CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(123));
958
959 // Test transition to monomorphic IC.
960 return_val = callable(object).ToHandleChecked();
961 CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(123));
962
963 // Test transition to megamorphic IC.
964 Handle<Object> object3 =
965 InterpreterTester::NewObject("({ key : 789, val2 : 123 })");
966 return_val = callable(object3).ToHandleChecked();
967 CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(789));
968}
969
970
971TEST(InterpreterStoreNamedProperty) {
972 HandleAndZoneScope handles;
973 i::Isolate* isolate = handles.main_isolate();
974 i::Factory* factory = isolate->factory();
975 i::Zone zone;
976
977 i::FeedbackVectorSpec feedback_spec(&zone);
978 i::FeedbackVectorSlot slot = feedback_spec.AddStoreICSlot();
979
980 Handle<i::TypeFeedbackVector> vector =
981 i::NewTypeFeedbackVector(isolate, &feedback_spec);
982
983 Handle<i::String> name = factory->NewStringFromAsciiChecked("val");
984 name = factory->string_table()->LookupString(isolate, name);
985
986 BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
987 builder.set_locals_count(0);
988 builder.set_context_count(0);
989 builder.set_parameter_count(1);
990 builder.LoadLiteral(Smi::FromInt(999))
991 .StoreNamedProperty(builder.Parameter(0), name, vector->GetIndex(slot),
992 i::STRICT)
993 .Return();
994 Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
995
996 InterpreterTester tester(isolate, bytecode_array, vector);
997 auto callable = tester.GetCallable<Handle<Object>>();
998 Handle<Object> object = InterpreterTester::NewObject("({ val : 123 })");
999 // Test IC miss.
1000 Handle<Object> result;
1001 callable(object).ToHandleChecked();
1002 CHECK(Runtime::GetObjectProperty(isolate, object, name).ToHandle(&result));
1003 CHECK_EQ(Smi::cast(*result), Smi::FromInt(999));
1004
1005 // Test transition to monomorphic IC.
1006 callable(object).ToHandleChecked();
1007 CHECK(Runtime::GetObjectProperty(isolate, object, name).ToHandle(&result));
1008 CHECK_EQ(Smi::cast(*result), Smi::FromInt(999));
1009
1010 // Test transition to polymorphic IC.
1011 Handle<Object> object2 =
1012 InterpreterTester::NewObject("({ val : 456, other : 123 })");
1013 callable(object2).ToHandleChecked();
1014 CHECK(Runtime::GetObjectProperty(isolate, object2, name).ToHandle(&result));
1015 CHECK_EQ(Smi::cast(*result), Smi::FromInt(999));
1016
1017 // Test transition to megamorphic IC.
1018 Handle<Object> object3 =
1019 InterpreterTester::NewObject("({ val : 789, val2 : 123 })");
1020 callable(object3).ToHandleChecked();
1021 Handle<Object> object4 =
1022 InterpreterTester::NewObject("({ val : 789, val3 : 123 })");
1023 callable(object4).ToHandleChecked();
1024 Handle<Object> object5 =
1025 InterpreterTester::NewObject("({ val : 789, val4 : 123 })");
1026 callable(object5).ToHandleChecked();
1027 CHECK(Runtime::GetObjectProperty(isolate, object5, name).ToHandle(&result));
1028 CHECK_EQ(Smi::cast(*result), Smi::FromInt(999));
1029}
1030
1031
1032TEST(InterpreterStoreKeyedProperty) {
1033 HandleAndZoneScope handles;
1034 i::Isolate* isolate = handles.main_isolate();
1035 i::Factory* factory = isolate->factory();
1036 i::Zone zone;
1037
1038 i::FeedbackVectorSpec feedback_spec(&zone);
1039 i::FeedbackVectorSlot slot = feedback_spec.AddKeyedStoreICSlot();
1040
1041 Handle<i::TypeFeedbackVector> vector =
1042 i::NewTypeFeedbackVector(isolate, &feedback_spec);
1043
1044 Handle<i::String> name = factory->NewStringFromAsciiChecked("val");
1045 name = factory->string_table()->LookupString(isolate, name);
1046
1047 BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
1048 builder.set_locals_count(1);
1049 builder.set_context_count(0);
1050 builder.set_parameter_count(1);
1051 builder.LoadLiteral(name)
1052 .StoreAccumulatorInRegister(Register(0))
1053 .LoadLiteral(Smi::FromInt(999))
1054 .StoreKeyedProperty(builder.Parameter(0), Register(0),
1055 vector->GetIndex(slot), i::SLOPPY)
1056 .Return();
1057 Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
1058
1059 InterpreterTester tester(isolate, bytecode_array, vector);
1060 auto callable = tester.GetCallable<Handle<Object>>();
1061 Handle<Object> object = InterpreterTester::NewObject("({ val : 123 })");
1062 // Test IC miss.
1063 Handle<Object> result;
1064 callable(object).ToHandleChecked();
1065 CHECK(Runtime::GetObjectProperty(isolate, object, name).ToHandle(&result));
1066 CHECK_EQ(Smi::cast(*result), Smi::FromInt(999));
1067
1068 // Test transition to monomorphic IC.
1069 callable(object).ToHandleChecked();
1070 CHECK(Runtime::GetObjectProperty(isolate, object, name).ToHandle(&result));
1071 CHECK_EQ(Smi::cast(*result), Smi::FromInt(999));
1072
1073 // Test transition to megamorphic IC.
1074 Handle<Object> object2 =
1075 InterpreterTester::NewObject("({ val : 456, other : 123 })");
1076 callable(object2).ToHandleChecked();
1077 CHECK(Runtime::GetObjectProperty(isolate, object2, name).ToHandle(&result));
1078 CHECK_EQ(Smi::cast(*result), Smi::FromInt(999));
1079}
1080
1081
1082TEST(InterpreterCall) {
1083 HandleAndZoneScope handles;
1084 i::Isolate* isolate = handles.main_isolate();
1085 i::Factory* factory = isolate->factory();
1086 i::Zone zone;
1087
1088 i::FeedbackVectorSpec feedback_spec(&zone);
1089 i::FeedbackVectorSlot slot = feedback_spec.AddLoadICSlot();
1090
1091 Handle<i::TypeFeedbackVector> vector =
1092 i::NewTypeFeedbackVector(isolate, &feedback_spec);
1093 int slot_index = vector->GetIndex(slot);
1094
1095 Handle<i::String> name = factory->NewStringFromAsciiChecked("func");
1096 name = factory->string_table()->LookupString(isolate, name);
1097
1098 // Check with no args.
1099 {
1100 BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
1101 builder.set_locals_count(1);
1102 builder.set_context_count(0);
1103 builder.set_parameter_count(1);
1104 builder.LoadNamedProperty(builder.Parameter(0), name, slot_index, i::SLOPPY)
1105 .StoreAccumulatorInRegister(Register(0))
1106 .Call(Register(0), builder.Parameter(0), 0, 0)
1107 .Return();
1108 Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
1109
1110 InterpreterTester tester(handles.main_isolate(), bytecode_array, vector);
1111 auto callable = tester.GetCallable<Handle<Object>>();
1112
1113 Handle<Object> object = InterpreterTester::NewObject(
1114 "new (function Obj() { this.func = function() { return 0x265; }})()");
1115 Handle<Object> return_val = callable(object).ToHandleChecked();
1116 CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(0x265));
1117 }
1118
1119 // Check that receiver is passed properly.
1120 {
1121 BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
1122 builder.set_locals_count(1);
1123 builder.set_context_count(0);
1124 builder.set_parameter_count(1);
1125 builder.LoadNamedProperty(builder.Parameter(0), name, slot_index, i::SLOPPY)
1126 .StoreAccumulatorInRegister(Register(0))
1127 .Call(Register(0), builder.Parameter(0), 0, 0)
1128 .Return();
1129 Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
1130
1131 InterpreterTester tester(handles.main_isolate(), bytecode_array, vector);
1132 auto callable = tester.GetCallable<Handle<Object>>();
1133
1134 Handle<Object> object = InterpreterTester::NewObject(
1135 "new (function Obj() {"
1136 " this.val = 1234;"
1137 " this.func = function() { return this.val; };"
1138 "})()");
1139 Handle<Object> return_val = callable(object).ToHandleChecked();
1140 CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(1234));
1141 }
1142
1143 // Check with two parameters (+ receiver).
1144 {
1145 BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
1146 builder.set_locals_count(4);
1147 builder.set_context_count(0);
1148 builder.set_parameter_count(1);
1149 builder.LoadNamedProperty(builder.Parameter(0), name, slot_index, i::SLOPPY)
1150 .StoreAccumulatorInRegister(Register(0))
1151 .LoadAccumulatorWithRegister(builder.Parameter(0))
1152 .StoreAccumulatorInRegister(Register(1))
1153 .LoadLiteral(Smi::FromInt(51))
1154 .StoreAccumulatorInRegister(Register(2))
1155 .LoadLiteral(Smi::FromInt(11))
1156 .StoreAccumulatorInRegister(Register(3))
1157 .Call(Register(0), Register(1), 2, 0)
1158 .Return();
1159 Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
1160
1161 InterpreterTester tester(handles.main_isolate(), bytecode_array, vector);
1162 auto callable = tester.GetCallable<Handle<Object>>();
1163
1164 Handle<Object> object = InterpreterTester::NewObject(
1165 "new (function Obj() { "
1166 " this.func = function(a, b) { return a - b; }"
1167 "})()");
1168 Handle<Object> return_val = callable(object).ToHandleChecked();
1169 CHECK(return_val->SameValue(Smi::FromInt(40)));
1170 }
1171
1172 // Check with 10 parameters (+ receiver).
1173 {
1174 BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
1175 builder.set_locals_count(12);
1176 builder.set_context_count(0);
1177 builder.set_parameter_count(1);
1178 builder.LoadNamedProperty(builder.Parameter(0), name, slot_index, i::SLOPPY)
1179 .StoreAccumulatorInRegister(Register(0))
1180 .LoadAccumulatorWithRegister(builder.Parameter(0))
1181 .StoreAccumulatorInRegister(Register(1))
1182 .LoadLiteral(factory->NewStringFromAsciiChecked("a"))
1183 .StoreAccumulatorInRegister(Register(2))
1184 .LoadLiteral(factory->NewStringFromAsciiChecked("b"))
1185 .StoreAccumulatorInRegister(Register(3))
1186 .LoadLiteral(factory->NewStringFromAsciiChecked("c"))
1187 .StoreAccumulatorInRegister(Register(4))
1188 .LoadLiteral(factory->NewStringFromAsciiChecked("d"))
1189 .StoreAccumulatorInRegister(Register(5))
1190 .LoadLiteral(factory->NewStringFromAsciiChecked("e"))
1191 .StoreAccumulatorInRegister(Register(6))
1192 .LoadLiteral(factory->NewStringFromAsciiChecked("f"))
1193 .StoreAccumulatorInRegister(Register(7))
1194 .LoadLiteral(factory->NewStringFromAsciiChecked("g"))
1195 .StoreAccumulatorInRegister(Register(8))
1196 .LoadLiteral(factory->NewStringFromAsciiChecked("h"))
1197 .StoreAccumulatorInRegister(Register(9))
1198 .LoadLiteral(factory->NewStringFromAsciiChecked("i"))
1199 .StoreAccumulatorInRegister(Register(10))
1200 .LoadLiteral(factory->NewStringFromAsciiChecked("j"))
1201 .StoreAccumulatorInRegister(Register(11))
1202 .Call(Register(0), Register(1), 10, 0)
1203 .Return();
1204 Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
1205
1206 InterpreterTester tester(handles.main_isolate(), bytecode_array, vector);
1207 auto callable = tester.GetCallable<Handle<Object>>();
1208
1209 Handle<Object> object = InterpreterTester::NewObject(
1210 "new (function Obj() { "
1211 " this.prefix = \"prefix_\";"
1212 " this.func = function(a, b, c, d, e, f, g, h, i, j) {"
1213 " return this.prefix + a + b + c + d + e + f + g + h + i + j;"
1214 " }"
1215 "})()");
1216 Handle<Object> return_val = callable(object).ToHandleChecked();
1217 Handle<i::String> expected =
1218 factory->NewStringFromAsciiChecked("prefix_abcdefghij");
1219 CHECK(i::String::cast(*return_val)->Equals(*expected));
1220 }
1221}
1222
1223
1224static BytecodeArrayBuilder& SetRegister(BytecodeArrayBuilder& builder,
1225 Register reg, int value,
1226 Register scratch) {
1227 return builder.StoreAccumulatorInRegister(scratch)
1228 .LoadLiteral(Smi::FromInt(value))
1229 .StoreAccumulatorInRegister(reg)
1230 .LoadAccumulatorWithRegister(scratch);
1231}
1232
1233
1234static BytecodeArrayBuilder& IncrementRegister(BytecodeArrayBuilder& builder,
1235 Register reg, int value,
1236 Register scratch) {
1237 return builder.StoreAccumulatorInRegister(scratch)
1238 .LoadLiteral(Smi::FromInt(value))
1239 .BinaryOperation(Token::Value::ADD, reg, Strength::WEAK)
1240 .StoreAccumulatorInRegister(reg)
1241 .LoadAccumulatorWithRegister(scratch);
1242}
1243
1244
1245TEST(InterpreterJumps) {
1246 HandleAndZoneScope handles;
1247 BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
1248 builder.set_locals_count(2);
1249 builder.set_context_count(0);
1250 builder.set_parameter_count(0);
1251 Register reg(0), scratch(1);
1252 BytecodeLabel label[3];
1253
1254 builder.LoadLiteral(Smi::FromInt(0))
1255 .StoreAccumulatorInRegister(reg)
1256 .Jump(&label[1]);
1257 SetRegister(builder, reg, 1024, scratch).Bind(&label[0]);
1258 IncrementRegister(builder, reg, 1, scratch).Jump(&label[2]);
1259 SetRegister(builder, reg, 2048, scratch).Bind(&label[1]);
1260 IncrementRegister(builder, reg, 2, scratch).Jump(&label[0]);
1261 SetRegister(builder, reg, 4096, scratch).Bind(&label[2]);
1262 IncrementRegister(builder, reg, 4, scratch)
1263 .LoadAccumulatorWithRegister(reg)
1264 .Return();
1265
1266 Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
1267 InterpreterTester tester(handles.main_isolate(), bytecode_array);
1268 auto callable = tester.GetCallable<>();
1269 Handle<Object> return_value = callable().ToHandleChecked();
1270 CHECK_EQ(Smi::cast(*return_value)->value(), 7);
1271}
1272
1273
1274TEST(InterpreterConditionalJumps) {
1275 HandleAndZoneScope handles;
1276 BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
1277 builder.set_locals_count(2);
1278 builder.set_context_count(0);
1279 builder.set_parameter_count(0);
1280 Register reg(0), scratch(1);
1281 BytecodeLabel label[2];
1282 BytecodeLabel done, done1;
1283
1284 builder.LoadLiteral(Smi::FromInt(0))
1285 .StoreAccumulatorInRegister(reg)
1286 .LoadFalse()
1287 .JumpIfFalse(&label[0]);
1288 IncrementRegister(builder, reg, 1024, scratch)
1289 .Bind(&label[0])
1290 .LoadTrue()
1291 .JumpIfFalse(&done);
1292 IncrementRegister(builder, reg, 1, scratch).LoadTrue().JumpIfTrue(&label[1]);
1293 IncrementRegister(builder, reg, 2048, scratch).Bind(&label[1]);
1294 IncrementRegister(builder, reg, 2, scratch).LoadFalse().JumpIfTrue(&done1);
1295 IncrementRegister(builder, reg, 4, scratch)
1296 .LoadAccumulatorWithRegister(reg)
1297 .Bind(&done)
1298 .Bind(&done1)
1299 .Return();
1300
1301 Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
1302 InterpreterTester tester(handles.main_isolate(), bytecode_array);
1303 auto callable = tester.GetCallable<>();
1304 Handle<Object> return_value = callable().ToHandleChecked();
1305 CHECK_EQ(Smi::cast(*return_value)->value(), 7);
1306}
1307
1308
1309TEST(InterpreterConditionalJumps2) {
1310 // TODO(oth): Add tests for all conditional jumps near and far.
1311 HandleAndZoneScope handles;
1312 BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
1313 builder.set_locals_count(2);
1314 builder.set_context_count(0);
1315 builder.set_parameter_count(0);
1316 Register reg(0), scratch(1);
1317 BytecodeLabel label[2];
1318 BytecodeLabel done, done1;
1319
1320 builder.LoadLiteral(Smi::FromInt(0))
1321 .StoreAccumulatorInRegister(reg)
1322 .LoadFalse()
1323 .JumpIfFalse(&label[0]);
1324 IncrementRegister(builder, reg, 1024, scratch)
1325 .Bind(&label[0])
1326 .LoadTrue()
1327 .JumpIfFalse(&done);
1328 IncrementRegister(builder, reg, 1, scratch).LoadTrue().JumpIfTrue(&label[1]);
1329 IncrementRegister(builder, reg, 2048, scratch).Bind(&label[1]);
1330 IncrementRegister(builder, reg, 2, scratch).LoadFalse().JumpIfTrue(&done1);
1331 IncrementRegister(builder, reg, 4, scratch)
1332 .LoadAccumulatorWithRegister(reg)
1333 .Bind(&done)
1334 .Bind(&done1)
1335 .Return();
1336
1337 Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
1338 InterpreterTester tester(handles.main_isolate(), bytecode_array);
1339 auto callable = tester.GetCallable<>();
1340 Handle<Object> return_value = callable().ToHandleChecked();
1341 CHECK_EQ(Smi::cast(*return_value)->value(), 7);
1342}
1343
1344
1345static const Token::Value kComparisonTypes[] = {
1346 Token::Value::EQ, Token::Value::NE, Token::Value::EQ_STRICT,
1347 Token::Value::NE_STRICT, Token::Value::LT, Token::Value::LTE,
1348 Token::Value::GT, Token::Value::GTE};
1349
1350
1351template <typename T>
1352bool CompareC(Token::Value op, T lhs, T rhs, bool types_differed = false) {
1353 switch (op) {
1354 case Token::Value::EQ:
1355 return lhs == rhs;
1356 case Token::Value::NE:
1357 return lhs != rhs;
1358 case Token::Value::EQ_STRICT:
1359 return (lhs == rhs) && !types_differed;
1360 case Token::Value::NE_STRICT:
1361 return (lhs != rhs) || types_differed;
1362 case Token::Value::LT:
1363 return lhs < rhs;
1364 case Token::Value::LTE:
1365 return lhs <= rhs;
1366 case Token::Value::GT:
1367 return lhs > rhs;
1368 case Token::Value::GTE:
1369 return lhs >= rhs;
1370 default:
1371 UNREACHABLE();
1372 return false;
1373 }
1374}
1375
1376
1377TEST(InterpreterSmiComparisons) {
1378 // NB Constants cover 31-bit space.
1379 int inputs[] = {v8::internal::kMinInt / 2,
1380 v8::internal::kMinInt / 4,
1381 -108733832,
1382 -999,
1383 -42,
1384 -2,
1385 -1,
1386 0,
1387 +1,
1388 +2,
1389 42,
1390 12345678,
1391 v8::internal::kMaxInt / 4,
1392 v8::internal::kMaxInt / 2};
1393
1394 for (size_t c = 0; c < arraysize(kComparisonTypes); c++) {
1395 Token::Value comparison = kComparisonTypes[c];
1396 for (size_t i = 0; i < arraysize(inputs); i++) {
1397 for (size_t j = 0; j < arraysize(inputs); j++) {
1398 HandleAndZoneScope handles;
1399 BytecodeArrayBuilder builder(handles.main_isolate(),
1400 handles.main_zone());
1401 Register r0(0);
1402 builder.set_locals_count(1);
1403 builder.set_context_count(0);
1404 builder.set_parameter_count(0);
1405 builder.LoadLiteral(Smi::FromInt(inputs[i]))
1406 .StoreAccumulatorInRegister(r0)
1407 .LoadLiteral(Smi::FromInt(inputs[j]))
1408 .CompareOperation(comparison, r0, Strength::WEAK)
1409 .Return();
1410
1411 Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
1412 InterpreterTester tester(handles.main_isolate(), bytecode_array);
1413 auto callable = tester.GetCallable<>();
1414 Handle<Object> return_value = callable().ToHandleChecked();
1415 CHECK(return_value->IsBoolean());
1416 CHECK_EQ(return_value->BooleanValue(),
1417 CompareC(comparison, inputs[i], inputs[j]));
1418 }
1419 }
1420 }
1421}
1422
1423
1424TEST(InterpreterHeapNumberComparisons) {
1425 double inputs[] = {std::numeric_limits<double>::min(),
1426 std::numeric_limits<double>::max(),
1427 -0.001,
1428 0.01,
1429 0.1000001,
1430 1e99,
1431 -1e-99};
1432 for (size_t c = 0; c < arraysize(kComparisonTypes); c++) {
1433 Token::Value comparison = kComparisonTypes[c];
1434 for (size_t i = 0; i < arraysize(inputs); i++) {
1435 for (size_t j = 0; j < arraysize(inputs); j++) {
1436 HandleAndZoneScope handles;
1437 i::Factory* factory = handles.main_isolate()->factory();
1438 BytecodeArrayBuilder builder(handles.main_isolate(),
1439 handles.main_zone());
1440 Register r0(0);
1441 builder.set_locals_count(1);
1442 builder.set_context_count(0);
1443 builder.set_parameter_count(0);
1444 builder.LoadLiteral(factory->NewHeapNumber(inputs[i]))
1445 .StoreAccumulatorInRegister(r0)
1446 .LoadLiteral(factory->NewHeapNumber(inputs[j]))
1447 .CompareOperation(comparison, r0, Strength::WEAK)
1448 .Return();
1449
1450 Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
1451 InterpreterTester tester(handles.main_isolate(), bytecode_array);
1452 auto callable = tester.GetCallable<>();
1453 Handle<Object> return_value = callable().ToHandleChecked();
1454 CHECK(return_value->IsBoolean());
1455 CHECK_EQ(return_value->BooleanValue(),
1456 CompareC(comparison, inputs[i], inputs[j]));
1457 }
1458 }
1459 }
1460}
1461
1462
1463TEST(InterpreterStringComparisons) {
1464 std::string inputs[] = {"A", "abc", "z", "", "Foo!", "Foo"};
1465
1466 for (size_t c = 0; c < arraysize(kComparisonTypes); c++) {
1467 Token::Value comparison = kComparisonTypes[c];
1468 for (size_t i = 0; i < arraysize(inputs); i++) {
1469 for (size_t j = 0; j < arraysize(inputs); j++) {
1470 const char* lhs = inputs[i].c_str();
1471 const char* rhs = inputs[j].c_str();
1472 HandleAndZoneScope handles;
1473 i::Factory* factory = handles.main_isolate()->factory();
1474 BytecodeArrayBuilder builder(handles.main_isolate(),
1475 handles.main_zone());
1476 Register r0(0);
1477 builder.set_locals_count(1);
1478 builder.set_context_count(0);
1479 builder.set_parameter_count(0);
1480 builder.LoadLiteral(factory->NewStringFromAsciiChecked(lhs))
1481 .StoreAccumulatorInRegister(r0)
1482 .LoadLiteral(factory->NewStringFromAsciiChecked(rhs))
1483 .CompareOperation(comparison, r0, Strength::WEAK)
1484 .Return();
1485
1486 Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
1487 InterpreterTester tester(handles.main_isolate(), bytecode_array);
1488 auto callable = tester.GetCallable<>();
1489 Handle<Object> return_value = callable().ToHandleChecked();
1490 CHECK(return_value->IsBoolean());
1491 CHECK_EQ(return_value->BooleanValue(),
1492 CompareC(comparison, inputs[i], inputs[j]));
1493 }
1494 }
1495 }
1496}
1497
1498
1499TEST(InterpreterMixedComparisons) {
1500 // This test compares a HeapNumber with a String. The latter is
1501 // convertible to a HeapNumber so comparison will be between numeric
1502 // values except for the strict comparisons where no conversion is
1503 // performed.
1504 const char* inputs[] = {"-1.77", "-40.333", "0.01", "55.77e5", "2.01"};
1505
1506 i::UnicodeCache unicode_cache;
1507
1508 for (size_t c = 0; c < arraysize(kComparisonTypes); c++) {
1509 Token::Value comparison = kComparisonTypes[c];
1510 for (size_t i = 0; i < arraysize(inputs); i++) {
1511 for (size_t j = 0; j < arraysize(inputs); j++) {
1512 for (int pass = 0; pass < 2; pass++) {
1513 const char* lhs_cstr = inputs[i];
1514 const char* rhs_cstr = inputs[j];
1515 double lhs = StringToDouble(&unicode_cache, lhs_cstr,
1516 i::ConversionFlags::NO_FLAGS);
1517 double rhs = StringToDouble(&unicode_cache, rhs_cstr,
1518 i::ConversionFlags::NO_FLAGS);
1519 HandleAndZoneScope handles;
1520 i::Factory* factory = handles.main_isolate()->factory();
1521 BytecodeArrayBuilder builder(handles.main_isolate(),
1522 handles.main_zone());
1523 Register r0(0);
1524 builder.set_locals_count(1);
1525 builder.set_context_count(0);
1526 builder.set_parameter_count(0);
1527 if (pass == 0) {
1528 // Comparison with HeapNumber on the lhs and String on the rhs
1529 builder.LoadLiteral(factory->NewNumber(lhs))
1530 .StoreAccumulatorInRegister(r0)
1531 .LoadLiteral(factory->NewStringFromAsciiChecked(rhs_cstr))
1532 .CompareOperation(comparison, r0, Strength::WEAK)
1533 .Return();
1534 } else {
1535 // Comparison with HeapNumber on the rhs and String on the lhs
1536 builder.LoadLiteral(factory->NewStringFromAsciiChecked(lhs_cstr))
1537 .StoreAccumulatorInRegister(r0)
1538 .LoadLiteral(factory->NewNumber(rhs))
1539 .CompareOperation(comparison, r0, Strength::WEAK)
1540 .Return();
1541 }
1542
1543 Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
1544 InterpreterTester tester(handles.main_isolate(), bytecode_array);
1545 auto callable = tester.GetCallable<>();
1546 Handle<Object> return_value = callable().ToHandleChecked();
1547 CHECK(return_value->IsBoolean());
1548 CHECK_EQ(return_value->BooleanValue(),
1549 CompareC(comparison, lhs, rhs, true));
1550 }
1551 }
1552 }
1553 }
1554}
1555
1556
1557TEST(InterpreterInstanceOf) {
1558 HandleAndZoneScope handles;
1559 i::Factory* factory = handles.main_isolate()->factory();
1560 Handle<i::String> name = factory->NewStringFromAsciiChecked("cons");
1561 Handle<i::JSFunction> func = factory->NewFunction(name);
1562 Handle<i::JSObject> instance = factory->NewJSObject(func);
1563 Handle<i::Object> other = factory->NewNumber(3.3333);
1564 Handle<i::Object> cases[] = {Handle<i::Object>::cast(instance), other};
1565 for (size_t i = 0; i < arraysize(cases); i++) {
1566 bool expected_value = (i == 0);
1567 BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
1568 Register r0(0);
1569 builder.set_locals_count(1);
1570 builder.set_context_count(0);
1571 builder.set_parameter_count(0);
1572 builder.LoadLiteral(cases[i]);
1573 builder.StoreAccumulatorInRegister(r0)
1574 .LoadLiteral(func)
1575 .CompareOperation(Token::Value::INSTANCEOF, r0, Strength::WEAK)
1576 .Return();
1577
1578 Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
1579 InterpreterTester tester(handles.main_isolate(), bytecode_array);
1580 auto callable = tester.GetCallable<>();
1581 Handle<Object> return_value = callable().ToHandleChecked();
1582 CHECK(return_value->IsBoolean());
1583 CHECK_EQ(return_value->BooleanValue(), expected_value);
1584 }
1585}
1586
1587
1588TEST(InterpreterTestIn) {
1589 HandleAndZoneScope handles;
1590 i::Factory* factory = handles.main_isolate()->factory();
1591 // Allocate an array
1592 Handle<i::JSArray> array =
1593 factory->NewJSArray(i::ElementsKind::FAST_SMI_ELEMENTS);
1594 // Check for these properties on the array object
1595 const char* properties[] = {"length", "fuzzle", "x", "0"};
1596 for (size_t i = 0; i < arraysize(properties); i++) {
1597 bool expected_value = (i == 0);
1598 BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
1599 Register r0(0);
1600 builder.set_locals_count(1);
1601 builder.set_context_count(0);
1602 builder.set_parameter_count(0);
1603 builder.LoadLiteral(factory->NewStringFromAsciiChecked(properties[i]))
1604 .StoreAccumulatorInRegister(r0)
1605 .LoadLiteral(Handle<Object>::cast(array))
1606 .CompareOperation(Token::Value::IN, r0, Strength::WEAK)
1607 .Return();
1608
1609 Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
1610 InterpreterTester tester(handles.main_isolate(), bytecode_array);
1611 auto callable = tester.GetCallable<>();
1612 Handle<Object> return_value = callable().ToHandleChecked();
1613 CHECK(return_value->IsBoolean());
1614 CHECK_EQ(return_value->BooleanValue(), expected_value);
1615 }
1616}
1617
1618
1619TEST(InterpreterUnaryNot) {
1620 HandleAndZoneScope handles;
1621 for (size_t i = 1; i < 10; i++) {
1622 bool expected_value = ((i & 1) == 1);
1623 BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
1624 Register r0(0);
1625 builder.set_locals_count(0);
1626 builder.set_context_count(0);
1627 builder.set_parameter_count(0);
1628 builder.LoadFalse();
1629 for (size_t j = 0; j < i; j++) {
1630 builder.LogicalNot();
1631 }
1632 builder.Return();
1633 Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
1634 InterpreterTester tester(handles.main_isolate(), bytecode_array);
1635 auto callable = tester.GetCallable<>();
1636 Handle<Object> return_value = callable().ToHandleChecked();
1637 CHECK(return_value->IsBoolean());
1638 CHECK_EQ(return_value->BooleanValue(), expected_value);
1639 }
1640}
1641
1642
1643static void LoadAny(BytecodeArrayBuilder* builder,
1644 v8::internal::Factory* factory, Handle<Object> obj) {
1645 if (obj->IsOddball()) {
1646 if (obj->SameValue(*factory->true_value())) {
1647 builder->LoadTrue();
1648 } else if (obj->SameValue(*factory->false_value())) {
1649 builder->LoadFalse();
1650 } else if (obj->SameValue(*factory->the_hole_value())) {
1651 builder->LoadTheHole();
1652 } else if (obj->SameValue(*factory->null_value())) {
1653 builder->LoadNull();
1654 } else if (obj->SameValue(*factory->undefined_value())) {
1655 builder->LoadUndefined();
1656 } else {
1657 UNREACHABLE();
1658 }
1659 } else if (obj->IsSmi()) {
1660 builder->LoadLiteral(*Handle<Smi>::cast(obj));
1661 } else {
1662 builder->LoadLiteral(obj);
1663 }
1664}
1665
1666
1667TEST(InterpreterUnaryNotNonBoolean) {
1668 HandleAndZoneScope handles;
1669 i::Factory* factory = handles.main_isolate()->factory();
1670
1671 std::pair<Handle<Object>, bool> object_type_tuples[] = {
1672 std::make_pair(factory->undefined_value(), true),
1673 std::make_pair(factory->null_value(), true),
1674 std::make_pair(factory->false_value(), true),
1675 std::make_pair(factory->true_value(), false),
1676 std::make_pair(factory->NewNumber(9.1), false),
1677 std::make_pair(factory->NewNumberFromInt(0), true),
1678 std::make_pair(
1679 Handle<Object>::cast(factory->NewStringFromStaticChars("hello")),
1680 false),
1681 std::make_pair(
1682 Handle<Object>::cast(factory->NewStringFromStaticChars("")), true),
1683 };
1684
1685 for (size_t i = 0; i < arraysize(object_type_tuples); i++) {
1686 BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
1687 Register r0(0);
1688 builder.set_locals_count(0);
1689 builder.set_context_count(0);
1690 builder.set_parameter_count(0);
1691 LoadAny(&builder, factory, object_type_tuples[i].first);
1692 builder.LogicalNot();
1693 builder.Return();
1694 Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
1695 InterpreterTester tester(handles.main_isolate(), bytecode_array);
1696 auto callable = tester.GetCallable<>();
1697 Handle<Object> return_value = callable().ToHandleChecked();
1698 CHECK(return_value->IsBoolean());
1699 CHECK_EQ(return_value->BooleanValue(), object_type_tuples[i].second);
1700 }
1701}
1702
1703
1704TEST(InterpreterTypeof) {
1705 HandleAndZoneScope handles;
1706
1707 std::pair<const char*, const char*> typeof_vals[] = {
1708 std::make_pair("return typeof undefined;", "undefined"),
1709 std::make_pair("return typeof null;", "object"),
1710 std::make_pair("return typeof true;", "boolean"),
1711 std::make_pair("return typeof false;", "boolean"),
1712 std::make_pair("return typeof 9.1;", "number"),
1713 std::make_pair("return typeof 7771;", "number"),
1714 std::make_pair("return typeof 'hello';", "string"),
1715 std::make_pair("return typeof global_unallocated;", "undefined"),
1716 };
1717
1718 for (size_t i = 0; i < arraysize(typeof_vals); i++) {
1719 std::string source(InterpreterTester::SourceForBody(typeof_vals[i].first));
1720 InterpreterTester tester(handles.main_isolate(), source.c_str());
1721
1722 auto callable = tester.GetCallable<>();
1723 Handle<v8::internal::String> return_value =
1724 Handle<v8::internal::String>::cast(callable().ToHandleChecked());
1725 auto actual = return_value->ToCString();
1726 CHECK_EQ(strcmp(&actual[0], typeof_vals[i].second), 0);
1727 }
1728}
1729
1730
1731TEST(InterpreterCallRuntime) {
1732 HandleAndZoneScope handles;
1733
1734 BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone());
1735 builder.set_locals_count(2);
1736 builder.set_context_count(0);
1737 builder.set_parameter_count(1);
1738 builder.LoadLiteral(Smi::FromInt(15))
1739 .StoreAccumulatorInRegister(Register(0))
1740 .LoadLiteral(Smi::FromInt(40))
1741 .StoreAccumulatorInRegister(Register(1))
1742 .CallRuntime(Runtime::kAdd, Register(0), 2)
1743 .Return();
1744 Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
1745
1746 InterpreterTester tester(handles.main_isolate(), bytecode_array);
1747 auto callable = tester.GetCallable<>();
1748
1749 Handle<Object> return_val = callable().ToHandleChecked();
1750 CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(55));
1751}
1752
1753
1754TEST(InterpreterFunctionLiteral) {
1755 HandleAndZoneScope handles;
1756
1757 // Test calling a function literal.
1758 std::string source(
1759 "function " + InterpreterTester::function_name() + "(a) {\n"
1760 " return (function(x){ return x + 2; })(a);\n"
1761 "}");
1762 InterpreterTester tester(handles.main_isolate(), source.c_str());
1763 auto callable = tester.GetCallable<Handle<Object>>();
1764
1765 Handle<i::Object> return_val = callable(
1766 Handle<Smi>(Smi::FromInt(3), handles.main_isolate())).ToHandleChecked();
1767 CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(5));
1768}
1769
1770
1771TEST(InterpreterRegExpLiterals) {
1772 HandleAndZoneScope handles;
1773 i::Isolate* isolate = handles.main_isolate();
1774 i::Factory* factory = isolate->factory();
1775
1776 std::pair<const char*, Handle<Object>> literals[] = {
1777 std::make_pair("return /abd/.exec('cccabbdd');\n",
1778 factory->null_value()),
1779 std::make_pair("return /ab+d/.exec('cccabbdd')[0];\n",
1780 factory->NewStringFromStaticChars("abbd")),
1781 std::make_pair("return /AbC/i.exec('ssaBC')[0];\n",
1782 factory->NewStringFromStaticChars("aBC")),
1783 std::make_pair("return 'ssaBC'.match(/AbC/i)[0];\n",
1784 factory->NewStringFromStaticChars("aBC")),
1785 std::make_pair("return 'ssaBCtAbC'.match(/(AbC)/gi)[1];\n",
1786 factory->NewStringFromStaticChars("AbC")),
1787 };
1788
1789 for (size_t i = 0; i < arraysize(literals); i++) {
1790 std::string source(InterpreterTester::SourceForBody(literals[i].first));
1791 InterpreterTester tester(handles.main_isolate(), source.c_str());
1792 auto callable = tester.GetCallable<>();
1793
1794 Handle<i::Object> return_value = callable().ToHandleChecked();
1795 CHECK(return_value->SameValue(*literals[i].second));
1796 }
1797}
1798
1799
1800TEST(InterpreterArrayLiterals) {
1801 HandleAndZoneScope handles;
1802 i::Isolate* isolate = handles.main_isolate();
1803 i::Factory* factory = isolate->factory();
1804
1805 std::pair<const char*, Handle<Object>> literals[] = {
1806 std::make_pair("return [][0];\n",
1807 factory->undefined_value()),
1808 std::make_pair("return [1, 3, 2][1];\n",
1809 handle(Smi::FromInt(3), isolate)),
1810 std::make_pair("return ['a', 'b', 'c'][2];\n",
1811 factory->NewStringFromStaticChars("c")),
1812 std::make_pair("var a = 100; return [a, a + 1, a + 2, a + 3][2];\n",
1813 handle(Smi::FromInt(102), isolate)),
1814 std::make_pair("return [[1, 2, 3], ['a', 'b', 'c']][1][0];\n",
1815 factory->NewStringFromStaticChars("a")),
1816 std::make_pair("var t = 't'; return [[t, t + 'est'], [1 + t]][0][1];\n",
1817 factory->NewStringFromStaticChars("test"))
1818 };
1819
1820 for (size_t i = 0; i < arraysize(literals); i++) {
1821 std::string source(InterpreterTester::SourceForBody(literals[i].first));
1822 InterpreterTester tester(handles.main_isolate(), source.c_str());
1823 auto callable = tester.GetCallable<>();
1824
1825 Handle<i::Object> return_value = callable().ToHandleChecked();
1826 CHECK(return_value->SameValue(*literals[i].second));
1827 }
1828}
1829
1830
1831TEST(InterpreterObjectLiterals) {
1832 HandleAndZoneScope handles;
1833 i::Isolate* isolate = handles.main_isolate();
1834 i::Factory* factory = isolate->factory();
1835
1836 std::pair<const char*, Handle<Object>> literals[] = {
1837 std::make_pair("return { }.name;",
1838 factory->undefined_value()),
1839 std::make_pair("return { name: 'string', val: 9.2 }.name;",
1840 factory->NewStringFromStaticChars("string")),
1841 std::make_pair("var a = 15; return { name: 'string', val: a }.val;",
1842 handle(Smi::FromInt(15), isolate)),
1843 std::make_pair("var a = 5; return { val: a, val: a + 1 }.val;",
1844 handle(Smi::FromInt(6), isolate)),
1845 std::make_pair("return { func: function() { return 'test' } }.func();",
1846 factory->NewStringFromStaticChars("test")),
1847 std::make_pair("return { func(a) { return a + 'st'; } }.func('te');",
1848 factory->NewStringFromStaticChars("test")),
1849 std::make_pair("return { get a() { return 22; } }.a;",
1850 handle(Smi::FromInt(22), isolate)),
1851 std::make_pair("var a = { get b() { return this.x + 't'; },\n"
1852 " set b(val) { this.x = val + 's' } };\n"
1853 "a.b = 'te';\n"
1854 "return a.b;",
1855 factory->NewStringFromStaticChars("test")),
1856 std::make_pair("var a = 123; return { 1: a }[1];",
1857 handle(Smi::FromInt(123), isolate)),
1858 std::make_pair("return Object.getPrototypeOf({ __proto__: null });",
1859 factory->null_value()),
1860 std::make_pair("var a = 'test'; return { [a]: 1 }.test;",
1861 handle(Smi::FromInt(1), isolate)),
1862 std::make_pair("var a = 'test'; return { b: a, [a]: a + 'ing' }['test']",
1863 factory->NewStringFromStaticChars("testing")),
1864 std::make_pair("var a = 'proto_str';\n"
1865 "var b = { [a]: 1, __proto__: { var : a } };\n"
1866 "return Object.getPrototypeOf(b).var",
1867 factory->NewStringFromStaticChars("proto_str")),
1868 std::make_pair("var n = 'name';\n"
1869 "return { [n]: 'val', get a() { return 987 } }['a'];",
1870 handle(Smi::FromInt(987), isolate)),
1871 };
1872
1873 for (size_t i = 0; i < arraysize(literals); i++) {
1874 std::string source(InterpreterTester::SourceForBody(literals[i].first));
1875 InterpreterTester tester(handles.main_isolate(), source.c_str());
1876 auto callable = tester.GetCallable<>();
1877
1878 Handle<i::Object> return_value = callable().ToHandleChecked();
1879 CHECK(return_value->SameValue(*literals[i].second));
1880 }
1881}
1882
1883
1884TEST(InterpreterConstruct) {
1885 HandleAndZoneScope handles;
1886
1887 std::string source(
1888 "function counter() { this.count = 0; }\n"
1889 "function " +
1890 InterpreterTester::function_name() +
1891 "() {\n"
1892 " var c = new counter();\n"
1893 " return c.count;\n"
1894 "}");
1895 InterpreterTester tester(handles.main_isolate(), source.c_str());
1896 auto callable = tester.GetCallable<>();
1897
1898 Handle<Object> return_val = callable().ToHandleChecked();
1899 CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(0));
1900}
1901
1902
1903TEST(InterpreterConstructWithArgument) {
1904 HandleAndZoneScope handles;
1905
1906 std::string source(
1907 "function counter(arg0) { this.count = 17; this.x = arg0; }\n"
1908 "function " +
1909 InterpreterTester::function_name() +
1910 "() {\n"
1911 " var c = new counter(3);\n"
1912 " return c.x;\n"
1913 "}");
1914 InterpreterTester tester(handles.main_isolate(), source.c_str());
1915 auto callable = tester.GetCallable<>();
1916
1917 Handle<Object> return_val = callable().ToHandleChecked();
1918 CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(3));
1919}
1920
1921
1922TEST(InterpreterConstructWithArguments) {
1923 HandleAndZoneScope handles;
1924
1925 std::string source(
1926 "function counter(arg0, arg1) {\n"
1927 " this.count = 7; this.x = arg0; this.y = arg1;\n"
1928 "}\n"
1929 "function " +
1930 InterpreterTester::function_name() +
1931 "() {\n"
1932 " var c = new counter(3, 5);\n"
1933 " return c.count + c.x + c.y;\n"
1934 "}");
1935 InterpreterTester tester(handles.main_isolate(), source.c_str());
1936 auto callable = tester.GetCallable<>();
1937
1938 Handle<Object> return_val = callable().ToHandleChecked();
1939 CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(15));
1940}
1941
1942
1943TEST(InterpreterContextVariables) {
1944 HandleAndZoneScope handles;
1945 i::Isolate* isolate = handles.main_isolate();
1946
1947 std::ostringstream unique_vars;
1948 for (int i = 0; i < 250; i++) {
1949 unique_vars << "var a" << i << " = 0;";
1950 }
1951 std::pair<std::string, Handle<Object>> context_vars[] = {
1952 std::make_pair("var a; (function() { a = 1; })(); return a;",
1953 handle(Smi::FromInt(1), isolate)),
1954 std::make_pair("var a = 10; (function() { a; })(); return a;",
1955 handle(Smi::FromInt(10), isolate)),
1956 std::make_pair("var a = 20; var b = 30;\n"
1957 "return (function() { return a + b; })();",
1958 handle(Smi::FromInt(50), isolate)),
1959 std::make_pair("'use strict'; let a = 1;\n"
1960 "{ let b = 2; return (function() { return a + b; })(); }",
1961 handle(Smi::FromInt(3), isolate)),
1962 std::make_pair("'use strict'; let a = 10;\n"
1963 "{ let b = 20; var c = function() { [a, b] };\n"
1964 " return a + b; }",
1965 handle(Smi::FromInt(30), isolate)),
1966 std::make_pair("'use strict';" + unique_vars.str() +
1967 "eval(); var b = 100; return b;",
1968 handle(Smi::FromInt(100), isolate)),
1969 };
1970
1971 for (size_t i = 0; i < arraysize(context_vars); i++) {
1972 std::string source(
1973 InterpreterTester::SourceForBody(context_vars[i].first.c_str()));
1974 InterpreterTester tester(handles.main_isolate(), source.c_str());
1975 auto callable = tester.GetCallable<>();
1976
1977 Handle<i::Object> return_value = callable().ToHandleChecked();
1978 CHECK(return_value->SameValue(*context_vars[i].second));
1979 }
1980}
1981
1982
1983TEST(InterpreterContextParameters) {
1984 HandleAndZoneScope handles;
1985 i::Isolate* isolate = handles.main_isolate();
1986
1987 std::pair<const char*, Handle<Object>> context_params[] = {
1988 std::make_pair("return (function() { return arg1; })();",
1989 handle(Smi::FromInt(1), isolate)),
1990 std::make_pair("(function() { arg1 = 4; })(); return arg1;",
1991 handle(Smi::FromInt(4), isolate)),
1992 std::make_pair("(function() { arg3 = arg2 - arg1; })(); return arg3;",
1993 handle(Smi::FromInt(1), isolate)),
1994 };
1995
1996 for (size_t i = 0; i < arraysize(context_params); i++) {
1997 std::string source = "function " + InterpreterTester::function_name() +
1998 "(arg1, arg2, arg3) {" + context_params[i].first + "}";
1999 InterpreterTester tester(handles.main_isolate(), source.c_str());
2000 auto callable =
2001 tester.GetCallable<Handle<Object>, Handle<Object>, Handle<Object>>();
2002
2003 Handle<Object> a1 = handle(Smi::FromInt(1), isolate);
2004 Handle<Object> a2 = handle(Smi::FromInt(2), isolate);
2005 Handle<Object> a3 = handle(Smi::FromInt(3), isolate);
2006 Handle<i::Object> return_value = callable(a1, a2, a3).ToHandleChecked();
2007 CHECK(return_value->SameValue(*context_params[i].second));
2008 }
2009}
2010
2011
2012TEST(InterpreterOuterContextVariables) {
2013 HandleAndZoneScope handles;
2014 i::Isolate* isolate = handles.main_isolate();
2015
2016 std::pair<const char*, Handle<Object>> context_vars[] = {
2017 std::make_pair("return outerVar * innerArg;",
2018 handle(Smi::FromInt(200), isolate)),
2019 std::make_pair("outerVar = innerArg; return outerVar",
2020 handle(Smi::FromInt(20), isolate)),
2021 };
2022
2023 std::string header(
2024 "function Outer() {"
2025 " var outerVar = 10;"
2026 " function Inner(innerArg) {"
2027 " this.innerFunc = function() { ");
2028 std::string footer(
2029 " }}"
2030 " this.getInnerFunc = function() { return new Inner(20).innerFunc; }"
2031 "}"
2032 "var f = new Outer().getInnerFunc();");
2033
2034 for (size_t i = 0; i < arraysize(context_vars); i++) {
2035 std::string source = header + context_vars[i].first + footer;
2036 InterpreterTester tester(handles.main_isolate(), source.c_str(), "*");
2037 auto callable = tester.GetCallable<>();
2038
2039 Handle<i::Object> return_value = callable().ToHandleChecked();
2040 CHECK(return_value->SameValue(*context_vars[i].second));
2041 }
2042}
2043
2044
2045TEST(InterpreterComma) {
2046 HandleAndZoneScope handles;
2047 i::Isolate* isolate = handles.main_isolate();
2048 i::Factory* factory = isolate->factory();
2049
2050 std::pair<const char*, Handle<Object>> literals[] = {
2051 std::make_pair("var a; return 0, a;\n", factory->undefined_value()),
2052 std::make_pair("return 'a', 2.2, 3;\n",
2053 handle(Smi::FromInt(3), isolate)),
2054 std::make_pair("return 'a', 'b', 'c';\n",
2055 factory->NewStringFromStaticChars("c")),
2056 std::make_pair("return 3.2, 2.3, 4.5;\n", factory->NewNumber(4.5)),
2057 std::make_pair("var a = 10; return b = a, b = b+1;\n",
2058 handle(Smi::FromInt(11), isolate)),
2059 std::make_pair("var a = 10; return b = a, b = b+1, b + 10;\n",
2060 handle(Smi::FromInt(21), isolate))};
2061
2062 for (size_t i = 0; i < arraysize(literals); i++) {
2063 std::string source(InterpreterTester::SourceForBody(literals[i].first));
2064 InterpreterTester tester(handles.main_isolate(), source.c_str());
2065 auto callable = tester.GetCallable<>();
2066
2067 Handle<i::Object> return_value = callable().ToHandleChecked();
2068 CHECK(return_value->SameValue(*literals[i].second));
2069 }
2070}
2071
2072
2073TEST(InterpreterLogicalOr) {
2074 HandleAndZoneScope handles;
2075 i::Isolate* isolate = handles.main_isolate();
2076 i::Factory* factory = isolate->factory();
2077
2078 std::pair<const char*, Handle<Object>> literals[] = {
2079 std::make_pair("var a, b; return a || b;\n", factory->undefined_value()),
2080 std::make_pair("var a, b = 10; return a || b;\n",
2081 handle(Smi::FromInt(10), isolate)),
2082 std::make_pair("var a = '0', b = 10; return a || b;\n",
2083 factory->NewStringFromStaticChars("0")),
2084 std::make_pair("return 0 || 3.2;\n", factory->NewNumber(3.2)),
2085 std::make_pair("return 'a' || 0;\n",
2086 factory->NewStringFromStaticChars("a")),
2087 std::make_pair("var a = '0', b = 10; return (a == 0) || b;\n",
2088 factory->true_value())};
2089
2090 for (size_t i = 0; i < arraysize(literals); i++) {
2091 std::string source(InterpreterTester::SourceForBody(literals[i].first));
2092 InterpreterTester tester(handles.main_isolate(), source.c_str());
2093 auto callable = tester.GetCallable<>();
2094
2095 Handle<i::Object> return_value = callable().ToHandleChecked();
2096 CHECK(return_value->SameValue(*literals[i].second));
2097 }
2098}
2099
2100
2101TEST(InterpreterLogicalAnd) {
2102 HandleAndZoneScope handles;
2103 i::Isolate* isolate = handles.main_isolate();
2104 i::Factory* factory = isolate->factory();
2105
2106 std::pair<const char*, Handle<Object>> literals[] = {
2107 std::make_pair("var a, b = 10; return a && b;\n",
2108 factory->undefined_value()),
2109 std::make_pair("var a = 0, b = 10; return a && b / a;\n",
2110 handle(Smi::FromInt(0), isolate)),
2111 std::make_pair("var a = '0', b = 10; return a && b;\n",
2112 handle(Smi::FromInt(10), isolate)),
2113 std::make_pair("return 0.0 && 3.2;\n", handle(Smi::FromInt(0), isolate)),
2114 std::make_pair("return 'a' && 'b';\n",
2115 factory->NewStringFromStaticChars("b")),
2116 std::make_pair("return 'a' && 0 || 'b', 'c';\n",
2117 factory->NewStringFromStaticChars("c")),
2118 std::make_pair("var x = 1, y = 3; return x && 0 + 1 || y;\n",
2119 handle(Smi::FromInt(1), isolate)),
2120 std::make_pair("var x = 1, y = 3; return (x == 1) && (3 == 3) || y;\n",
2121 factory->true_value())};
2122
2123 for (size_t i = 0; i < arraysize(literals); i++) {
2124 std::string source(InterpreterTester::SourceForBody(literals[i].first));
2125 InterpreterTester tester(handles.main_isolate(), source.c_str());
2126 auto callable = tester.GetCallable<>();
2127
2128 Handle<i::Object> return_value = callable().ToHandleChecked();
2129 CHECK(return_value->SameValue(*literals[i].second));
2130 }
2131}
2132
2133
2134TEST(InterpreterTryCatch) {
2135 HandleAndZoneScope handles;
2136
2137 // TODO(rmcilroy): modify tests when we have real try catch support.
2138 std::string source(InterpreterTester::SourceForBody(
2139 "var a = 1; try { a = a + 1; } catch(e) { a = a + 2; }; return a;"));
2140 InterpreterTester tester(handles.main_isolate(), source.c_str());
2141 auto callable = tester.GetCallable<>();
2142
2143 Handle<Object> return_val = callable().ToHandleChecked();
2144 CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(2));
2145}
2146
2147
2148TEST(InterpreterTryFinally) {
2149 HandleAndZoneScope handles;
2150
2151 // TODO(rmcilroy): modify tests when we have real try finally support.
2152 std::string source(InterpreterTester::SourceForBody(
2153 "var a = 1; try { a = a + 1; } finally { a = a + 2; }; return a;"));
2154 InterpreterTester tester(handles.main_isolate(), source.c_str());
2155 auto callable = tester.GetCallable<>();
2156
2157 Handle<Object> return_val = callable().ToHandleChecked();
2158 CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(4));
2159}
2160
2161
2162TEST(InterpreterThrow) {
2163 HandleAndZoneScope handles;
2164 i::Isolate* isolate = handles.main_isolate();
2165 i::Factory* factory = isolate->factory();
2166
2167 // TODO(rmcilroy): modify tests when we have real try catch support.
2168 std::pair<const char*, Handle<Object>> throws[] = {
2169 std::make_pair("throw undefined;\n",
2170 factory->undefined_value()),
2171 std::make_pair("throw 1;\n",
2172 handle(Smi::FromInt(1), isolate)),
2173 std::make_pair("throw 'Error';\n",
2174 factory->NewStringFromStaticChars("Error")),
2175 std::make_pair("var a = true; if (a) { throw 'Error'; }\n",
2176 factory->NewStringFromStaticChars("Error")),
2177 std::make_pair("var a = false; if (a) { throw 'Error'; }\n",
2178 factory->undefined_value()),
2179 std::make_pair("throw 'Error1'; throw 'Error2'\n",
2180 factory->NewStringFromStaticChars("Error1")),
2181 };
2182
2183 const char* try_wrapper =
2184 "(function() { try { f(); } catch(e) { return e; }})()";
2185
2186 for (size_t i = 0; i < arraysize(throws); i++) {
2187 std::string source(InterpreterTester::SourceForBody(throws[i].first));
2188 InterpreterTester tester(handles.main_isolate(), source.c_str());
2189 tester.GetCallable<>();
2190 Handle<Object> thrown_obj = v8::Utils::OpenHandle(*CompileRun(try_wrapper));
2191 CHECK(thrown_obj->SameValue(*throws[i].second));
2192 }
2193}
2194
2195
2196TEST(InterpreterCountOperators) {
2197 HandleAndZoneScope handles;
2198 i::Isolate* isolate = handles.main_isolate();
2199 i::Factory* factory = isolate->factory();
2200
2201 std::pair<const char*, Handle<Object>> count_ops[] = {
2202 std::make_pair("var a = 1; return ++a;",
2203 handle(Smi::FromInt(2), isolate)),
2204 std::make_pair("var a = 1; return a++;",
2205 handle(Smi::FromInt(1), isolate)),
2206 std::make_pair("var a = 5; return --a;",
2207 handle(Smi::FromInt(4), isolate)),
2208 std::make_pair("var a = 5; return a--;",
2209 handle(Smi::FromInt(5), isolate)),
2210 std::make_pair("var a = 5.2; return --a;",
2211 factory->NewHeapNumber(4.2)),
2212 std::make_pair("var a = 'string'; return ++a;",
2213 factory->nan_value()),
2214 std::make_pair("var a = 'string'; return a--;",
2215 factory->nan_value()),
2216 std::make_pair("var a = true; return ++a;",
2217 handle(Smi::FromInt(2), isolate)),
2218 std::make_pair("var a = false; return a--;",
2219 handle(Smi::FromInt(0), isolate)),
2220 std::make_pair("var a = { val: 11 }; return ++a.val;",
2221 handle(Smi::FromInt(12), isolate)),
2222 std::make_pair("var a = { val: 11 }; return a.val--;",
2223 handle(Smi::FromInt(11), isolate)),
2224 std::make_pair("var a = { val: 11 }; return ++a.val;",
2225 handle(Smi::FromInt(12), isolate)),
2226 std::make_pair("var name = 'val'; var a = { val: 22 }; return --a[name];",
2227 handle(Smi::FromInt(21), isolate)),
2228 std::make_pair("var name = 'val'; var a = { val: 22 }; return a[name]++;",
2229 handle(Smi::FromInt(22), isolate)),
2230 std::make_pair("var a = 1; (function() { a = 2 })(); return ++a;",
2231 handle(Smi::FromInt(3), isolate)),
2232 std::make_pair("var a = 1; (function() { a = 2 })(); return a--;",
2233 handle(Smi::FromInt(2), isolate)),
2234 std::make_pair("var i = 5; while(i--) {}; return i;",
2235 handle(Smi::FromInt(-1), isolate)),
2236 std::make_pair("var i = 1; if(i--) { return 1; } else { return 2; };",
2237 handle(Smi::FromInt(1), isolate)),
2238 std::make_pair("var i = -2; do {} while(i++) {}; return i;",
2239 handle(Smi::FromInt(1), isolate)),
2240 std::make_pair("var i = -1; for(; i++; ) {}; return i",
2241 handle(Smi::FromInt(1), isolate)),
2242 std::make_pair("var i = 20; switch(i++) {\n"
2243 " case 20: return 1;\n"
2244 " default: return 2;\n"
2245 "}",
2246 handle(Smi::FromInt(1), isolate)),
2247 };
2248
2249 for (size_t i = 0; i < arraysize(count_ops); i++) {
2250 std::string source(InterpreterTester::SourceForBody(count_ops[i].first));
2251 InterpreterTester tester(handles.main_isolate(), source.c_str());
2252 auto callable = tester.GetCallable<>();
2253
2254 Handle<i::Object> return_value = callable().ToHandleChecked();
2255 CHECK(return_value->SameValue(*count_ops[i].second));
2256 }
2257}
2258
2259
2260TEST(InterpreterGlobalCountOperators) {
2261 HandleAndZoneScope handles;
2262 i::Isolate* isolate = handles.main_isolate();
2263
2264 std::pair<const char*, Handle<Object>> count_ops[] = {
2265 std::make_pair("var global = 100;function f(){ return ++global; }",
2266 handle(Smi::FromInt(101), isolate)),
2267 std::make_pair("var global = 100; function f(){ return --global; }",
2268 handle(Smi::FromInt(99), isolate)),
2269 std::make_pair("var global = 100; function f(){ return global++; }",
2270 handle(Smi::FromInt(100), isolate)),
2271 std::make_pair("unallocated = 200; function f(){ return ++unallocated; }",
2272 handle(Smi::FromInt(201), isolate)),
2273 std::make_pair("unallocated = 200; function f(){ return --unallocated; }",
2274 handle(Smi::FromInt(199), isolate)),
2275 std::make_pair("unallocated = 200; function f(){ return unallocated++; }",
2276 handle(Smi::FromInt(200), isolate)),
2277 };
2278
2279 for (size_t i = 0; i < arraysize(count_ops); i++) {
2280 InterpreterTester tester(handles.main_isolate(), count_ops[i].first);
2281 auto callable = tester.GetCallable<>();
2282
2283 Handle<i::Object> return_value = callable().ToHandleChecked();
2284 CHECK(return_value->SameValue(*count_ops[i].second));
2285 }
2286}
2287
2288
2289TEST(InterpreterCompoundExpressions) {
2290 HandleAndZoneScope handles;
2291 i::Isolate* isolate = handles.main_isolate();
2292 i::Factory* factory = isolate->factory();
2293
2294 std::pair<const char*, Handle<Object>> compound_expr[] = {
2295 std::make_pair("var a = 1; a += 2; return a;",
2296 Handle<Object>(Smi::FromInt(3), isolate)),
2297 std::make_pair("var a = 10; a /= 2; return a;",
2298 Handle<Object>(Smi::FromInt(5), isolate)),
2299 std::make_pair("var a = 'test'; a += 'ing'; return a;",
2300 factory->NewStringFromStaticChars("testing")),
2301 std::make_pair("var a = { val: 2 }; a.val *= 2; return a.val;",
2302 Handle<Object>(Smi::FromInt(4), isolate)),
2303 std::make_pair("var a = 1; (function f() { a = 2; })(); a += 24;"
2304 "return a;",
2305 Handle<Object>(Smi::FromInt(26), isolate)),
2306 };
2307
2308 for (size_t i = 0; i < arraysize(compound_expr); i++) {
2309 std::string source(
2310 InterpreterTester::SourceForBody(compound_expr[i].first));
2311 InterpreterTester tester(handles.main_isolate(), source.c_str());
2312 auto callable = tester.GetCallable<>();
2313
2314 Handle<i::Object> return_value = callable().ToHandleChecked();
2315 CHECK(return_value->SameValue(*compound_expr[i].second));
2316 }
2317}
2318
2319
2320TEST(InterpreterGlobalCompoundExpressions) {
2321 HandleAndZoneScope handles;
2322 i::Isolate* isolate = handles.main_isolate();
2323
2324 std::pair<const char*, Handle<Object>> compound_expr[2] = {
2325 std::make_pair("var global = 100;"
2326 "function f() { global += 20; return global; }",
2327 Handle<Object>(Smi::FromInt(120), isolate)),
2328 std::make_pair("unallocated = 100;"
2329 "function f() { unallocated -= 20; return unallocated; }",
2330 Handle<Object>(Smi::FromInt(80), isolate)),
2331 };
2332
2333 for (size_t i = 0; i < arraysize(compound_expr); i++) {
2334 InterpreterTester tester(handles.main_isolate(), compound_expr[i].first);
2335 auto callable = tester.GetCallable<>();
2336
2337 Handle<i::Object> return_value = callable().ToHandleChecked();
2338 CHECK(return_value->SameValue(*compound_expr[i].second));
2339 }
2340}
2341
2342
2343TEST(InterpreterCreateArguments) {
2344 HandleAndZoneScope handles;
2345 i::Isolate* isolate = handles.main_isolate();
2346 i::Factory* factory = isolate->factory();
2347
2348 std::pair<const char*, int> create_args[] = {
2349 std::make_pair("function f() { return arguments[0]; }", 0),
2350 std::make_pair("function f(a) { return arguments[0]; }", 0),
2351 std::make_pair("function f() { return arguments[2]; }", 2),
2352 std::make_pair("function f(a) { return arguments[2]; }", 2),
2353 std::make_pair("function f(a, b, c, d) { return arguments[2]; }", 2),
2354 std::make_pair("function f(a) {"
2355 "'use strict'; return arguments[0]; }",
2356 0),
2357 std::make_pair("function f(a, b, c, d) {"
2358 "'use strict'; return arguments[2]; }",
2359 2),
2360 // Check arguments are mapped in sloppy mode and unmapped in strict.
2361 std::make_pair("function f(a, b, c, d) {"
2362 " c = b; return arguments[2]; }",
2363 1),
2364 std::make_pair("function f(a, b, c, d) {"
2365 " 'use strict'; c = b; return arguments[2]; }",
2366 2),
2367 };
2368
2369 // Test passing no arguments.
2370 for (size_t i = 0; i < arraysize(create_args); i++) {
2371 InterpreterTester tester(handles.main_isolate(), create_args[i].first);
2372 auto callable = tester.GetCallable<>();
2373 Handle<Object> return_val = callable().ToHandleChecked();
2374 CHECK(return_val.is_identical_to(factory->undefined_value()));
2375 }
2376
2377 // Test passing one argument.
2378 for (size_t i = 0; i < arraysize(create_args); i++) {
2379 InterpreterTester tester(handles.main_isolate(), create_args[i].first);
2380 auto callable = tester.GetCallable<Handle<Object>>();
2381 Handle<Object> return_val =
2382 callable(handle(Smi::FromInt(40), isolate)).ToHandleChecked();
2383 if (create_args[i].second == 0) {
2384 CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(40));
2385 } else {
2386 CHECK(return_val.is_identical_to(factory->undefined_value()));
2387 }
2388 }
2389
2390 // Test passing three argument.
2391 for (size_t i = 0; i < arraysize(create_args); i++) {
2392 Handle<Object> args[3] = {
2393 handle(Smi::FromInt(40), isolate),
2394 handle(Smi::FromInt(60), isolate),
2395 handle(Smi::FromInt(80), isolate),
2396 };
2397
2398 InterpreterTester tester(handles.main_isolate(), create_args[i].first);
2399 auto callable =
2400 tester.GetCallable<Handle<Object>, Handle<Object>, Handle<Object>>();
2401 Handle<Object> return_val =
2402 callable(args[0], args[1], args[2]).ToHandleChecked();
2403 CHECK(return_val->SameValue(*args[create_args[i].second]));
2404 }
2405}
2406
2407
2408TEST(InterpreterConditional) {
2409 HandleAndZoneScope handles;
2410 i::Isolate* isolate = handles.main_isolate();
2411
2412 std::pair<const char*, Handle<Object>> conditional[] = {
2413 std::make_pair("return true ? 2 : 3;",
2414 handle(Smi::FromInt(2), isolate)),
2415 std::make_pair("return false ? 2 : 3;",
2416 handle(Smi::FromInt(3), isolate)),
2417 std::make_pair("var a = 1; return a ? 20 : 30;",
2418 handle(Smi::FromInt(20), isolate)),
2419 std::make_pair("var a = 1; return a ? 20 : 30;",
2420 handle(Smi::FromInt(20), isolate)),
2421 std::make_pair("var a = 'string'; return a ? 20 : 30;",
2422 handle(Smi::FromInt(20), isolate)),
2423 std::make_pair("var a = undefined; return a ? 20 : 30;",
2424 handle(Smi::FromInt(30), isolate)),
2425 std::make_pair("return 1 ? 2 ? 3 : 4 : 5;",
2426 handle(Smi::FromInt(3), isolate)),
2427 std::make_pair("return 0 ? 2 ? 3 : 4 : 5;",
2428 handle(Smi::FromInt(5), isolate)),
2429 };
2430
2431 for (size_t i = 0; i < arraysize(conditional); i++) {
2432 std::string source(InterpreterTester::SourceForBody(conditional[i].first));
2433 InterpreterTester tester(handles.main_isolate(), source.c_str());
2434 auto callable = tester.GetCallable<>();
2435
2436 Handle<i::Object> return_value = callable().ToHandleChecked();
2437 CHECK(return_value->SameValue(*conditional[i].second));
2438 }
2439}
2440
2441
2442TEST(InterpreterDelete) {
2443 HandleAndZoneScope handles;
2444 i::Isolate* isolate = handles.main_isolate();
2445 i::Factory* factory = isolate->factory();
2446
2447 // Tests for delete for local variables that work both in strict
2448 // and sloppy modes
2449 std::pair<const char*, Handle<Object>> test_delete[] = {
2450 std::make_pair(
2451 "var a = { x:10, y:'abc', z:30.2}; delete a.x; return a.x;\n",
2452 factory->undefined_value()),
2453 std::make_pair(
2454 "var b = { x:10, y:'abc', z:30.2}; delete b.x; return b.y;\n",
2455 factory->NewStringFromStaticChars("abc")),
2456 std::make_pair("var c = { x:10, y:'abc', z:30.2}; var d = c; delete d.x; "
2457 "return c.x;\n",
2458 factory->undefined_value()),
2459 std::make_pair("var e = { x:10, y:'abc', z:30.2}; var g = e; delete g.x; "
2460 "return e.y;\n",
2461 factory->NewStringFromStaticChars("abc")),
2462 std::make_pair("var a = { x:10, y:'abc', z:30.2};\n"
2463 "var b = a;"
2464 "delete b.x;"
2465 "return b.x;\n",
2466 factory->undefined_value()),
2467 std::make_pair("var a = {1:10};\n"
2468 "(function f1() {return a;});"
2469 "return delete a[1];",
2470 factory->ToBoolean(true)),
2471 std::make_pair("return delete this;", factory->ToBoolean(true)),
2472 std::make_pair("return delete 'test';", factory->ToBoolean(true))};
2473
2474 // Test delete in sloppy mode
2475 for (size_t i = 0; i < arraysize(test_delete); i++) {
2476 std::string source(InterpreterTester::SourceForBody(test_delete[i].first));
2477 InterpreterTester tester(handles.main_isolate(), source.c_str());
2478 auto callable = tester.GetCallable<>();
2479
2480 Handle<i::Object> return_value = callable().ToHandleChecked();
2481 CHECK(return_value->SameValue(*test_delete[i].second));
2482 }
2483
2484 // Test delete in strict mode
2485 for (size_t i = 0; i < arraysize(test_delete); i++) {
2486 std::string strict_test =
2487 "'use strict'; " + std::string(test_delete[i].first);
2488 std::string source(InterpreterTester::SourceForBody(strict_test.c_str()));
2489 InterpreterTester tester(handles.main_isolate(), source.c_str());
2490 auto callable = tester.GetCallable<>();
2491
2492 Handle<i::Object> return_value = callable().ToHandleChecked();
2493 CHECK(return_value->SameValue(*test_delete[i].second));
2494 }
2495}
2496
2497
2498TEST(InterpreterDeleteSloppyUnqualifiedIdentifier) {
2499 HandleAndZoneScope handles;
2500 i::Isolate* isolate = handles.main_isolate();
2501 i::Factory* factory = isolate->factory();
2502
2503 // These tests generate a syntax error for strict mode. We don't
2504 // test for it here.
2505 std::pair<const char*, Handle<Object>> test_delete[] = {
2506 std::make_pair("var sloppy_a = { x:10, y:'abc'};\n"
2507 "var sloppy_b = delete sloppy_a;\n"
2508 "if (delete sloppy_a) {\n"
2509 " return undefined;\n"
2510 "} else {\n"
2511 " return sloppy_a.x;\n"
2512 "}\n",
2513 Handle<Object>(Smi::FromInt(10), isolate)),
2514 // TODO(mythria) When try-catch is implemented change the tests to check
2515 // if delete actually deletes
2516 std::make_pair("sloppy_a = { x:10, y:'abc'};\n"
2517 "var sloppy_b = delete sloppy_a;\n"
2518 // "try{return a.x;} catch(e) {return b;}\n"
2519 "return sloppy_b;",
2520 factory->ToBoolean(true)),
2521 std::make_pair("sloppy_a = { x:10, y:'abc'};\n"
2522 "var sloppy_b = delete sloppy_c;\n"
2523 "return sloppy_b;",
2524 factory->ToBoolean(true))};
2525
2526 for (size_t i = 0; i < arraysize(test_delete); i++) {
2527 std::string source(InterpreterTester::SourceForBody(test_delete[i].first));
2528 InterpreterTester tester(handles.main_isolate(), source.c_str());
2529 auto callable = tester.GetCallable<>();
2530
2531 Handle<i::Object> return_value = callable().ToHandleChecked();
2532 CHECK(return_value->SameValue(*test_delete[i].second));
2533 }
2534}
2535
2536
2537TEST(InterpreterGlobalDelete) {
2538 HandleAndZoneScope handles;
2539 i::Isolate* isolate = handles.main_isolate();
2540 i::Factory* factory = isolate->factory();
2541
2542 std::pair<const char*, Handle<Object>> test_global_delete[] = {
2543 std::make_pair("var a = { x:10, y:'abc', z:30.2 };\n"
2544 "function f() {\n"
2545 " delete a.x;\n"
2546 " return a.x;\n"
2547 "}\n"
2548 "f();\n",
2549 factory->undefined_value()),
2550 std::make_pair("var b = {1:10, 2:'abc', 3:30.2 };\n"
2551 "function f() {\n"
2552 " delete b[2];\n"
2553 " return b[1];\n"
2554 " }\n"
2555 "f();\n",
2556 Handle<Object>(Smi::FromInt(10), isolate)),
2557 std::make_pair("var c = { x:10, y:'abc', z:30.2 };\n"
2558 "function f() {\n"
2559 " var d = c;\n"
2560 " delete d.y;\n"
2561 " return d.x;\n"
2562 "}\n"
2563 "f();\n",
2564 Handle<Object>(Smi::FromInt(10), isolate)),
2565 std::make_pair("e = { x:10, y:'abc' };\n"
2566 "function f() {\n"
2567 " return delete e;\n"
2568 "}\n"
2569 "f();\n",
2570 factory->ToBoolean(true)),
2571 std::make_pair("var g = { x:10, y:'abc' };\n"
2572 "function f() {\n"
2573 " return delete g;\n"
2574 "}\n"
2575 "f();\n",
2576 factory->ToBoolean(false)),
2577 std::make_pair("function f() {\n"
2578 " var obj = {h:10, f1() {return delete this;}};\n"
2579 " return obj.f1();\n"
2580 "}\n"
2581 "f();",
2582 factory->ToBoolean(true)),
2583 std::make_pair("function f() {\n"
2584 " var obj = {h:10,\n"
2585 " f1() {\n"
2586 " 'use strict';\n"
2587 " return delete this.h;}};\n"
2588 " return obj.f1();\n"
2589 "}\n"
2590 "f();",
2591 factory->ToBoolean(true))};
2592
2593 for (size_t i = 0; i < arraysize(test_global_delete); i++) {
2594 InterpreterTester tester(handles.main_isolate(),
2595 test_global_delete[i].first);
2596 auto callable = tester.GetCallable<>();
2597
2598 Handle<i::Object> return_value = callable().ToHandleChecked();
2599 CHECK(return_value->SameValue(*test_global_delete[i].second));
2600 }
2601}
2602
2603
2604TEST(InterpreterBasicLoops) {
2605 HandleAndZoneScope handles;
2606 i::Isolate* isolate = handles.main_isolate();
2607 i::Factory* factory = isolate->factory();
2608
2609 std::pair<const char*, Handle<Object>> loops[] = {
2610 std::make_pair("var a = 10; var b = 1;\n"
2611 "while (a) {\n"
2612 " b = b * 2;\n"
2613 " a = a - 1;\n"
2614 "};\n"
2615 "return b;\n",
2616 factory->NewHeapNumber(1024)),
2617 std::make_pair("var a = 1; var b = 1;\n"
2618 "do {\n"
2619 " b = b * 2;\n"
2620 " --a;\n"
2621 "} while(a);\n"
2622 "return b;\n",
2623 handle(Smi::FromInt(2), isolate)),
2624 std::make_pair("var b = 1;\n"
2625 "for ( var a = 10; a; a--) {\n"
2626 " b *= 2;\n"
2627 "}\n"
2628 "return b;",
2629 factory->NewHeapNumber(1024)),
2630 std::make_pair("var a = 10; var b = 1;\n"
2631 "while (a > 0) {\n"
2632 " b = b * 2;\n"
2633 " a = a - 1;\n"
2634 "};\n"
2635 "return b;\n",
2636 factory->NewHeapNumber(1024)),
2637 std::make_pair("var a = 1; var b = 1;\n"
2638 "do {\n"
2639 " b = b * 2;\n"
2640 " --a;\n"
2641 "} while(a);\n"
2642 "return b;\n",
2643 handle(Smi::FromInt(2), isolate)),
2644 std::make_pair("var b = 1;\n"
2645 "for ( var a = 10; a > 0; a--) {\n"
2646 " b *= 2;\n"
2647 "}\n"
2648 "return b;",
2649 factory->NewHeapNumber(1024)),
2650 std::make_pair("var a = 10; var b = 1;\n"
2651 "while (false) {\n"
2652 " b = b * 2;\n"
2653 " a = a - 1;\n"
2654 "}\n"
2655 "return b;\n",
2656 Handle<Object>(Smi::FromInt(1), isolate)),
2657 std::make_pair("var a = 10; var b = 1;\n"
2658 "while (true) {\n"
2659 " b = b * 2;\n"
2660 " a = a - 1;\n"
2661 " if (a == 0) break;"
2662 " continue;"
2663 "}\n"
2664 "return b;\n",
2665 factory->NewHeapNumber(1024)),
2666 std::make_pair("var a = 10; var b = 1;\n"
2667 "do {\n"
2668 " b = b * 2;\n"
2669 " a = a - 1;\n"
2670 " if (a == 0) break;"
2671 "} while(true);\n"
2672 "return b;\n",
2673 factory->NewHeapNumber(1024)),
2674 std::make_pair("var a = 10; var b = 1;\n"
2675 "do {\n"
2676 " b = b * 2;\n"
2677 " a = a - 1;\n"
2678 " if (a == 0) break;"
2679 "} while(false);\n"
2680 "return b;\n",
2681 Handle<Object>(Smi::FromInt(2), isolate)),
2682 std::make_pair("var a = 10; var b = 1;\n"
2683 "for ( a = 1, b = 30; false; ) {\n"
2684 " b = b * 2;\n"
2685 "}\n"
2686 "return b;\n",
2687 Handle<Object>(Smi::FromInt(30), isolate))};
2688
2689 for (size_t i = 0; i < arraysize(loops); i++) {
2690 std::string source(InterpreterTester::SourceForBody(loops[i].first));
2691 InterpreterTester tester(handles.main_isolate(), source.c_str());
2692 auto callable = tester.GetCallable<>();
2693
2694 Handle<i::Object> return_value = callable().ToHandleChecked();
2695 CHECK(return_value->SameValue(*loops[i].second));
2696 }
2697}
2698
2699
2700TEST(InterpreterForIn) {
2701 HandleAndZoneScope handles;
2702
2703 std::pair<const char*, int> for_in_samples[] = {
2704 {"function f() {\n"
2705 " var r = -1;\n"
2706 " for (var a in null) { r = a; }\n"
2707 " return r;\n"
2708 "}",
2709 -1},
2710 {"function f() {\n"
2711 " var r = -1;\n"
2712 " for (var a in undefined) { r = a; }\n"
2713 " return r;\n"
2714 "}",
2715 -1},
2716 {"function f() {\n"
2717 " var r = 0;\n"
2718 " for (var a in [0,6,7,9]) { r = r + (1 << a); }\n"
2719 " return r;\n"
2720 "}",
2721 0xf},
2722 {"function f() {\n"
2723 " var r = 0;\n"
2724 " for (var a in [0,6,7,9]) { r = r + (1 << a); }\n"
2725 " var r = 0;\n"
2726 " for (var a in [0,6,7,9]) { r = r + (1 << a); }\n"
2727 " return r;\n"
2728 "}",
2729 0xf},
2730 {"function f() {\n"
2731 " var r = 0;\n"
2732 " for (var a in 'foobar') { r = r + (1 << a); }\n"
2733 " return r;\n"
2734 "}",
2735 0x3f},
2736 {"function f() {\n"
2737 " var r = 0;\n"
2738 " for (var a in {1:0, 10:1, 100:2, 1000:3}) {\n"
2739 " r = r + Number(a);\n"
2740 " }\n"
2741 " return r;\n"
2742 "}",
2743 1111},
2744 {"function f() {\n"
2745 " var r = 0;\n"
2746 " var data = {1:0, 10:1, 100:2, 1000:3};\n"
2747 " for (var a in data) {\n"
2748 " if (a == 1) delete data[1];\n"
2749 " r = r + Number(a);\n"
2750 " }\n"
2751 " return r;\n"
2752 "}",
2753 1111},
2754 {"function f() {\n"
2755 " var r = 0;\n"
2756 " var data = {1:0, 10:1, 100:2, 1000:3};\n"
2757 " for (var a in data) {\n"
2758 " if (a == 10) delete data[100];\n"
2759 " r = r + Number(a);\n"
2760 " }\n"
2761 " return r;\n"
2762 "}",
2763 1011},
2764 {"function f() {\n"
2765 " var r = 0;\n"
2766 " var data = {1:0, 10:1, 100:2, 1000:3};\n"
2767 " for (var a in data) {\n"
2768 " if (a == 10) data[10000] = 4;\n"
2769 " r = r + Number(a);\n"
2770 " }\n"
2771 " return r;\n"
2772 "}",
2773 1111},
2774 {"function f() {\n"
2775 " var r = 0;\n"
2776 " var input = 'foobar';\n"
2777 " for (var a in input) {\n"
2778 " if (input[a] == 'b') break;\n"
2779 " r = r + (1 << a);\n"
2780 " }\n"
2781 " return r;\n"
2782 "}",
2783 0x7},
2784 {"function f() {\n"
2785 "var r = 0;\n"
2786 "var input = 'foobar';\n"
2787 "for (var a in input) {\n"
2788 " if (input[a] == 'b') continue;\n"
2789 " r = r + (1 << a);\n"
2790 "}\n"
2791 "return r;\n"
2792 "}",
2793 0x37},
2794 {"function f() {\n"
2795 " var r = 0;\n"
2796 " var data = {1:0, 10:1, 100:2, 1000:3};\n"
2797 " for (var a in data) {\n"
2798 " if (a == 10) {\n"
2799 " data[10000] = 4;\n"
2800 " }\n"
2801 " r = r + Number(a);\n"
2802 " }\n"
2803 " return r;\n"
2804 "}",
2805 1111},
2806 {"function f() {\n"
2807 " var r = [ 3 ];\n"
2808 " var data = {1:0, 10:1, 100:2, 1000:3};\n"
2809 " for (r[10] in data) {\n"
2810 " }\n"
2811 " return Number(r[10]);\n"
2812 "}",
2813 1000},
2814 {"function f() {\n"
2815 " var r = [ 3 ];\n"
2816 " var data = {1:0, 10:1, 100:2, 1000:3};\n"
2817 " for (r['100'] in data) {\n"
2818 " }\n"
2819 " return Number(r['100']);\n"
2820 "}",
2821 1000},
2822 {"function f() {\n"
2823 " var obj = {}\n"
2824 " var descObj = new Boolean(false);\n"
2825 " var accessed = 0;\n"
2826 " descObj.enumerable = true;\n"
2827 " Object.defineProperties(obj, { prop:descObj });\n"
2828 " for (var p in obj) {\n"
2829 " if (p === 'prop') { accessed = 1; }\n"
2830 " }\n"
2831 " return accessed;"
2832 "}",
2833 1},
2834 {"function f() {\n"
2835 " var appointment = {};\n"
2836 " Object.defineProperty(appointment, 'startTime', {\n"
2837 " value: 1001,\n"
2838 " writable: false,\n"
2839 " enumerable: false,\n"
2840 " configurable: true\n"
2841 " });\n"
2842 " Object.defineProperty(appointment, 'name', {\n"
2843 " value: 'NAME',\n"
2844 " writable: false,\n"
2845 " enumerable: false,\n"
2846 " configurable: true\n"
2847 " });\n"
2848 " var meeting = Object.create(appointment);\n"
2849 " Object.defineProperty(meeting, 'conferenceCall', {\n"
2850 " value: 'In-person meeting',\n"
2851 " writable: false,\n"
2852 " enumerable: false,\n"
2853 " configurable: true\n"
2854 " });\n"
2855 "\n"
2856 " var teamMeeting = Object.create(meeting);\n"
2857 "\n"
2858 " var flags = 0;\n"
2859 " for (var p in teamMeeting) {\n"
2860 " if (p === 'startTime') {\n"
2861 " flags |= 1;\n"
2862 " }\n"
2863 " if (p === 'name') {\n"
2864 " flags |= 2;\n"
2865 " }\n"
2866 " if (p === 'conferenceCall') {\n"
2867 " flags |= 4;\n"
2868 " }\n"
2869 " }\n"
2870 "\n"
2871 " var hasOwnProperty = !teamMeeting.hasOwnProperty('name') &&\n"
2872 " !teamMeeting.hasOwnProperty('startTime') &&\n"
2873 " !teamMeeting.hasOwnProperty('conferenceCall');\n"
2874 " if (!hasOwnProperty) {\n"
2875 " flags |= 8;\n"
2876 " }\n"
2877 " return flags;\n"
2878 " }",
2879 0},
2880 {"function f() {\n"
2881 " var data = {x:23, y:34};\n"
2882 " var result = 0;\n"
2883 " var o = {};\n"
2884 " var arr = [o];\n"
2885 " for (arr[0].p in data)\n" // This is to test if value is loaded
2886 " result += data[arr[0].p];\n" // back from accumulator before storing
2887 " return result;\n" // named properties.
2888 "}",
2889 57},
2890 {"function f() {\n"
2891 " var data = {x:23, y:34};\n"
2892 " var result = 0;\n"
2893 " var o = {};\n"
2894 " var i = 0;\n"
2895 " for (o[i++] in data)\n" // This is to test if value is loaded
2896 " result += data[o[i-1]];\n" // back from accumulator before
2897 " return result;\n" // storing keyed properties.
2898 "}",
2899 57}};
2900
2901 for (size_t i = 0; i < arraysize(for_in_samples); i++) {
2902 InterpreterTester tester(handles.main_isolate(), for_in_samples[i].first);
2903 auto callable = tester.GetCallable<>();
2904 Handle<Object> return_val = callable().ToHandleChecked();
2905 CHECK_EQ(Handle<Smi>::cast(return_val)->value(), for_in_samples[i].second);
2906 }
2907}
2908
2909
2910TEST(InterpreterSwitch) {
2911 HandleAndZoneScope handles;
2912 i::Isolate* isolate = handles.main_isolate();
2913 i::Factory* factory = isolate->factory();
2914
2915 std::pair<const char*, Handle<Object>> switch_ops[] = {
2916 std::make_pair("var a = 1;\n"
2917 "switch(a) {\n"
2918 " case 1: return 2;\n"
2919 " case 2: return 3;\n"
2920 "}\n",
2921 handle(Smi::FromInt(2), isolate)),
2922 std::make_pair("var a = 1;\n"
2923 "switch(a) {\n"
2924 " case 2: a = 2; break;\n"
2925 " case 1: a = 3; break;\n"
2926 "}\n"
2927 "return a;",
2928 handle(Smi::FromInt(3), isolate)),
2929 std::make_pair("var a = 1;\n"
2930 "switch(a) {\n"
2931 " case 1: a = 2; // fall-through\n"
2932 " case 2: a = 3; break;\n"
2933 "}\n"
2934 "return a;",
2935 handle(Smi::FromInt(3), isolate)),
2936 std::make_pair("var a = 100;\n"
2937 "switch(a) {\n"
2938 " case 1: return 100;\n"
2939 " case 2: return 200;\n"
2940 "}\n"
2941 "return undefined;",
2942 factory->undefined_value()),
2943 std::make_pair("var a = 100;\n"
2944 "switch(a) {\n"
2945 " case 1: return 100;\n"
2946 " case 2: return 200;\n"
2947 " default: return 300;\n"
2948 "}\n"
2949 "return undefined;",
2950 handle(Smi::FromInt(300), isolate)),
2951 std::make_pair("var a = 100;\n"
2952 "switch(typeof(a)) {\n"
2953 " case 'string': return 1;\n"
2954 " case 'number': return 2;\n"
2955 " default: return 3;\n"
2956 "}\n",
2957 handle(Smi::FromInt(2), isolate)),
2958 std::make_pair("var a = 100;\n"
2959 "switch(a) {\n"
2960 " case a += 20: return 1;\n"
2961 " case a -= 10: return 2;\n"
2962 " case a -= 10: return 3;\n"
2963 " default: return 3;\n"
2964 "}\n",
2965 handle(Smi::FromInt(3), isolate)),
2966 std::make_pair("var a = 1;\n"
2967 "switch(a) {\n"
2968 " case 1: \n"
2969 " switch(a + 1) {\n"
2970 " case 2 : a += 1; break;\n"
2971 " default : a += 2; break;\n"
2972 " } // fall-through\n"
2973 " case 2: a += 3;\n"
2974 "}\n"
2975 "return a;",
2976 handle(Smi::FromInt(5), isolate)),
2977 };
2978
2979 for (size_t i = 0; i < arraysize(switch_ops); i++) {
2980 std::string source(InterpreterTester::SourceForBody(switch_ops[i].first));
2981 InterpreterTester tester(handles.main_isolate(), source.c_str());
2982 auto callable = tester.GetCallable<>();
2983
2984 Handle<i::Object> return_value = callable().ToHandleChecked();
2985 CHECK(return_value->SameValue(*switch_ops[i].second));
2986 }
2987}
2988
2989
2990TEST(InterpreterSloppyThis) {
2991 HandleAndZoneScope handles;
2992 i::Isolate* isolate = handles.main_isolate();
2993 i::Factory* factory = isolate->factory();
2994
2995 std::pair<const char*, Handle<Object>> sloppy_this[] = {
2996 std::make_pair("var global_val = 100;\n"
2997 "function f() { return this.global_val; }\n",
2998 handle(Smi::FromInt(100), isolate)),
2999 std::make_pair("var global_val = 110;\n"
3000 "function g() { return this.global_val; };"
3001 "function f() { return g(); }\n",
3002 handle(Smi::FromInt(110), isolate)),
3003 std::make_pair("var global_val = 110;\n"
3004 "function g() { return this.global_val };"
3005 "function f() { 'use strict'; return g(); }\n",
3006 handle(Smi::FromInt(110), isolate)),
3007 std::make_pair("function f() { 'use strict'; return this; }\n",
3008 factory->undefined_value()),
3009 std::make_pair("function g() { 'use strict'; return this; };"
3010 "function f() { return g(); }\n",
3011 factory->undefined_value()),
3012 };
3013
3014 for (size_t i = 0; i < arraysize(sloppy_this); i++) {
3015 InterpreterTester tester(handles.main_isolate(), sloppy_this[i].first);
3016 auto callable = tester.GetCallable<>();
3017
3018 Handle<i::Object> return_value = callable().ToHandleChecked();
3019 CHECK(return_value->SameValue(*sloppy_this[i].second));
3020 }
3021}
3022
3023
3024TEST(InterpreterThisFunction) {
3025 HandleAndZoneScope handles;
3026 i::Isolate* isolate = handles.main_isolate();
3027 i::Factory* factory = isolate->factory();
3028
3029 InterpreterTester tester(handles.main_isolate(),
3030 "var f;\n f = function f() { return f.name; }");
3031 auto callable = tester.GetCallable<>();
3032
3033 Handle<i::Object> return_value = callable().ToHandleChecked();
3034 CHECK(return_value->SameValue(*factory->NewStringFromStaticChars("f")));
3035}
3036
3037
3038TEST(InterpreterNewTarget) {
3039 HandleAndZoneScope handles;
3040 i::Isolate* isolate = handles.main_isolate();
3041 i::Factory* factory = isolate->factory();
3042
3043 // TODO(rmcilroy): Add tests that we get the original constructor for
3044 // superclass constructors once we have class support.
3045 InterpreterTester tester(handles.main_isolate(),
3046 "function f() { this.a = new.target; }");
3047 auto callable = tester.GetCallable<>();
3048 callable().ToHandleChecked();
3049
3050 Handle<Object> new_target_name = v8::Utils::OpenHandle(
3051 *CompileRun("(function() { return (new f()).a.name; })();"));
3052 CHECK(new_target_name->SameValue(*factory->NewStringFromStaticChars("f")));
3053}
3054
3055
3056TEST(InterpreterAssignmentInExpressions) {
3057 HandleAndZoneScope handles;
3058
3059 std::pair<const char*, int> samples[] = {
3060 {"function f() {\n"
3061 " var x = 7;\n"
3062 " var y = x + (x = 1) + (x = 2);\n"
3063 " return y;\n"
3064 "}",
3065 10},
3066 {"function f() {\n"
3067 " var x = 7;\n"
3068 " var y = x + (x = 1) + (x = 2);\n"
3069 " return x;\n"
3070 "}",
3071 2},
3072 {"function f() {\n"
3073 " var x = 55;\n"
3074 " x = x + (x = 100) + (x = 101);\n"
3075 " return x;\n"
3076 "}",
3077 256},
3078 {"function f() {\n"
3079 " var x = 7;\n"
3080 " return ++x + x + x++;\n"
3081 "}",
3082 24},
3083 {"function f() {\n"
3084 " var x = 7;\n"
3085 " var y = 1 + ++x + x + x++;\n"
3086 " return x;\n"
3087 "}",
3088 9},
3089 {"function f() {\n"
3090 " var x = 7;\n"
3091 " var y = ++x + x + x++;\n"
3092 " return x;\n"
3093 "}",
3094 9},
3095 {"function f() {\n"
3096 " var x = 7, y = 100, z = 1000;\n"
3097 " return x + (x += 3) + y + (y *= 10) + (z *= 7) + z;\n"
3098 "}",
3099 15117},
3100 {"function f() {\n"
3101 " var inner = function (x) { return x + (x = 2) + (x = 4) + x; };\n"
3102 " return inner(1);\n"
3103 "}",
3104 11},
3105 {"function f() {\n"
3106 " var x = 1, y = 2;\n"
3107 " x = x + (x = 3) + y + (y = 4), y = y + (y = 5) + y + x;\n"
3108 " return x + y;\n"
3109 "}",
3110 10 + 24},
3111 {"function f() {\n"
3112 " var x = 0;\n"
3113 " var y = x | (x = 1) | (x = 2);\n"
3114 " return x;\n"
3115 "}",
3116 2},
3117 {"function f() {\n"
3118 " var x = 0;\n"
3119 " var y = x || (x = 1);\n"
3120 " return x;\n"
3121 "}",
3122 1},
3123 {"function f() {\n"
3124 " var x = 1;\n"
3125 " var y = x && (x = 2) && (x = 3);\n"
3126 " return x;\n"
3127 "}",
3128 3},
3129 {"function f() {\n"
3130 " var x = 1;\n"
3131 " var y = x || (x = 2);\n"
3132 " return x;\n"
3133 "}",
3134 1},
3135 {"function f() {\n"
3136 " var x = 1;\n"
3137 " x = (x << (x = 3)) | (x = 16);\n"
3138 " return x;\n"
3139 "}",
3140 24},
3141 {"function f() {\n"
3142 " var r = 7;\n"
3143 " var s = 11;\n"
3144 " var t = 13;\n"
3145 " var u = r + s + t + (r = 10) + (s = 20) +"
3146 " (t = (r + s)) + r + s + t;\n"
3147 " return r + s + t + u;\n"
3148 "}",
3149 211},
3150 {"function f() {\n"
3151 " var r = 7;\n"
3152 " var s = 11;\n"
3153 " var t = 13;\n"
3154 " return r > (3 * s * (s = 1)) ? (t + (t += 1)) : (r + (r = 4));\n"
3155 "}",
3156 11},
3157 {"function f() {\n"
3158 " var r = 7;\n"
3159 " var s = 11;\n"
3160 " var t = 13;\n"
3161 " return r > (3 * s * (s = 0)) ? (t + (t += 1)) : (r + (r = 4));\n"
3162 "}",
3163 27},
3164 {"function f() {\n"
3165 " var r = 7;\n"
3166 " var s = 11;\n"
3167 " var t = 13;\n"
3168 " return (r + (r = 5)) > s ? r : t;\n"
3169 "}",
3170 5},
3171 {"function f(a) {\n"
3172 " return a + (arguments[0] = 10);\n"
3173 "}",
3174 50},
3175 {"function f(a) {\n"
3176 " return a + (arguments[0] = 10) + a;\n"
3177 "}",
3178 60},
3179 {"function f(a) {\n"
3180 " return a + (arguments[0] = 10) + arguments[0];\n"
3181 "}",
3182 60},
3183 };
3184
3185 const int arg_value = 40;
3186 for (size_t i = 0; i < arraysize(samples); i++) {
3187 InterpreterTester tester(handles.main_isolate(), samples[i].first);
3188 auto callable = tester.GetCallable<Handle<Object>>();
3189 Handle<Object> return_val =
3190 callable(handle(Smi::FromInt(arg_value), handles.main_isolate()))
3191 .ToHandleChecked();
3192 CHECK_EQ(Handle<Smi>::cast(return_val)->value(), samples[i].second);
3193 }
3194}
3195
3196
3197TEST(InterpreterToName) {
3198 HandleAndZoneScope handles;
3199 i::Isolate* isolate = handles.main_isolate();
3200 i::Factory* factory = isolate->factory();
3201
3202 std::pair<const char*, Handle<Object>> to_name_tests[] = {
3203 {"var a = 'val'; var obj = {[a] : 10}; return obj.val;",
3204 factory->NewNumberFromInt(10)},
3205 {"var a = 20; var obj = {[a] : 10}; return obj['20'];",
3206 factory->NewNumberFromInt(10)},
3207 {"var a = 20; var obj = {[a] : 10}; return obj[20];",
3208 factory->NewNumberFromInt(10)},
3209 {"var a = {val:23}; var obj = {[a] : 10}; return obj[a];",
3210 factory->NewNumberFromInt(10)},
3211 {"var a = {val:23}; var obj = {[a] : 10};\n"
3212 "return obj['[object Object]'];",
3213 factory->NewNumberFromInt(10)},
3214 {"var a = {toString : function() { return 'x'}};\n"
3215 "var obj = {[a] : 10};\n"
3216 "return obj.x;",
3217 factory->NewNumberFromInt(10)},
3218 {"var a = {valueOf : function() { return 'x'}};\n"
3219 "var obj = {[a] : 10};\n"
3220 "return obj.x;",
3221 factory->undefined_value()},
3222 {"var a = {[Symbol.toPrimitive] : function() { return 'x'}};\n"
3223 "var obj = {[a] : 10};\n"
3224 "return obj.x;",
3225 factory->NewNumberFromInt(10)},
3226 };
3227
3228 for (size_t i = 0; i < arraysize(to_name_tests); i++) {
3229 std::string source(
3230 InterpreterTester::SourceForBody(to_name_tests[i].first));
3231 InterpreterTester tester(handles.main_isolate(), source.c_str());
3232 auto callable = tester.GetCallable<>();
3233
3234 Handle<i::Object> return_value = callable().ToHandleChecked();
3235 CHECK(return_value->SameValue(*to_name_tests[i].second));
3236 }
3237}
3238
3239
3240TEST(TemporaryRegisterAllocation) {
3241 HandleAndZoneScope handles;
3242 i::Isolate* isolate = handles.main_isolate();
3243 i::Factory* factory = isolate->factory();
3244
3245 std::pair<const char*, Handle<Object>> reg_tests[] = {
3246 {"function add(a, b, c) {"
3247 " return a + b + c;"
3248 "}"
3249 "function f() {"
3250 " var a = 10, b = 10;"
3251 " return add(a, b++, b);"
3252 "}",
3253 factory->NewNumberFromInt(31)},
3254 {"function add(a, b, c, d) {"
3255 " return a + b + c + d;"
3256 "}"
3257 "function f() {"
3258 " var x = 10, y = 20, z = 30;"
3259 " return x + add(x, (y= x++), x, z);"
3260 "}",
3261 factory->NewNumberFromInt(71)},
3262 };
3263
3264 for (size_t i = 0; i < arraysize(reg_tests); i++) {
3265 InterpreterTester tester(handles.main_isolate(), reg_tests[i].first);
3266 auto callable = tester.GetCallable<>();
3267
3268 Handle<i::Object> return_value = callable().ToHandleChecked();
3269 CHECK(return_value->SameValue(*reg_tests[i].second));
3270 }
3271}
3272
3273
3274TEST(InterpreterLookupSlot) {
3275 HandleAndZoneScope handles;
3276 i::Isolate* isolate = handles.main_isolate();
3277 i::Factory* factory = isolate->factory();
3278
3279 // TODO(mythria): Add more tests when we have support for eval/with.
3280 const char* function_prologue = "var f;"
3281 "var x = 1;"
3282 "function f1() {"
3283 " eval(\"function t() {";
3284 const char* function_epilogue = " }; f = t;\");"
3285 "}"
3286 "f1();";
3287
3288
3289 std::pair<const char*, Handle<Object>> lookup_slot[] = {
3290 {"return x;", handle(Smi::FromInt(1), isolate)},
3291 {"return typeof x;", factory->NewStringFromStaticChars("number")},
3292 {"return typeof dummy;", factory->NewStringFromStaticChars("undefined")},
3293 {"x = 10; return x;", handle(Smi::FromInt(10), isolate)},
3294 {"'use strict'; x = 20; return x;", handle(Smi::FromInt(20), isolate)},
3295 };
3296
3297 for (size_t i = 0; i < arraysize(lookup_slot); i++) {
3298 std::string script = std::string(function_prologue) +
3299 std::string(lookup_slot[i].first) +
3300 std::string(function_epilogue);
3301
3302 InterpreterTester tester(handles.main_isolate(), script.c_str(), "t");
3303 auto callable = tester.GetCallable<>();
3304
3305 Handle<i::Object> return_value = callable().ToHandleChecked();
3306 CHECK(return_value->SameValue(*lookup_slot[i].second));
3307 }
3308}
3309
3310
3311TEST(InterpreterCallLookupSlot) {
3312 HandleAndZoneScope handles;
3313 i::Isolate* isolate = handles.main_isolate();
3314
3315 std::pair<const char*, Handle<Object>> call_lookup[] = {
3316 {"g = function(){ return 2 }; eval(''); return g();",
3317 handle(Smi::FromInt(2), isolate)},
3318 {"g = function(){ return 2 }; eval('g = function() {return 3}');\n"
3319 "return g();",
3320 handle(Smi::FromInt(3), isolate)},
3321 {"g = { x: function(){ return this.y }, y: 20 };\n"
3322 "eval('g = { x: g.x, y: 30 }');\n"
3323 "return g.x();",
3324 handle(Smi::FromInt(30), isolate)},
3325 };
3326
3327 for (size_t i = 0; i < arraysize(call_lookup); i++) {
3328 std::string source(InterpreterTester::SourceForBody(call_lookup[i].first));
3329 InterpreterTester tester(handles.main_isolate(), source.c_str());
3330 auto callable = tester.GetCallable<>();
3331
3332 Handle<i::Object> return_value = callable().ToHandleChecked();
3333 CHECK(return_value->SameValue(*call_lookup[i].second));
3334 }
3335}
3336
3337
3338TEST(InterpreterLookupSlotWide) {
3339 HandleAndZoneScope handles;
3340 i::Isolate* isolate = handles.main_isolate();
3341 i::Factory* factory = isolate->factory();
3342
3343 const char* function_prologue =
3344 "var f;"
3345 "var x = 1;"
3346 "function f1() {"
3347 " eval(\"function t() {";
3348 const char* function_epilogue =
3349 " }; f = t;\");"
3350 "}"
3351 "f1();";
3352 std::ostringstream str;
3353 str << "var y = 2.3;";
3354 for (int i = 1; i < 256; i++) {
3355 str << "y = " << 2.3 + i << ";";
3356 }
3357 std::string init_function_body = str.str();
3358
3359 std::pair<std::string, Handle<Object>> lookup_slot[] = {
3360 {init_function_body + "return x;", handle(Smi::FromInt(1), isolate)},
3361 {init_function_body + "return typeof x;",
3362 factory->NewStringFromStaticChars("number")},
3363 {init_function_body + "return x = 10;",
3364 handle(Smi::FromInt(10), isolate)},
3365 {"'use strict';" + init_function_body + "x = 20; return x;",
3366 handle(Smi::FromInt(20), isolate)},
3367 };
3368
3369 for (size_t i = 0; i < arraysize(lookup_slot); i++) {
3370 std::string script = std::string(function_prologue) + lookup_slot[i].first +
3371 std::string(function_epilogue);
3372
3373 InterpreterTester tester(handles.main_isolate(), script.c_str(), "t");
3374 auto callable = tester.GetCallable<>();
3375
3376 Handle<i::Object> return_value = callable().ToHandleChecked();
3377 CHECK(return_value->SameValue(*lookup_slot[i].second));
3378 }
3379}
3380
3381
3382TEST(InterpreterDeleteLookupSlot) {
3383 HandleAndZoneScope handles;
3384 i::Isolate* isolate = handles.main_isolate();
3385 i::Factory* factory = isolate->factory();
3386
3387 // TODO(mythria): Add more tests when we have support for eval/with.
3388 const char* function_prologue = "var f;"
3389 "var x = 1;"
3390 "y = 10;"
3391 "var obj = {val:10};"
3392 "var z = 30;"
3393 "function f1() {"
3394 " var z = 20;"
3395 " eval(\"function t() {";
3396 const char* function_epilogue = " }; f = t;\");"
3397 "}"
3398 "f1();";
3399
3400
3401 std::pair<const char*, Handle<Object>> delete_lookup_slot[] = {
3402 {"return delete x;", factory->false_value()},
3403 {"return delete y;", factory->true_value()},
3404 {"return delete z;", factory->false_value()},
3405 {"return delete obj.val;", factory->true_value()},
3406 {"'use strict'; return delete obj.val;", factory->true_value()},
3407 };
3408
3409 for (size_t i = 0; i < arraysize(delete_lookup_slot); i++) {
3410 std::string script = std::string(function_prologue) +
3411 std::string(delete_lookup_slot[i].first) +
3412 std::string(function_epilogue);
3413
3414 InterpreterTester tester(handles.main_isolate(), script.c_str(), "t");
3415 auto callable = tester.GetCallable<>();
3416
3417 Handle<i::Object> return_value = callable().ToHandleChecked();
3418 CHECK(return_value->SameValue(*delete_lookup_slot[i].second));
3419 }
3420}
3421
3422
3423TEST(JumpWithConstantsAndWideConstants) {
3424 HandleAndZoneScope handles;
3425 auto isolate = handles.main_isolate();
3426 auto factory = isolate->factory();
3427 const int kStep = 13;
3428 for (int constants = 3; constants < 256 + 3 * kStep; constants += kStep) {
3429 std::ostringstream filler_os;
3430 // Generate a string that consumes constant pool entries and
3431 // spread out branch distances in script below.
3432 for (int i = 0; i < constants; i++) {
3433 filler_os << "var x_ = 'x_" << i << "';\n";
3434 }
3435 std::string filler(filler_os.str());
3436 std::ostringstream script_os;
3437 script_os << "function " << InterpreterTester::function_name() << "(a) {\n";
3438 script_os << " " << filler;
3439 script_os << " for (var i = a; i < 2; i++) {\n";
3440 script_os << " " << filler;
3441 script_os << " if (i == 0) { " << filler << "i = 10; continue; }\n";
3442 script_os << " else if (i == a) { " << filler << "i = 12; break; }\n";
3443 script_os << " else { " << filler << " }\n";
3444 script_os << " }\n";
3445 script_os << " return i;\n";
3446 script_os << "}\n";
3447 std::string script(script_os.str());
3448 for (int a = 0; a < 3; a++) {
3449 InterpreterTester tester(handles.main_isolate(), script.c_str());
3450 auto callable = tester.GetCallable<Handle<Object>>();
3451 Handle<Object> return_val =
3452 callable(factory->NewNumberFromInt(a)).ToHandleChecked();
3453 static const int results[] = {11, 12, 2};
3454 CHECK_EQ(Handle<Smi>::cast(return_val)->value(), results[a]);
3455 }
3456 }
3457}
3458
3459
3460TEST(InterpreterEval) {
3461 HandleAndZoneScope handles;
3462 i::Isolate* isolate = handles.main_isolate();
3463 i::Factory* factory = isolate->factory();
3464
3465 std::pair<const char*, Handle<Object>> eval[] = {
3466 {"return eval('1;');", handle(Smi::FromInt(1), isolate)},
3467 {"return eval('100 * 20;');", handle(Smi::FromInt(2000), isolate)},
3468 {"var x = 10; return eval('x + 20;');",
3469 handle(Smi::FromInt(30), isolate)},
3470 {"var x = 10; eval('x = 33;'); return x;",
3471 handle(Smi::FromInt(33), isolate)},
3472 {"'use strict'; var x = 20; var z = 0;\n"
3473 "eval('var x = 33; z = x;'); return x + z;",
3474 handle(Smi::FromInt(53), isolate)},
3475 {"eval('var x = 33;'); eval('var y = x + 20'); return x + y;",
3476 handle(Smi::FromInt(86), isolate)},
3477 {"var x = 1; eval('for(i = 0; i < 10; i++) x = x + 1;'); return x",
3478 handle(Smi::FromInt(11), isolate)},
3479 {"var x = 10; eval('var x = 20;'); return x;",
3480 handle(Smi::FromInt(20), isolate)},
3481 {"var x = 1; eval('\"use strict\"; var x = 2;'); return x;",
3482 handle(Smi::FromInt(1), isolate)},
3483 {"'use strict'; var x = 1; eval('var x = 2;'); return x;",
3484 handle(Smi::FromInt(1), isolate)},
3485 {"var x = 10; eval('x + 20;'); return typeof x;",
3486 factory->NewStringFromStaticChars("number")},
3487 {"eval('var y = 10;'); return typeof unallocated;",
3488 factory->NewStringFromStaticChars("undefined")},
3489 {"'use strict'; eval('var y = 10;'); return typeof unallocated;",
3490 factory->NewStringFromStaticChars("undefined")},
3491 {"eval('var x = 10;'); return typeof x;",
3492 factory->NewStringFromStaticChars("number")},
3493 {"var x = {}; eval('var x = 10;'); return typeof x;",
3494 factory->NewStringFromStaticChars("number")},
3495 {"'use strict'; var x = {}; eval('var x = 10;'); return typeof x;",
3496 factory->NewStringFromStaticChars("object")},
3497 };
3498
3499 for (size_t i = 0; i < arraysize(eval); i++) {
3500 std::string source(InterpreterTester::SourceForBody(eval[i].first));
3501 InterpreterTester tester(handles.main_isolate(), source.c_str());
3502 auto callable = tester.GetCallable<>();
3503
3504 Handle<i::Object> return_value = callable().ToHandleChecked();
3505 CHECK(return_value->SameValue(*eval[i].second));
3506 }
3507}
3508
3509
3510TEST(InterpreterEvalParams) {
3511 HandleAndZoneScope handles;
3512 i::Isolate* isolate = handles.main_isolate();
3513
3514 std::pair<const char*, Handle<Object>> eval_params[] = {
3515 {"var x = 10; return eval('x + p1;');",
3516 handle(Smi::FromInt(30), isolate)},
3517 {"var x = 10; eval('p1 = x;'); return p1;",
3518 handle(Smi::FromInt(10), isolate)},
3519 {"var a = 10;"
3520 "function inner() { return eval('a + p1;');}"
3521 "return inner();",
3522 handle(Smi::FromInt(30), isolate)},
3523 };
3524
3525 for (size_t i = 0; i < arraysize(eval_params); i++) {
3526 std::string source = "function " + InterpreterTester::function_name() +
3527 "(p1) {" + eval_params[i].first + "}";
3528 InterpreterTester tester(handles.main_isolate(), source.c_str());
3529 auto callable = tester.GetCallable<Handle<Object>>();
3530
3531 Handle<i::Object> return_value =
3532 callable(handle(Smi::FromInt(20), isolate)).ToHandleChecked();
3533 CHECK(return_value->SameValue(*eval_params[i].second));
3534 }
3535}
3536
3537
3538TEST(InterpreterEvalGlobal) {
3539 HandleAndZoneScope handles;
3540 i::Isolate* isolate = handles.main_isolate();
3541 i::Factory* factory = isolate->factory();
3542
3543 std::pair<const char*, Handle<Object>> eval_global[] = {
3544 {"function add_global() { eval('function test() { z = 33; }; test()'); };"
3545 "function f() { add_global(); return z; }; f();",
3546 handle(Smi::FromInt(33), isolate)},
3547 {"function add_global() {\n"
3548 " eval('\"use strict\"; function test() { y = 33; };"
3549 " try { test() } catch(e) {}');\n"
3550 "}\n"
3551 "function f() { add_global(); return typeof y; } f();",
3552 factory->NewStringFromStaticChars("undefined")},
3553 };
3554
3555 for (size_t i = 0; i < arraysize(eval_global); i++) {
3556 InterpreterTester tester(handles.main_isolate(), eval_global[i].first,
3557 "test");
3558 auto callable = tester.GetCallable<>();
3559
3560 Handle<i::Object> return_value = callable().ToHandleChecked();
3561 CHECK(return_value->SameValue(*eval_global[i].second));
3562 }
3563}
3564
3565} // namespace interpreter
3566} // namespace internal
3567} // namespace v8