blob: 69cf0e18bd48dfa507f248e563083519be77c5d0 [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;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000068 i::FLAG_always_opt = false;
69 // Set ignition filter flag via SetFlagsFromString to avoid double-free
70 // (or potential leak with StrDup() based on ownership confusion).
71 ScopedVector<char> ignition_filter(64);
72 SNPrintF(ignition_filter, "--ignition-filter=%s", filter);
73 FlagList::SetFlagsFromString(ignition_filter.start(),
74 ignition_filter.length());
75 // Ensure handler table is generated.
76 isolate->interpreter()->Initialize();
77 }
78
79 InterpreterTester(Isolate* isolate, Handle<BytecodeArray> bytecode,
80 MaybeHandle<TypeFeedbackVector> feedback_vector =
81 MaybeHandle<TypeFeedbackVector>(),
82 const char* filter = kFunctionName)
83 : InterpreterTester(isolate, nullptr, bytecode, feedback_vector, filter) {
84 }
85
86
87 InterpreterTester(Isolate* isolate, const char* source,
88 const char* filter = kFunctionName)
89 : InterpreterTester(isolate, source, MaybeHandle<BytecodeArray>(),
90 MaybeHandle<TypeFeedbackVector>(), filter) {}
91
92 virtual ~InterpreterTester() {}
93
94 template <class... A>
95 InterpreterCallable<A...> GetCallable() {
96 return InterpreterCallable<A...>(isolate_, GetBytecodeFunction<A...>());
97 }
98
Ben Murdoch097c5b22016-05-18 11:27:45 +010099 Local<Message> CheckThrowsReturnMessage() {
100 TryCatch try_catch(reinterpret_cast<v8::Isolate*>(isolate_));
101 auto callable = GetCallable<>();
102 MaybeHandle<Object> no_result = callable();
103 CHECK(isolate_->has_pending_exception());
104 CHECK(try_catch.HasCaught());
105 CHECK(no_result.is_null());
106 isolate_->OptionalRescheduleException(true);
107 CHECK(!try_catch.Message().IsEmpty());
108 return try_catch.Message();
109 }
110
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000111 static Handle<Object> NewObject(const char* script) {
112 return v8::Utils::OpenHandle(*CompileRun(script));
113 }
114
115 static Handle<String> GetName(Isolate* isolate, const char* name) {
116 Handle<String> result = isolate->factory()->NewStringFromAsciiChecked(name);
117 return isolate->factory()->string_table()->LookupString(isolate, result);
118 }
119
120 static std::string SourceForBody(const char* body) {
121 return "function " + function_name() + "() {\n" + std::string(body) + "\n}";
122 }
123
124 static std::string function_name() {
125 return std::string(kFunctionName);
126 }
127
128 private:
129 Isolate* isolate_;
130 const char* source_;
131 MaybeHandle<BytecodeArray> bytecode_;
132 MaybeHandle<TypeFeedbackVector> feedback_vector_;
133
134 template <class... A>
135 Handle<JSFunction> GetBytecodeFunction() {
136 Handle<JSFunction> function;
137 if (source_) {
138 CompileRun(source_);
139 v8::Local<v8::Context> context =
140 v8::Isolate::GetCurrent()->GetCurrentContext();
141 Local<Function> api_function =
142 Local<Function>::Cast(CcTest::global()
143 ->Get(context, v8_str(kFunctionName))
144 .ToLocalChecked());
145 function = Handle<JSFunction>::cast(v8::Utils::OpenHandle(*api_function));
146 } else {
147 int arg_count = sizeof...(A);
148 std::string source("(function " + function_name() + "(");
149 for (int i = 0; i < arg_count; i++) {
150 source += i == 0 ? "a" : ", a";
151 }
152 source += "){})";
153 function = Handle<JSFunction>::cast(v8::Utils::OpenHandle(
154 *v8::Local<v8::Function>::Cast(CompileRun(source.c_str()))));
155 function->ReplaceCode(
156 *isolate_->builtins()->InterpreterEntryTrampoline());
157 }
158
159 if (!bytecode_.is_null()) {
160 function->shared()->set_function_data(*bytecode_.ToHandleChecked());
161 }
162 if (!feedback_vector_.is_null()) {
163 function->shared()->set_feedback_vector(
164 *feedback_vector_.ToHandleChecked());
165 }
166 return function;
167 }
168
169 DISALLOW_COPY_AND_ASSIGN(InterpreterTester);
170};
171
172
173TEST(InterpreterReturn) {
174 HandleAndZoneScope handles;
175 Handle<Object> undefined_value =
176 handles.main_isolate()->factory()->undefined_value();
177
Ben Murdoch097c5b22016-05-18 11:27:45 +0100178 BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone(), 1,
179 0, 0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000180 builder.Return();
181 Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
182
183 InterpreterTester tester(handles.main_isolate(), bytecode_array);
184 auto callable = tester.GetCallable<>();
185 Handle<Object> return_val = callable().ToHandleChecked();
186 CHECK(return_val.is_identical_to(undefined_value));
187}
188
189
190TEST(InterpreterLoadUndefined) {
191 HandleAndZoneScope handles;
192 Handle<Object> undefined_value =
193 handles.main_isolate()->factory()->undefined_value();
194
Ben Murdoch097c5b22016-05-18 11:27:45 +0100195 BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone(), 1,
196 0, 0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000197 builder.LoadUndefined().Return();
198 Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
199
200 InterpreterTester tester(handles.main_isolate(), bytecode_array);
201 auto callable = tester.GetCallable<>();
202 Handle<Object> return_val = callable().ToHandleChecked();
203 CHECK(return_val.is_identical_to(undefined_value));
204}
205
206
207TEST(InterpreterLoadNull) {
208 HandleAndZoneScope handles;
209 Handle<Object> null_value = handles.main_isolate()->factory()->null_value();
210
Ben Murdoch097c5b22016-05-18 11:27:45 +0100211 BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone(), 1,
212 0, 0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000213 builder.LoadNull().Return();
214 Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
215
216 InterpreterTester tester(handles.main_isolate(), bytecode_array);
217 auto callable = tester.GetCallable<>();
218 Handle<Object> return_val = callable().ToHandleChecked();
219 CHECK(return_val.is_identical_to(null_value));
220}
221
222
223TEST(InterpreterLoadTheHole) {
224 HandleAndZoneScope handles;
225 Handle<Object> the_hole_value =
226 handles.main_isolate()->factory()->the_hole_value();
227
Ben Murdoch097c5b22016-05-18 11:27:45 +0100228 BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone(), 1,
229 0, 0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000230 builder.LoadTheHole().Return();
231 Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
232
233 InterpreterTester tester(handles.main_isolate(), bytecode_array);
234 auto callable = tester.GetCallable<>();
235 Handle<Object> return_val = callable().ToHandleChecked();
236 CHECK(return_val.is_identical_to(the_hole_value));
237}
238
239
240TEST(InterpreterLoadTrue) {
241 HandleAndZoneScope handles;
242 Handle<Object> true_value = handles.main_isolate()->factory()->true_value();
243
Ben Murdoch097c5b22016-05-18 11:27:45 +0100244 BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone(), 1,
245 0, 0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000246 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
Ben Murdoch097c5b22016-05-18 11:27:45 +0100260 BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone(), 1,
261 0, 0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000262 builder.LoadFalse().Return();
263 Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
264
265 InterpreterTester tester(handles.main_isolate(), bytecode_array);
266 auto callable = tester.GetCallable<>();
267 Handle<Object> return_val = callable().ToHandleChecked();
268 CHECK(return_val.is_identical_to(false_value));
269}
270
271
272TEST(InterpreterLoadLiteral) {
273 HandleAndZoneScope handles;
274 i::Factory* factory = handles.main_isolate()->factory();
275
276 // Small Smis.
277 for (int i = -128; i < 128; i++) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100278 BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone(), 1,
279 0, 0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000280 builder.LoadLiteral(Smi::FromInt(i)).Return();
281 Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
282
283 InterpreterTester tester(handles.main_isolate(), bytecode_array);
284 auto callable = tester.GetCallable<>();
285 Handle<Object> return_val = callable().ToHandleChecked();
286 CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(i));
287 }
288
289 // Large Smis.
290 {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100291 BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone(), 1,
292 0, 0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000293 builder.LoadLiteral(Smi::FromInt(0x12345678)).Return();
294 Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
295
296 InterpreterTester tester(handles.main_isolate(), bytecode_array);
297 auto callable = tester.GetCallable<>();
298 Handle<Object> return_val = callable().ToHandleChecked();
299 CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(0x12345678));
300 }
301
302 // Heap numbers.
303 {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100304 BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone(), 1,
305 0, 0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000306 builder.LoadLiteral(factory->NewHeapNumber(-2.1e19)).Return();
307 Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
308
309 InterpreterTester tester(handles.main_isolate(), bytecode_array);
310 auto callable = tester.GetCallable<>();
311 Handle<Object> return_val = callable().ToHandleChecked();
312 CHECK_EQ(i::HeapNumber::cast(*return_val)->value(), -2.1e19);
313 }
314
315 // Strings.
316 {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100317 BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone(), 1,
318 0, 0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000319 Handle<i::String> string = factory->NewStringFromAsciiChecked("String");
320 builder.LoadLiteral(string).Return();
321 Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
322
323 InterpreterTester tester(handles.main_isolate(), bytecode_array);
324 auto callable = tester.GetCallable<>();
325 Handle<Object> return_val = callable().ToHandleChecked();
326 CHECK(i::String::cast(*return_val)->Equals(*string));
327 }
328}
329
330
331TEST(InterpreterLoadStoreRegisters) {
332 HandleAndZoneScope handles;
333 Handle<Object> true_value = handles.main_isolate()->factory()->true_value();
334 for (int i = 0; i <= kMaxInt8; i++) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100335 BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone(), 1,
336 0, i + 1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000337 Register reg(i);
338 builder.LoadTrue()
339 .StoreAccumulatorInRegister(reg)
340 .LoadFalse()
341 .LoadAccumulatorWithRegister(reg)
342 .Return();
343 Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
344
345 InterpreterTester tester(handles.main_isolate(), bytecode_array);
346 auto callable = tester.GetCallable<>();
347 Handle<Object> return_val = callable().ToHandleChecked();
348 CHECK(return_val.is_identical_to(true_value));
349 }
350}
351
352
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000353static const Token::Value kShiftOperators[] = {
354 Token::Value::SHL, Token::Value::SAR, Token::Value::SHR};
355
356
357static const Token::Value kArithmeticOperators[] = {
358 Token::Value::BIT_OR, Token::Value::BIT_XOR, Token::Value::BIT_AND,
359 Token::Value::SHL, Token::Value::SAR, Token::Value::SHR,
360 Token::Value::ADD, Token::Value::SUB, Token::Value::MUL,
361 Token::Value::DIV, Token::Value::MOD};
362
363
364static double BinaryOpC(Token::Value op, double lhs, double rhs) {
365 switch (op) {
366 case Token::Value::ADD:
367 return lhs + rhs;
368 case Token::Value::SUB:
369 return lhs - rhs;
370 case Token::Value::MUL:
371 return lhs * rhs;
372 case Token::Value::DIV:
373 return lhs / rhs;
374 case Token::Value::MOD:
375 return std::fmod(lhs, rhs);
376 case Token::Value::BIT_OR:
377 return (v8::internal::DoubleToInt32(lhs) |
378 v8::internal::DoubleToInt32(rhs));
379 case Token::Value::BIT_XOR:
380 return (v8::internal::DoubleToInt32(lhs) ^
381 v8::internal::DoubleToInt32(rhs));
382 case Token::Value::BIT_AND:
383 return (v8::internal::DoubleToInt32(lhs) &
384 v8::internal::DoubleToInt32(rhs));
385 case Token::Value::SHL: {
386 int32_t val = v8::internal::DoubleToInt32(lhs);
387 uint32_t count = v8::internal::DoubleToUint32(rhs) & 0x1F;
388 int32_t result = val << count;
389 return result;
390 }
391 case Token::Value::SAR: {
392 int32_t val = v8::internal::DoubleToInt32(lhs);
393 uint32_t count = v8::internal::DoubleToUint32(rhs) & 0x1F;
394 int32_t result = val >> count;
395 return result;
396 }
397 case Token::Value::SHR: {
398 uint32_t val = v8::internal::DoubleToUint32(lhs);
399 uint32_t count = v8::internal::DoubleToUint32(rhs) & 0x1F;
400 uint32_t result = val >> count;
401 return result;
402 }
403 default:
404 UNREACHABLE();
405 return std::numeric_limits<double>::min();
406 }
407}
408
409
410TEST(InterpreterShiftOpsSmi) {
411 int lhs_inputs[] = {0, -17, -182, 1073741823, -1};
412 int rhs_inputs[] = {5, 2, 1, -1, -2, 0, 31, 32, -32, 64, 37};
413 for (size_t l = 0; l < arraysize(lhs_inputs); l++) {
414 for (size_t r = 0; r < arraysize(rhs_inputs); r++) {
415 for (size_t o = 0; o < arraysize(kShiftOperators); o++) {
416 HandleAndZoneScope handles;
417 i::Factory* factory = handles.main_isolate()->factory();
418 BytecodeArrayBuilder builder(handles.main_isolate(),
Ben Murdoch097c5b22016-05-18 11:27:45 +0100419 handles.main_zone(), 1, 0, 1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000420 Register reg(0);
421 int lhs = lhs_inputs[l];
422 int rhs = rhs_inputs[r];
423 builder.LoadLiteral(Smi::FromInt(lhs))
424 .StoreAccumulatorInRegister(reg)
425 .LoadLiteral(Smi::FromInt(rhs))
Ben Murdoch097c5b22016-05-18 11:27:45 +0100426 .BinaryOperation(kShiftOperators[o], reg)
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000427 .Return();
428 Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
429
430 InterpreterTester tester(handles.main_isolate(), bytecode_array);
431 auto callable = tester.GetCallable<>();
432 Handle<Object> return_value = callable().ToHandleChecked();
433 Handle<Object> expected_value =
434 factory->NewNumber(BinaryOpC(kShiftOperators[o], lhs, rhs));
435 CHECK(return_value->SameValue(*expected_value));
436 }
437 }
438 }
439}
440
441
442TEST(InterpreterBinaryOpsSmi) {
443 int lhs_inputs[] = {3266, 1024, 0, -17, -18000};
444 int rhs_inputs[] = {3266, 5, 4, 3, 2, 1, -1, -2};
445 for (size_t l = 0; l < arraysize(lhs_inputs); l++) {
446 for (size_t r = 0; r < arraysize(rhs_inputs); r++) {
447 for (size_t o = 0; o < arraysize(kArithmeticOperators); o++) {
448 HandleAndZoneScope handles;
449 i::Factory* factory = handles.main_isolate()->factory();
450 BytecodeArrayBuilder builder(handles.main_isolate(),
Ben Murdoch097c5b22016-05-18 11:27:45 +0100451 handles.main_zone(), 1, 0, 1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000452 Register reg(0);
453 int lhs = lhs_inputs[l];
454 int rhs = rhs_inputs[r];
455 builder.LoadLiteral(Smi::FromInt(lhs))
456 .StoreAccumulatorInRegister(reg)
457 .LoadLiteral(Smi::FromInt(rhs))
Ben Murdoch097c5b22016-05-18 11:27:45 +0100458 .BinaryOperation(kArithmeticOperators[o], reg)
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000459 .Return();
460 Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
461
462 InterpreterTester tester(handles.main_isolate(), bytecode_array);
463 auto callable = tester.GetCallable<>();
464 Handle<Object> return_value = callable().ToHandleChecked();
465 Handle<Object> expected_value =
466 factory->NewNumber(BinaryOpC(kArithmeticOperators[o], lhs, rhs));
467 CHECK(return_value->SameValue(*expected_value));
468 }
469 }
470 }
471}
472
473
474TEST(InterpreterBinaryOpsHeapNumber) {
475 double lhs_inputs[] = {3266.101, 1024.12, 0.01, -17.99, -18000.833, 9.1e17};
476 double rhs_inputs[] = {3266.101, 5.999, 4.778, 3.331, 2.643,
477 1.1, -1.8, -2.9, 8.3e-27};
478 for (size_t l = 0; l < arraysize(lhs_inputs); l++) {
479 for (size_t r = 0; r < arraysize(rhs_inputs); r++) {
480 for (size_t o = 0; o < arraysize(kArithmeticOperators); o++) {
481 HandleAndZoneScope handles;
482 i::Factory* factory = handles.main_isolate()->factory();
483 BytecodeArrayBuilder builder(handles.main_isolate(),
Ben Murdoch097c5b22016-05-18 11:27:45 +0100484 handles.main_zone(), 1, 0, 1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000485 Register reg(0);
486 double lhs = lhs_inputs[l];
487 double rhs = rhs_inputs[r];
488 builder.LoadLiteral(factory->NewNumber(lhs))
489 .StoreAccumulatorInRegister(reg)
490 .LoadLiteral(factory->NewNumber(rhs))
Ben Murdoch097c5b22016-05-18 11:27:45 +0100491 .BinaryOperation(kArithmeticOperators[o], reg)
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000492 .Return();
493 Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
494
495 InterpreterTester tester(handles.main_isolate(), bytecode_array);
496 auto callable = tester.GetCallable<>();
497 Handle<Object> return_value = callable().ToHandleChecked();
498 Handle<Object> expected_value =
499 factory->NewNumber(BinaryOpC(kArithmeticOperators[o], lhs, rhs));
500 CHECK(return_value->SameValue(*expected_value));
501 }
502 }
503 }
504}
505
506
507TEST(InterpreterStringAdd) {
508 HandleAndZoneScope handles;
509 i::Factory* factory = handles.main_isolate()->factory();
510
511 struct TestCase {
512 Handle<Object> lhs;
513 Handle<Object> rhs;
514 Handle<Object> expected_value;
515 } test_cases[] = {
516 {factory->NewStringFromStaticChars("a"),
517 factory->NewStringFromStaticChars("b"),
518 factory->NewStringFromStaticChars("ab")},
519 {factory->NewStringFromStaticChars("aaaaaa"),
520 factory->NewStringFromStaticChars("b"),
521 factory->NewStringFromStaticChars("aaaaaab")},
522 {factory->NewStringFromStaticChars("aaa"),
523 factory->NewStringFromStaticChars("bbbbb"),
524 factory->NewStringFromStaticChars("aaabbbbb")},
525 {factory->NewStringFromStaticChars(""),
526 factory->NewStringFromStaticChars("b"),
527 factory->NewStringFromStaticChars("b")},
528 {factory->NewStringFromStaticChars("a"),
529 factory->NewStringFromStaticChars(""),
530 factory->NewStringFromStaticChars("a")},
531 {factory->NewStringFromStaticChars("1.11"), factory->NewHeapNumber(2.5),
532 factory->NewStringFromStaticChars("1.112.5")},
533 {factory->NewStringFromStaticChars("-1.11"), factory->NewHeapNumber(2.56),
534 factory->NewStringFromStaticChars("-1.112.56")},
535 {factory->NewStringFromStaticChars(""), factory->NewHeapNumber(2.5),
536 factory->NewStringFromStaticChars("2.5")},
537 };
538
539 for (size_t i = 0; i < arraysize(test_cases); i++) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100540 BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone(), 1,
541 0, 1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000542 Register reg(0);
543 builder.LoadLiteral(test_cases[i].lhs)
544 .StoreAccumulatorInRegister(reg)
545 .LoadLiteral(test_cases[i].rhs)
Ben Murdoch097c5b22016-05-18 11:27:45 +0100546 .BinaryOperation(Token::Value::ADD, reg)
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000547 .Return();
548 Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
549
550 InterpreterTester tester(handles.main_isolate(), bytecode_array);
551 auto callable = tester.GetCallable<>();
552 Handle<Object> return_value = callable().ToHandleChecked();
553 CHECK(return_value->SameValue(*test_cases[i].expected_value));
554 }
555}
556
557
558TEST(InterpreterParameter1) {
559 HandleAndZoneScope handles;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100560 BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone(), 1,
561 0, 0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000562 builder.LoadAccumulatorWithRegister(builder.Parameter(0)).Return();
563 Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
564
565 InterpreterTester tester(handles.main_isolate(), bytecode_array);
566 auto callable = tester.GetCallable<Handle<Object>>();
567
568 // Check for heap objects.
569 Handle<Object> true_value = handles.main_isolate()->factory()->true_value();
570 Handle<Object> return_val = callable(true_value).ToHandleChecked();
571 CHECK(return_val.is_identical_to(true_value));
572
573 // Check for Smis.
574 return_val = callable(Handle<Smi>(Smi::FromInt(3), handles.main_isolate()))
575 .ToHandleChecked();
576 CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(3));
577}
578
579
580TEST(InterpreterParameter8) {
581 HandleAndZoneScope handles;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100582 BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone(), 8,
583 0, 0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000584 builder.LoadAccumulatorWithRegister(builder.Parameter(0))
Ben Murdoch097c5b22016-05-18 11:27:45 +0100585 .BinaryOperation(Token::Value::ADD, builder.Parameter(1))
586 .BinaryOperation(Token::Value::ADD, builder.Parameter(2))
587 .BinaryOperation(Token::Value::ADD, builder.Parameter(3))
588 .BinaryOperation(Token::Value::ADD, builder.Parameter(4))
589 .BinaryOperation(Token::Value::ADD, builder.Parameter(5))
590 .BinaryOperation(Token::Value::ADD, builder.Parameter(6))
591 .BinaryOperation(Token::Value::ADD, builder.Parameter(7))
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000592 .Return();
593 Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
594
595 InterpreterTester tester(handles.main_isolate(), bytecode_array);
596 typedef Handle<Object> H;
597 auto callable = tester.GetCallable<H, H, H, H, H, H, H, H>();
598
599 Handle<Smi> arg1 = Handle<Smi>(Smi::FromInt(1), handles.main_isolate());
600 Handle<Smi> arg2 = Handle<Smi>(Smi::FromInt(2), handles.main_isolate());
601 Handle<Smi> arg3 = Handle<Smi>(Smi::FromInt(3), handles.main_isolate());
602 Handle<Smi> arg4 = Handle<Smi>(Smi::FromInt(4), handles.main_isolate());
603 Handle<Smi> arg5 = Handle<Smi>(Smi::FromInt(5), handles.main_isolate());
604 Handle<Smi> arg6 = Handle<Smi>(Smi::FromInt(6), handles.main_isolate());
605 Handle<Smi> arg7 = Handle<Smi>(Smi::FromInt(7), handles.main_isolate());
606 Handle<Smi> arg8 = Handle<Smi>(Smi::FromInt(8), handles.main_isolate());
607 // Check for Smis.
608 Handle<Object> return_val =
609 callable(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8)
610 .ToHandleChecked();
611 CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(36));
612}
613
614
615TEST(InterpreterParameter1Assign) {
616 HandleAndZoneScope handles;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100617 BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone(), 1,
618 0, 0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000619 builder.LoadLiteral(Smi::FromInt(5))
620 .StoreAccumulatorInRegister(builder.Parameter(0))
621 .LoadAccumulatorWithRegister(builder.Parameter(0))
622 .Return();
623 Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
624
625 InterpreterTester tester(handles.main_isolate(), bytecode_array);
626 auto callable = tester.GetCallable<Handle<Object>>();
627
628 Handle<Object> return_val =
629 callable(Handle<Smi>(Smi::FromInt(3), handles.main_isolate()))
630 .ToHandleChecked();
631 CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(5));
632}
633
634
635TEST(InterpreterLoadGlobal) {
636 HandleAndZoneScope handles;
637
638 // Test loading a global.
639 std::string source(
640 "var global = 321;\n"
641 "function " + InterpreterTester::function_name() + "() {\n"
642 " return global;\n"
643 "}");
644 InterpreterTester tester(handles.main_isolate(), source.c_str());
645 auto callable = tester.GetCallable<>();
646
647 Handle<Object> return_val = callable().ToHandleChecked();
648 CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(321));
649}
650
651
652TEST(InterpreterStoreGlobal) {
653 HandleAndZoneScope handles;
654 i::Isolate* isolate = handles.main_isolate();
655 i::Factory* factory = isolate->factory();
656
657 // Test storing to a global.
658 std::string source(
659 "var global = 321;\n"
660 "function " + InterpreterTester::function_name() + "() {\n"
661 " global = 999;\n"
662 "}");
663 InterpreterTester tester(handles.main_isolate(), source.c_str());
664 auto callable = tester.GetCallable<>();
665
666 callable().ToHandleChecked();
667 Handle<i::String> name = factory->InternalizeUtf8String("global");
668 Handle<i::Object> global_obj =
669 Object::GetProperty(isolate->global_object(), name).ToHandleChecked();
670 CHECK_EQ(Smi::cast(*global_obj), Smi::FromInt(999));
671}
672
673
674TEST(InterpreterCallGlobal) {
675 HandleAndZoneScope handles;
676
677 // Test calling a global function.
678 std::string source(
679 "function g_add(a, b) { return a + b; }\n"
680 "function " + InterpreterTester::function_name() + "() {\n"
681 " return g_add(5, 10);\n"
682 "}");
683 InterpreterTester tester(handles.main_isolate(), source.c_str());
684 auto callable = tester.GetCallable<>();
685
686 Handle<Object> return_val = callable().ToHandleChecked();
687 CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(15));
688}
689
690
691TEST(InterpreterLoadUnallocated) {
692 HandleAndZoneScope handles;
693
694 // Test loading an unallocated global.
695 std::string source(
696 "unallocated = 123;\n"
697 "function " + InterpreterTester::function_name() + "() {\n"
698 " return unallocated;\n"
699 "}");
700 InterpreterTester tester(handles.main_isolate(), source.c_str());
701 auto callable = tester.GetCallable<>();
702
703 Handle<Object> return_val = callable().ToHandleChecked();
704 CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(123));
705}
706
707
708TEST(InterpreterStoreUnallocated) {
709 HandleAndZoneScope handles;
710 i::Isolate* isolate = handles.main_isolate();
711 i::Factory* factory = isolate->factory();
712
713 // Test storing to an unallocated global.
714 std::string source(
715 "unallocated = 321;\n"
716 "function " + InterpreterTester::function_name() + "() {\n"
717 " unallocated = 999;\n"
718 "}");
719 InterpreterTester tester(handles.main_isolate(), source.c_str());
720 auto callable = tester.GetCallable<>();
721
722 callable().ToHandleChecked();
723 Handle<i::String> name = factory->InternalizeUtf8String("unallocated");
724 Handle<i::Object> global_obj =
725 Object::GetProperty(isolate->global_object(), name).ToHandleChecked();
726 CHECK_EQ(Smi::cast(*global_obj), Smi::FromInt(999));
727}
728
729
730TEST(InterpreterLoadNamedProperty) {
731 HandleAndZoneScope handles;
732 i::Isolate* isolate = handles.main_isolate();
733 i::Factory* factory = isolate->factory();
734 i::Zone zone;
735
736 i::FeedbackVectorSpec feedback_spec(&zone);
737 i::FeedbackVectorSlot slot = feedback_spec.AddLoadICSlot();
738
739 Handle<i::TypeFeedbackVector> vector =
740 i::NewTypeFeedbackVector(isolate, &feedback_spec);
741
742 Handle<i::String> name = factory->NewStringFromAsciiChecked("val");
743 name = factory->string_table()->LookupString(isolate, name);
744
Ben Murdoch097c5b22016-05-18 11:27:45 +0100745 BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone(), 1,
746 0, 0);
747 builder.LoadNamedProperty(builder.Parameter(0), name, vector->GetIndex(slot))
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000748 .Return();
749 Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
750
751 InterpreterTester tester(handles.main_isolate(), bytecode_array, vector);
752 auto callable = tester.GetCallable<Handle<Object>>();
753
754 Handle<Object> object = InterpreterTester::NewObject("({ val : 123 })");
755 // Test IC miss.
756 Handle<Object> return_val = callable(object).ToHandleChecked();
757 CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(123));
758
759 // Test transition to monomorphic IC.
760 return_val = callable(object).ToHandleChecked();
761 CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(123));
762
763 // Test transition to polymorphic IC.
764 Handle<Object> object2 =
765 InterpreterTester::NewObject("({ val : 456, other : 123 })");
766 return_val = callable(object2).ToHandleChecked();
767 CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(456));
768
769 // Test transition to megamorphic IC.
770 Handle<Object> object3 =
771 InterpreterTester::NewObject("({ val : 789, val2 : 123 })");
772 callable(object3).ToHandleChecked();
773 Handle<Object> object4 =
774 InterpreterTester::NewObject("({ val : 789, val3 : 123 })");
775 callable(object4).ToHandleChecked();
776 Handle<Object> object5 =
777 InterpreterTester::NewObject("({ val : 789, val4 : 123 })");
778 return_val = callable(object5).ToHandleChecked();
779 CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(789));
780}
781
782
783TEST(InterpreterLoadKeyedProperty) {
784 HandleAndZoneScope handles;
785 i::Isolate* isolate = handles.main_isolate();
786 i::Factory* factory = isolate->factory();
787 i::Zone zone;
788
789 i::FeedbackVectorSpec feedback_spec(&zone);
790 i::FeedbackVectorSlot slot = feedback_spec.AddKeyedLoadICSlot();
791
792 Handle<i::TypeFeedbackVector> vector =
793 i::NewTypeFeedbackVector(isolate, &feedback_spec);
794
795 Handle<i::String> key = factory->NewStringFromAsciiChecked("key");
796 key = factory->string_table()->LookupString(isolate, key);
797
Ben Murdoch097c5b22016-05-18 11:27:45 +0100798 BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone(), 1,
799 0, 1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000800 builder.LoadLiteral(key)
Ben Murdoch097c5b22016-05-18 11:27:45 +0100801 .LoadKeyedProperty(builder.Parameter(0), vector->GetIndex(slot))
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000802 .Return();
803 Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
804
805 InterpreterTester tester(handles.main_isolate(), bytecode_array, vector);
806 auto callable = tester.GetCallable<Handle<Object>>();
807
808 Handle<Object> object = InterpreterTester::NewObject("({ key : 123 })");
809 // Test IC miss.
810 Handle<Object> return_val = callable(object).ToHandleChecked();
811 CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(123));
812
813 // Test transition to monomorphic IC.
814 return_val = callable(object).ToHandleChecked();
815 CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(123));
816
817 // Test transition to megamorphic IC.
818 Handle<Object> object3 =
819 InterpreterTester::NewObject("({ key : 789, val2 : 123 })");
820 return_val = callable(object3).ToHandleChecked();
821 CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(789));
822}
823
824
825TEST(InterpreterStoreNamedProperty) {
826 HandleAndZoneScope handles;
827 i::Isolate* isolate = handles.main_isolate();
828 i::Factory* factory = isolate->factory();
829 i::Zone zone;
830
831 i::FeedbackVectorSpec feedback_spec(&zone);
832 i::FeedbackVectorSlot slot = feedback_spec.AddStoreICSlot();
833
834 Handle<i::TypeFeedbackVector> vector =
835 i::NewTypeFeedbackVector(isolate, &feedback_spec);
836
837 Handle<i::String> name = factory->NewStringFromAsciiChecked("val");
838 name = factory->string_table()->LookupString(isolate, name);
839
Ben Murdoch097c5b22016-05-18 11:27:45 +0100840 BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone(), 1,
841 0, 0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000842 builder.LoadLiteral(Smi::FromInt(999))
843 .StoreNamedProperty(builder.Parameter(0), name, vector->GetIndex(slot),
844 i::STRICT)
845 .Return();
846 Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
847
848 InterpreterTester tester(isolate, bytecode_array, vector);
849 auto callable = tester.GetCallable<Handle<Object>>();
850 Handle<Object> object = InterpreterTester::NewObject("({ val : 123 })");
851 // Test IC miss.
852 Handle<Object> result;
853 callable(object).ToHandleChecked();
854 CHECK(Runtime::GetObjectProperty(isolate, object, name).ToHandle(&result));
855 CHECK_EQ(Smi::cast(*result), Smi::FromInt(999));
856
857 // Test transition to monomorphic IC.
858 callable(object).ToHandleChecked();
859 CHECK(Runtime::GetObjectProperty(isolate, object, name).ToHandle(&result));
860 CHECK_EQ(Smi::cast(*result), Smi::FromInt(999));
861
862 // Test transition to polymorphic IC.
863 Handle<Object> object2 =
864 InterpreterTester::NewObject("({ val : 456, other : 123 })");
865 callable(object2).ToHandleChecked();
866 CHECK(Runtime::GetObjectProperty(isolate, object2, name).ToHandle(&result));
867 CHECK_EQ(Smi::cast(*result), Smi::FromInt(999));
868
869 // Test transition to megamorphic IC.
870 Handle<Object> object3 =
871 InterpreterTester::NewObject("({ val : 789, val2 : 123 })");
872 callable(object3).ToHandleChecked();
873 Handle<Object> object4 =
874 InterpreterTester::NewObject("({ val : 789, val3 : 123 })");
875 callable(object4).ToHandleChecked();
876 Handle<Object> object5 =
877 InterpreterTester::NewObject("({ val : 789, val4 : 123 })");
878 callable(object5).ToHandleChecked();
879 CHECK(Runtime::GetObjectProperty(isolate, object5, name).ToHandle(&result));
880 CHECK_EQ(Smi::cast(*result), Smi::FromInt(999));
881}
882
883
884TEST(InterpreterStoreKeyedProperty) {
885 HandleAndZoneScope handles;
886 i::Isolate* isolate = handles.main_isolate();
887 i::Factory* factory = isolate->factory();
888 i::Zone zone;
889
890 i::FeedbackVectorSpec feedback_spec(&zone);
891 i::FeedbackVectorSlot slot = feedback_spec.AddKeyedStoreICSlot();
892
893 Handle<i::TypeFeedbackVector> vector =
894 i::NewTypeFeedbackVector(isolate, &feedback_spec);
895
896 Handle<i::String> name = factory->NewStringFromAsciiChecked("val");
897 name = factory->string_table()->LookupString(isolate, name);
898
Ben Murdoch097c5b22016-05-18 11:27:45 +0100899 BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone(), 1,
900 0, 1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000901 builder.LoadLiteral(name)
902 .StoreAccumulatorInRegister(Register(0))
903 .LoadLiteral(Smi::FromInt(999))
904 .StoreKeyedProperty(builder.Parameter(0), Register(0),
905 vector->GetIndex(slot), i::SLOPPY)
906 .Return();
907 Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
908
909 InterpreterTester tester(isolate, bytecode_array, vector);
910 auto callable = tester.GetCallable<Handle<Object>>();
911 Handle<Object> object = InterpreterTester::NewObject("({ val : 123 })");
912 // Test IC miss.
913 Handle<Object> result;
914 callable(object).ToHandleChecked();
915 CHECK(Runtime::GetObjectProperty(isolate, object, name).ToHandle(&result));
916 CHECK_EQ(Smi::cast(*result), Smi::FromInt(999));
917
918 // Test transition to monomorphic IC.
919 callable(object).ToHandleChecked();
920 CHECK(Runtime::GetObjectProperty(isolate, object, name).ToHandle(&result));
921 CHECK_EQ(Smi::cast(*result), Smi::FromInt(999));
922
923 // Test transition to megamorphic IC.
924 Handle<Object> object2 =
925 InterpreterTester::NewObject("({ val : 456, other : 123 })");
926 callable(object2).ToHandleChecked();
927 CHECK(Runtime::GetObjectProperty(isolate, object2, name).ToHandle(&result));
928 CHECK_EQ(Smi::cast(*result), Smi::FromInt(999));
929}
930
Ben Murdoch097c5b22016-05-18 11:27:45 +0100931static void TestInterpreterCall(TailCallMode tail_call_mode) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000932 HandleAndZoneScope handles;
933 i::Isolate* isolate = handles.main_isolate();
934 i::Factory* factory = isolate->factory();
935 i::Zone zone;
936
937 i::FeedbackVectorSpec feedback_spec(&zone);
938 i::FeedbackVectorSlot slot = feedback_spec.AddLoadICSlot();
939
940 Handle<i::TypeFeedbackVector> vector =
941 i::NewTypeFeedbackVector(isolate, &feedback_spec);
942 int slot_index = vector->GetIndex(slot);
943
944 Handle<i::String> name = factory->NewStringFromAsciiChecked("func");
945 name = factory->string_table()->LookupString(isolate, name);
946
947 // Check with no args.
948 {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100949 BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone(), 1,
950 0, 1);
951 builder.LoadNamedProperty(builder.Parameter(0), name, slot_index)
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000952 .StoreAccumulatorInRegister(Register(0))
Ben Murdoch097c5b22016-05-18 11:27:45 +0100953 .Call(Register(0), builder.Parameter(0), 1, 0, tail_call_mode)
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000954 .Return();
955 Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
956
957 InterpreterTester tester(handles.main_isolate(), bytecode_array, vector);
958 auto callable = tester.GetCallable<Handle<Object>>();
959
960 Handle<Object> object = InterpreterTester::NewObject(
961 "new (function Obj() { this.func = function() { return 0x265; }})()");
962 Handle<Object> return_val = callable(object).ToHandleChecked();
963 CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(0x265));
964 }
965
966 // Check that receiver is passed properly.
967 {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100968 BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone(), 1,
969 0, 1);
970 builder.LoadNamedProperty(builder.Parameter(0), name, slot_index)
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000971 .StoreAccumulatorInRegister(Register(0))
Ben Murdoch097c5b22016-05-18 11:27:45 +0100972 .Call(Register(0), builder.Parameter(0), 1, 0, tail_call_mode)
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000973 .Return();
974 Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
975
976 InterpreterTester tester(handles.main_isolate(), bytecode_array, vector);
977 auto callable = tester.GetCallable<Handle<Object>>();
978
979 Handle<Object> object = InterpreterTester::NewObject(
980 "new (function Obj() {"
981 " this.val = 1234;"
982 " this.func = function() { return this.val; };"
983 "})()");
984 Handle<Object> return_val = callable(object).ToHandleChecked();
985 CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(1234));
986 }
987
988 // Check with two parameters (+ receiver).
989 {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100990 BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone(), 1,
991 0, 4);
992 builder.LoadNamedProperty(builder.Parameter(0), name, slot_index)
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000993 .StoreAccumulatorInRegister(Register(0))
994 .LoadAccumulatorWithRegister(builder.Parameter(0))
995 .StoreAccumulatorInRegister(Register(1))
996 .LoadLiteral(Smi::FromInt(51))
997 .StoreAccumulatorInRegister(Register(2))
998 .LoadLiteral(Smi::FromInt(11))
999 .StoreAccumulatorInRegister(Register(3))
Ben Murdoch097c5b22016-05-18 11:27:45 +01001000 .Call(Register(0), Register(1), 3, 0, tail_call_mode)
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001001 .Return();
1002 Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
1003
1004 InterpreterTester tester(handles.main_isolate(), bytecode_array, vector);
1005 auto callable = tester.GetCallable<Handle<Object>>();
1006
1007 Handle<Object> object = InterpreterTester::NewObject(
1008 "new (function Obj() { "
1009 " this.func = function(a, b) { return a - b; }"
1010 "})()");
1011 Handle<Object> return_val = callable(object).ToHandleChecked();
1012 CHECK(return_val->SameValue(Smi::FromInt(40)));
1013 }
1014
1015 // Check with 10 parameters (+ receiver).
1016 {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001017 BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone(), 1,
1018 0, 12);
1019 builder.LoadNamedProperty(builder.Parameter(0), name, slot_index)
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001020 .StoreAccumulatorInRegister(Register(0))
1021 .LoadAccumulatorWithRegister(builder.Parameter(0))
1022 .StoreAccumulatorInRegister(Register(1))
1023 .LoadLiteral(factory->NewStringFromAsciiChecked("a"))
1024 .StoreAccumulatorInRegister(Register(2))
1025 .LoadLiteral(factory->NewStringFromAsciiChecked("b"))
1026 .StoreAccumulatorInRegister(Register(3))
1027 .LoadLiteral(factory->NewStringFromAsciiChecked("c"))
1028 .StoreAccumulatorInRegister(Register(4))
1029 .LoadLiteral(factory->NewStringFromAsciiChecked("d"))
1030 .StoreAccumulatorInRegister(Register(5))
1031 .LoadLiteral(factory->NewStringFromAsciiChecked("e"))
1032 .StoreAccumulatorInRegister(Register(6))
1033 .LoadLiteral(factory->NewStringFromAsciiChecked("f"))
1034 .StoreAccumulatorInRegister(Register(7))
1035 .LoadLiteral(factory->NewStringFromAsciiChecked("g"))
1036 .StoreAccumulatorInRegister(Register(8))
1037 .LoadLiteral(factory->NewStringFromAsciiChecked("h"))
1038 .StoreAccumulatorInRegister(Register(9))
1039 .LoadLiteral(factory->NewStringFromAsciiChecked("i"))
1040 .StoreAccumulatorInRegister(Register(10))
1041 .LoadLiteral(factory->NewStringFromAsciiChecked("j"))
1042 .StoreAccumulatorInRegister(Register(11))
Ben Murdoch097c5b22016-05-18 11:27:45 +01001043 .Call(Register(0), Register(1), 11, 0, tail_call_mode)
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001044 .Return();
1045 Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
1046
1047 InterpreterTester tester(handles.main_isolate(), bytecode_array, vector);
1048 auto callable = tester.GetCallable<Handle<Object>>();
1049
1050 Handle<Object> object = InterpreterTester::NewObject(
1051 "new (function Obj() { "
1052 " this.prefix = \"prefix_\";"
1053 " this.func = function(a, b, c, d, e, f, g, h, i, j) {"
1054 " return this.prefix + a + b + c + d + e + f + g + h + i + j;"
1055 " }"
1056 "})()");
1057 Handle<Object> return_val = callable(object).ToHandleChecked();
1058 Handle<i::String> expected =
1059 factory->NewStringFromAsciiChecked("prefix_abcdefghij");
1060 CHECK(i::String::cast(*return_val)->Equals(*expected));
1061 }
1062}
1063
Ben Murdoch097c5b22016-05-18 11:27:45 +01001064TEST(InterpreterCall) { TestInterpreterCall(TailCallMode::kDisallow); }
1065
1066TEST(InterpreterTailCall) { TestInterpreterCall(TailCallMode::kAllow); }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001067
1068static BytecodeArrayBuilder& SetRegister(BytecodeArrayBuilder& builder,
1069 Register reg, int value,
1070 Register scratch) {
1071 return builder.StoreAccumulatorInRegister(scratch)
1072 .LoadLiteral(Smi::FromInt(value))
1073 .StoreAccumulatorInRegister(reg)
1074 .LoadAccumulatorWithRegister(scratch);
1075}
1076
1077
1078static BytecodeArrayBuilder& IncrementRegister(BytecodeArrayBuilder& builder,
1079 Register reg, int value,
1080 Register scratch) {
1081 return builder.StoreAccumulatorInRegister(scratch)
1082 .LoadLiteral(Smi::FromInt(value))
Ben Murdoch097c5b22016-05-18 11:27:45 +01001083 .BinaryOperation(Token::Value::ADD, reg)
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001084 .StoreAccumulatorInRegister(reg)
1085 .LoadAccumulatorWithRegister(scratch);
1086}
1087
1088
1089TEST(InterpreterJumps) {
1090 HandleAndZoneScope handles;
Ben Murdoch097c5b22016-05-18 11:27:45 +01001091 BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone(), 0,
1092 0, 2);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001093 Register reg(0), scratch(1);
1094 BytecodeLabel label[3];
1095
1096 builder.LoadLiteral(Smi::FromInt(0))
1097 .StoreAccumulatorInRegister(reg)
1098 .Jump(&label[1]);
1099 SetRegister(builder, reg, 1024, scratch).Bind(&label[0]);
1100 IncrementRegister(builder, reg, 1, scratch).Jump(&label[2]);
1101 SetRegister(builder, reg, 2048, scratch).Bind(&label[1]);
1102 IncrementRegister(builder, reg, 2, scratch).Jump(&label[0]);
1103 SetRegister(builder, reg, 4096, scratch).Bind(&label[2]);
1104 IncrementRegister(builder, reg, 4, scratch)
1105 .LoadAccumulatorWithRegister(reg)
1106 .Return();
1107
1108 Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
1109 InterpreterTester tester(handles.main_isolate(), bytecode_array);
1110 auto callable = tester.GetCallable<>();
1111 Handle<Object> return_value = callable().ToHandleChecked();
1112 CHECK_EQ(Smi::cast(*return_value)->value(), 7);
1113}
1114
1115
1116TEST(InterpreterConditionalJumps) {
1117 HandleAndZoneScope handles;
Ben Murdoch097c5b22016-05-18 11:27:45 +01001118 BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone(), 0,
1119 0, 2);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001120 Register reg(0), scratch(1);
1121 BytecodeLabel label[2];
1122 BytecodeLabel done, done1;
1123
1124 builder.LoadLiteral(Smi::FromInt(0))
1125 .StoreAccumulatorInRegister(reg)
1126 .LoadFalse()
1127 .JumpIfFalse(&label[0]);
1128 IncrementRegister(builder, reg, 1024, scratch)
1129 .Bind(&label[0])
1130 .LoadTrue()
1131 .JumpIfFalse(&done);
1132 IncrementRegister(builder, reg, 1, scratch).LoadTrue().JumpIfTrue(&label[1]);
1133 IncrementRegister(builder, reg, 2048, scratch).Bind(&label[1]);
1134 IncrementRegister(builder, reg, 2, scratch).LoadFalse().JumpIfTrue(&done1);
1135 IncrementRegister(builder, reg, 4, scratch)
1136 .LoadAccumulatorWithRegister(reg)
1137 .Bind(&done)
1138 .Bind(&done1)
1139 .Return();
1140
1141 Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
1142 InterpreterTester tester(handles.main_isolate(), bytecode_array);
1143 auto callable = tester.GetCallable<>();
1144 Handle<Object> return_value = callable().ToHandleChecked();
1145 CHECK_EQ(Smi::cast(*return_value)->value(), 7);
1146}
1147
1148
1149TEST(InterpreterConditionalJumps2) {
1150 // TODO(oth): Add tests for all conditional jumps near and far.
1151 HandleAndZoneScope handles;
Ben Murdoch097c5b22016-05-18 11:27:45 +01001152 BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone(), 0,
1153 0, 2);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001154 Register reg(0), scratch(1);
1155 BytecodeLabel label[2];
1156 BytecodeLabel done, done1;
1157
1158 builder.LoadLiteral(Smi::FromInt(0))
1159 .StoreAccumulatorInRegister(reg)
1160 .LoadFalse()
1161 .JumpIfFalse(&label[0]);
1162 IncrementRegister(builder, reg, 1024, scratch)
1163 .Bind(&label[0])
1164 .LoadTrue()
1165 .JumpIfFalse(&done);
1166 IncrementRegister(builder, reg, 1, scratch).LoadTrue().JumpIfTrue(&label[1]);
1167 IncrementRegister(builder, reg, 2048, scratch).Bind(&label[1]);
1168 IncrementRegister(builder, reg, 2, scratch).LoadFalse().JumpIfTrue(&done1);
1169 IncrementRegister(builder, reg, 4, scratch)
1170 .LoadAccumulatorWithRegister(reg)
1171 .Bind(&done)
1172 .Bind(&done1)
1173 .Return();
1174
1175 Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
1176 InterpreterTester tester(handles.main_isolate(), bytecode_array);
1177 auto callable = tester.GetCallable<>();
1178 Handle<Object> return_value = callable().ToHandleChecked();
1179 CHECK_EQ(Smi::cast(*return_value)->value(), 7);
1180}
1181
1182
1183static const Token::Value kComparisonTypes[] = {
1184 Token::Value::EQ, Token::Value::NE, Token::Value::EQ_STRICT,
1185 Token::Value::NE_STRICT, Token::Value::LT, Token::Value::LTE,
1186 Token::Value::GT, Token::Value::GTE};
1187
1188
1189template <typename T>
1190bool CompareC(Token::Value op, T lhs, T rhs, bool types_differed = false) {
1191 switch (op) {
1192 case Token::Value::EQ:
1193 return lhs == rhs;
1194 case Token::Value::NE:
1195 return lhs != rhs;
1196 case Token::Value::EQ_STRICT:
1197 return (lhs == rhs) && !types_differed;
1198 case Token::Value::NE_STRICT:
1199 return (lhs != rhs) || types_differed;
1200 case Token::Value::LT:
1201 return lhs < rhs;
1202 case Token::Value::LTE:
1203 return lhs <= rhs;
1204 case Token::Value::GT:
1205 return lhs > rhs;
1206 case Token::Value::GTE:
1207 return lhs >= rhs;
1208 default:
1209 UNREACHABLE();
1210 return false;
1211 }
1212}
1213
1214
1215TEST(InterpreterSmiComparisons) {
1216 // NB Constants cover 31-bit space.
1217 int inputs[] = {v8::internal::kMinInt / 2,
1218 v8::internal::kMinInt / 4,
1219 -108733832,
1220 -999,
1221 -42,
1222 -2,
1223 -1,
1224 0,
1225 +1,
1226 +2,
1227 42,
1228 12345678,
1229 v8::internal::kMaxInt / 4,
1230 v8::internal::kMaxInt / 2};
1231
1232 for (size_t c = 0; c < arraysize(kComparisonTypes); c++) {
1233 Token::Value comparison = kComparisonTypes[c];
1234 for (size_t i = 0; i < arraysize(inputs); i++) {
1235 for (size_t j = 0; j < arraysize(inputs); j++) {
1236 HandleAndZoneScope handles;
1237 BytecodeArrayBuilder builder(handles.main_isolate(),
Ben Murdoch097c5b22016-05-18 11:27:45 +01001238 handles.main_zone(), 0, 0, 1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001239 Register r0(0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001240 builder.LoadLiteral(Smi::FromInt(inputs[i]))
1241 .StoreAccumulatorInRegister(r0)
1242 .LoadLiteral(Smi::FromInt(inputs[j]))
Ben Murdoch097c5b22016-05-18 11:27:45 +01001243 .CompareOperation(comparison, r0)
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001244 .Return();
1245
1246 Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
1247 InterpreterTester tester(handles.main_isolate(), bytecode_array);
1248 auto callable = tester.GetCallable<>();
1249 Handle<Object> return_value = callable().ToHandleChecked();
1250 CHECK(return_value->IsBoolean());
1251 CHECK_EQ(return_value->BooleanValue(),
1252 CompareC(comparison, inputs[i], inputs[j]));
1253 }
1254 }
1255 }
1256}
1257
1258
1259TEST(InterpreterHeapNumberComparisons) {
1260 double inputs[] = {std::numeric_limits<double>::min(),
1261 std::numeric_limits<double>::max(),
1262 -0.001,
1263 0.01,
1264 0.1000001,
1265 1e99,
1266 -1e-99};
1267 for (size_t c = 0; c < arraysize(kComparisonTypes); c++) {
1268 Token::Value comparison = kComparisonTypes[c];
1269 for (size_t i = 0; i < arraysize(inputs); i++) {
1270 for (size_t j = 0; j < arraysize(inputs); j++) {
1271 HandleAndZoneScope handles;
1272 i::Factory* factory = handles.main_isolate()->factory();
1273 BytecodeArrayBuilder builder(handles.main_isolate(),
Ben Murdoch097c5b22016-05-18 11:27:45 +01001274 handles.main_zone(), 0, 0, 1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001275 Register r0(0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001276 builder.LoadLiteral(factory->NewHeapNumber(inputs[i]))
1277 .StoreAccumulatorInRegister(r0)
1278 .LoadLiteral(factory->NewHeapNumber(inputs[j]))
Ben Murdoch097c5b22016-05-18 11:27:45 +01001279 .CompareOperation(comparison, r0)
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001280 .Return();
1281
1282 Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
1283 InterpreterTester tester(handles.main_isolate(), bytecode_array);
1284 auto callable = tester.GetCallable<>();
1285 Handle<Object> return_value = callable().ToHandleChecked();
1286 CHECK(return_value->IsBoolean());
1287 CHECK_EQ(return_value->BooleanValue(),
1288 CompareC(comparison, inputs[i], inputs[j]));
1289 }
1290 }
1291 }
1292}
1293
1294
1295TEST(InterpreterStringComparisons) {
1296 std::string inputs[] = {"A", "abc", "z", "", "Foo!", "Foo"};
1297
1298 for (size_t c = 0; c < arraysize(kComparisonTypes); c++) {
1299 Token::Value comparison = kComparisonTypes[c];
1300 for (size_t i = 0; i < arraysize(inputs); i++) {
1301 for (size_t j = 0; j < arraysize(inputs); j++) {
1302 const char* lhs = inputs[i].c_str();
1303 const char* rhs = inputs[j].c_str();
1304 HandleAndZoneScope handles;
1305 i::Factory* factory = handles.main_isolate()->factory();
1306 BytecodeArrayBuilder builder(handles.main_isolate(),
Ben Murdoch097c5b22016-05-18 11:27:45 +01001307 handles.main_zone(), 0, 0, 1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001308 Register r0(0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001309 builder.LoadLiteral(factory->NewStringFromAsciiChecked(lhs))
1310 .StoreAccumulatorInRegister(r0)
1311 .LoadLiteral(factory->NewStringFromAsciiChecked(rhs))
Ben Murdoch097c5b22016-05-18 11:27:45 +01001312 .CompareOperation(comparison, r0)
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001313 .Return();
1314
1315 Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
1316 InterpreterTester tester(handles.main_isolate(), bytecode_array);
1317 auto callable = tester.GetCallable<>();
1318 Handle<Object> return_value = callable().ToHandleChecked();
1319 CHECK(return_value->IsBoolean());
1320 CHECK_EQ(return_value->BooleanValue(),
1321 CompareC(comparison, inputs[i], inputs[j]));
1322 }
1323 }
1324 }
1325}
1326
1327
1328TEST(InterpreterMixedComparisons) {
1329 // This test compares a HeapNumber with a String. The latter is
1330 // convertible to a HeapNumber so comparison will be between numeric
1331 // values except for the strict comparisons where no conversion is
1332 // performed.
1333 const char* inputs[] = {"-1.77", "-40.333", "0.01", "55.77e5", "2.01"};
1334
1335 i::UnicodeCache unicode_cache;
1336
1337 for (size_t c = 0; c < arraysize(kComparisonTypes); c++) {
1338 Token::Value comparison = kComparisonTypes[c];
1339 for (size_t i = 0; i < arraysize(inputs); i++) {
1340 for (size_t j = 0; j < arraysize(inputs); j++) {
1341 for (int pass = 0; pass < 2; pass++) {
1342 const char* lhs_cstr = inputs[i];
1343 const char* rhs_cstr = inputs[j];
1344 double lhs = StringToDouble(&unicode_cache, lhs_cstr,
1345 i::ConversionFlags::NO_FLAGS);
1346 double rhs = StringToDouble(&unicode_cache, rhs_cstr,
1347 i::ConversionFlags::NO_FLAGS);
1348 HandleAndZoneScope handles;
1349 i::Factory* factory = handles.main_isolate()->factory();
1350 BytecodeArrayBuilder builder(handles.main_isolate(),
Ben Murdoch097c5b22016-05-18 11:27:45 +01001351 handles.main_zone(), 0, 0, 1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001352 Register r0(0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001353 if (pass == 0) {
1354 // Comparison with HeapNumber on the lhs and String on the rhs
1355 builder.LoadLiteral(factory->NewNumber(lhs))
1356 .StoreAccumulatorInRegister(r0)
1357 .LoadLiteral(factory->NewStringFromAsciiChecked(rhs_cstr))
Ben Murdoch097c5b22016-05-18 11:27:45 +01001358 .CompareOperation(comparison, r0)
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001359 .Return();
1360 } else {
1361 // Comparison with HeapNumber on the rhs and String on the lhs
1362 builder.LoadLiteral(factory->NewStringFromAsciiChecked(lhs_cstr))
1363 .StoreAccumulatorInRegister(r0)
1364 .LoadLiteral(factory->NewNumber(rhs))
Ben Murdoch097c5b22016-05-18 11:27:45 +01001365 .CompareOperation(comparison, r0)
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001366 .Return();
1367 }
1368
1369 Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
1370 InterpreterTester tester(handles.main_isolate(), bytecode_array);
1371 auto callable = tester.GetCallable<>();
1372 Handle<Object> return_value = callable().ToHandleChecked();
1373 CHECK(return_value->IsBoolean());
1374 CHECK_EQ(return_value->BooleanValue(),
1375 CompareC(comparison, lhs, rhs, true));
1376 }
1377 }
1378 }
1379 }
1380}
1381
1382
1383TEST(InterpreterInstanceOf) {
1384 HandleAndZoneScope handles;
1385 i::Factory* factory = handles.main_isolate()->factory();
1386 Handle<i::String> name = factory->NewStringFromAsciiChecked("cons");
1387 Handle<i::JSFunction> func = factory->NewFunction(name);
1388 Handle<i::JSObject> instance = factory->NewJSObject(func);
1389 Handle<i::Object> other = factory->NewNumber(3.3333);
1390 Handle<i::Object> cases[] = {Handle<i::Object>::cast(instance), other};
1391 for (size_t i = 0; i < arraysize(cases); i++) {
1392 bool expected_value = (i == 0);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001393 BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone(), 0,
1394 0, 1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001395 Register r0(0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001396 builder.LoadLiteral(cases[i]);
1397 builder.StoreAccumulatorInRegister(r0)
1398 .LoadLiteral(func)
Ben Murdoch097c5b22016-05-18 11:27:45 +01001399 .CompareOperation(Token::Value::INSTANCEOF, r0)
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001400 .Return();
1401
1402 Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
1403 InterpreterTester tester(handles.main_isolate(), bytecode_array);
1404 auto callable = tester.GetCallable<>();
1405 Handle<Object> return_value = callable().ToHandleChecked();
1406 CHECK(return_value->IsBoolean());
1407 CHECK_EQ(return_value->BooleanValue(), expected_value);
1408 }
1409}
1410
1411
1412TEST(InterpreterTestIn) {
1413 HandleAndZoneScope handles;
1414 i::Factory* factory = handles.main_isolate()->factory();
1415 // Allocate an array
1416 Handle<i::JSArray> array =
Ben Murdoch097c5b22016-05-18 11:27:45 +01001417 factory->NewJSArray(0, i::ElementsKind::FAST_SMI_ELEMENTS);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001418 // Check for these properties on the array object
1419 const char* properties[] = {"length", "fuzzle", "x", "0"};
1420 for (size_t i = 0; i < arraysize(properties); i++) {
1421 bool expected_value = (i == 0);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001422 BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone(), 0,
1423 0, 1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001424 Register r0(0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001425 builder.LoadLiteral(factory->NewStringFromAsciiChecked(properties[i]))
1426 .StoreAccumulatorInRegister(r0)
1427 .LoadLiteral(Handle<Object>::cast(array))
Ben Murdoch097c5b22016-05-18 11:27:45 +01001428 .CompareOperation(Token::Value::IN, r0)
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001429 .Return();
1430
1431 Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
1432 InterpreterTester tester(handles.main_isolate(), bytecode_array);
1433 auto callable = tester.GetCallable<>();
1434 Handle<Object> return_value = callable().ToHandleChecked();
1435 CHECK(return_value->IsBoolean());
1436 CHECK_EQ(return_value->BooleanValue(), expected_value);
1437 }
1438}
1439
1440
1441TEST(InterpreterUnaryNot) {
1442 HandleAndZoneScope handles;
1443 for (size_t i = 1; i < 10; i++) {
1444 bool expected_value = ((i & 1) == 1);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001445 BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone(), 0,
1446 0, 0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001447 Register r0(0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001448 builder.LoadFalse();
1449 for (size_t j = 0; j < i; j++) {
1450 builder.LogicalNot();
1451 }
1452 builder.Return();
1453 Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
1454 InterpreterTester tester(handles.main_isolate(), bytecode_array);
1455 auto callable = tester.GetCallable<>();
1456 Handle<Object> return_value = callable().ToHandleChecked();
1457 CHECK(return_value->IsBoolean());
1458 CHECK_EQ(return_value->BooleanValue(), expected_value);
1459 }
1460}
1461
1462
1463static void LoadAny(BytecodeArrayBuilder* builder,
1464 v8::internal::Factory* factory, Handle<Object> obj) {
1465 if (obj->IsOddball()) {
1466 if (obj->SameValue(*factory->true_value())) {
1467 builder->LoadTrue();
1468 } else if (obj->SameValue(*factory->false_value())) {
1469 builder->LoadFalse();
1470 } else if (obj->SameValue(*factory->the_hole_value())) {
1471 builder->LoadTheHole();
1472 } else if (obj->SameValue(*factory->null_value())) {
1473 builder->LoadNull();
1474 } else if (obj->SameValue(*factory->undefined_value())) {
1475 builder->LoadUndefined();
1476 } else {
1477 UNREACHABLE();
1478 }
1479 } else if (obj->IsSmi()) {
1480 builder->LoadLiteral(*Handle<Smi>::cast(obj));
1481 } else {
1482 builder->LoadLiteral(obj);
1483 }
1484}
1485
1486
1487TEST(InterpreterUnaryNotNonBoolean) {
1488 HandleAndZoneScope handles;
1489 i::Factory* factory = handles.main_isolate()->factory();
1490
1491 std::pair<Handle<Object>, bool> object_type_tuples[] = {
1492 std::make_pair(factory->undefined_value(), true),
1493 std::make_pair(factory->null_value(), true),
1494 std::make_pair(factory->false_value(), true),
1495 std::make_pair(factory->true_value(), false),
1496 std::make_pair(factory->NewNumber(9.1), false),
1497 std::make_pair(factory->NewNumberFromInt(0), true),
1498 std::make_pair(
1499 Handle<Object>::cast(factory->NewStringFromStaticChars("hello")),
1500 false),
1501 std::make_pair(
1502 Handle<Object>::cast(factory->NewStringFromStaticChars("")), true),
1503 };
1504
1505 for (size_t i = 0; i < arraysize(object_type_tuples); i++) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001506 BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone(), 0,
1507 0, 0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001508 Register r0(0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001509 LoadAny(&builder, factory, object_type_tuples[i].first);
1510 builder.LogicalNot();
1511 builder.Return();
1512 Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
1513 InterpreterTester tester(handles.main_isolate(), bytecode_array);
1514 auto callable = tester.GetCallable<>();
1515 Handle<Object> return_value = callable().ToHandleChecked();
1516 CHECK(return_value->IsBoolean());
1517 CHECK_EQ(return_value->BooleanValue(), object_type_tuples[i].second);
1518 }
1519}
1520
1521
1522TEST(InterpreterTypeof) {
1523 HandleAndZoneScope handles;
1524
1525 std::pair<const char*, const char*> typeof_vals[] = {
1526 std::make_pair("return typeof undefined;", "undefined"),
1527 std::make_pair("return typeof null;", "object"),
1528 std::make_pair("return typeof true;", "boolean"),
1529 std::make_pair("return typeof false;", "boolean"),
1530 std::make_pair("return typeof 9.1;", "number"),
1531 std::make_pair("return typeof 7771;", "number"),
1532 std::make_pair("return typeof 'hello';", "string"),
1533 std::make_pair("return typeof global_unallocated;", "undefined"),
1534 };
1535
1536 for (size_t i = 0; i < arraysize(typeof_vals); i++) {
1537 std::string source(InterpreterTester::SourceForBody(typeof_vals[i].first));
1538 InterpreterTester tester(handles.main_isolate(), source.c_str());
1539
1540 auto callable = tester.GetCallable<>();
1541 Handle<v8::internal::String> return_value =
1542 Handle<v8::internal::String>::cast(callable().ToHandleChecked());
1543 auto actual = return_value->ToCString();
1544 CHECK_EQ(strcmp(&actual[0], typeof_vals[i].second), 0);
1545 }
1546}
1547
1548
1549TEST(InterpreterCallRuntime) {
1550 HandleAndZoneScope handles;
1551
Ben Murdoch097c5b22016-05-18 11:27:45 +01001552 BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone(), 1,
1553 0, 2);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001554 builder.LoadLiteral(Smi::FromInt(15))
1555 .StoreAccumulatorInRegister(Register(0))
1556 .LoadLiteral(Smi::FromInt(40))
1557 .StoreAccumulatorInRegister(Register(1))
1558 .CallRuntime(Runtime::kAdd, Register(0), 2)
1559 .Return();
1560 Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray();
1561
1562 InterpreterTester tester(handles.main_isolate(), bytecode_array);
1563 auto callable = tester.GetCallable<>();
1564
1565 Handle<Object> return_val = callable().ToHandleChecked();
1566 CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(55));
1567}
1568
1569
1570TEST(InterpreterFunctionLiteral) {
1571 HandleAndZoneScope handles;
1572
1573 // Test calling a function literal.
1574 std::string source(
1575 "function " + InterpreterTester::function_name() + "(a) {\n"
1576 " return (function(x){ return x + 2; })(a);\n"
1577 "}");
1578 InterpreterTester tester(handles.main_isolate(), source.c_str());
1579 auto callable = tester.GetCallable<Handle<Object>>();
1580
1581 Handle<i::Object> return_val = callable(
1582 Handle<Smi>(Smi::FromInt(3), handles.main_isolate())).ToHandleChecked();
1583 CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(5));
1584}
1585
1586
1587TEST(InterpreterRegExpLiterals) {
1588 HandleAndZoneScope handles;
1589 i::Isolate* isolate = handles.main_isolate();
1590 i::Factory* factory = isolate->factory();
1591
1592 std::pair<const char*, Handle<Object>> literals[] = {
1593 std::make_pair("return /abd/.exec('cccabbdd');\n",
1594 factory->null_value()),
1595 std::make_pair("return /ab+d/.exec('cccabbdd')[0];\n",
1596 factory->NewStringFromStaticChars("abbd")),
1597 std::make_pair("return /AbC/i.exec('ssaBC')[0];\n",
1598 factory->NewStringFromStaticChars("aBC")),
1599 std::make_pair("return 'ssaBC'.match(/AbC/i)[0];\n",
1600 factory->NewStringFromStaticChars("aBC")),
1601 std::make_pair("return 'ssaBCtAbC'.match(/(AbC)/gi)[1];\n",
1602 factory->NewStringFromStaticChars("AbC")),
1603 };
1604
1605 for (size_t i = 0; i < arraysize(literals); i++) {
1606 std::string source(InterpreterTester::SourceForBody(literals[i].first));
1607 InterpreterTester tester(handles.main_isolate(), source.c_str());
1608 auto callable = tester.GetCallable<>();
1609
1610 Handle<i::Object> return_value = callable().ToHandleChecked();
1611 CHECK(return_value->SameValue(*literals[i].second));
1612 }
1613}
1614
1615
1616TEST(InterpreterArrayLiterals) {
1617 HandleAndZoneScope handles;
1618 i::Isolate* isolate = handles.main_isolate();
1619 i::Factory* factory = isolate->factory();
1620
1621 std::pair<const char*, Handle<Object>> literals[] = {
1622 std::make_pair("return [][0];\n",
1623 factory->undefined_value()),
1624 std::make_pair("return [1, 3, 2][1];\n",
1625 handle(Smi::FromInt(3), isolate)),
1626 std::make_pair("return ['a', 'b', 'c'][2];\n",
1627 factory->NewStringFromStaticChars("c")),
1628 std::make_pair("var a = 100; return [a, a + 1, a + 2, a + 3][2];\n",
1629 handle(Smi::FromInt(102), isolate)),
1630 std::make_pair("return [[1, 2, 3], ['a', 'b', 'c']][1][0];\n",
1631 factory->NewStringFromStaticChars("a")),
1632 std::make_pair("var t = 't'; return [[t, t + 'est'], [1 + t]][0][1];\n",
1633 factory->NewStringFromStaticChars("test"))
1634 };
1635
1636 for (size_t i = 0; i < arraysize(literals); i++) {
1637 std::string source(InterpreterTester::SourceForBody(literals[i].first));
1638 InterpreterTester tester(handles.main_isolate(), source.c_str());
1639 auto callable = tester.GetCallable<>();
1640
1641 Handle<i::Object> return_value = callable().ToHandleChecked();
1642 CHECK(return_value->SameValue(*literals[i].second));
1643 }
1644}
1645
1646
1647TEST(InterpreterObjectLiterals) {
1648 HandleAndZoneScope handles;
1649 i::Isolate* isolate = handles.main_isolate();
1650 i::Factory* factory = isolate->factory();
1651
1652 std::pair<const char*, Handle<Object>> literals[] = {
1653 std::make_pair("return { }.name;",
1654 factory->undefined_value()),
1655 std::make_pair("return { name: 'string', val: 9.2 }.name;",
1656 factory->NewStringFromStaticChars("string")),
1657 std::make_pair("var a = 15; return { name: 'string', val: a }.val;",
1658 handle(Smi::FromInt(15), isolate)),
1659 std::make_pair("var a = 5; return { val: a, val: a + 1 }.val;",
1660 handle(Smi::FromInt(6), isolate)),
1661 std::make_pair("return { func: function() { return 'test' } }.func();",
1662 factory->NewStringFromStaticChars("test")),
1663 std::make_pair("return { func(a) { return a + 'st'; } }.func('te');",
1664 factory->NewStringFromStaticChars("test")),
1665 std::make_pair("return { get a() { return 22; } }.a;",
1666 handle(Smi::FromInt(22), isolate)),
1667 std::make_pair("var a = { get b() { return this.x + 't'; },\n"
1668 " set b(val) { this.x = val + 's' } };\n"
1669 "a.b = 'te';\n"
1670 "return a.b;",
1671 factory->NewStringFromStaticChars("test")),
1672 std::make_pair("var a = 123; return { 1: a }[1];",
1673 handle(Smi::FromInt(123), isolate)),
1674 std::make_pair("return Object.getPrototypeOf({ __proto__: null });",
1675 factory->null_value()),
1676 std::make_pair("var a = 'test'; return { [a]: 1 }.test;",
1677 handle(Smi::FromInt(1), isolate)),
1678 std::make_pair("var a = 'test'; return { b: a, [a]: a + 'ing' }['test']",
1679 factory->NewStringFromStaticChars("testing")),
1680 std::make_pair("var a = 'proto_str';\n"
1681 "var b = { [a]: 1, __proto__: { var : a } };\n"
1682 "return Object.getPrototypeOf(b).var",
1683 factory->NewStringFromStaticChars("proto_str")),
1684 std::make_pair("var n = 'name';\n"
1685 "return { [n]: 'val', get a() { return 987 } }['a'];",
1686 handle(Smi::FromInt(987), isolate)),
1687 };
1688
1689 for (size_t i = 0; i < arraysize(literals); i++) {
1690 std::string source(InterpreterTester::SourceForBody(literals[i].first));
1691 InterpreterTester tester(handles.main_isolate(), source.c_str());
1692 auto callable = tester.GetCallable<>();
1693
1694 Handle<i::Object> return_value = callable().ToHandleChecked();
1695 CHECK(return_value->SameValue(*literals[i].second));
1696 }
1697}
1698
1699
1700TEST(InterpreterConstruct) {
1701 HandleAndZoneScope handles;
1702
1703 std::string source(
1704 "function counter() { this.count = 0; }\n"
1705 "function " +
1706 InterpreterTester::function_name() +
1707 "() {\n"
1708 " var c = new counter();\n"
1709 " return c.count;\n"
1710 "}");
1711 InterpreterTester tester(handles.main_isolate(), source.c_str());
1712 auto callable = tester.GetCallable<>();
1713
1714 Handle<Object> return_val = callable().ToHandleChecked();
1715 CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(0));
1716}
1717
1718
1719TEST(InterpreterConstructWithArgument) {
1720 HandleAndZoneScope handles;
1721
1722 std::string source(
1723 "function counter(arg0) { this.count = 17; this.x = arg0; }\n"
1724 "function " +
1725 InterpreterTester::function_name() +
1726 "() {\n"
1727 " var c = new counter(3);\n"
1728 " return c.x;\n"
1729 "}");
1730 InterpreterTester tester(handles.main_isolate(), source.c_str());
1731 auto callable = tester.GetCallable<>();
1732
1733 Handle<Object> return_val = callable().ToHandleChecked();
1734 CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(3));
1735}
1736
1737
1738TEST(InterpreterConstructWithArguments) {
1739 HandleAndZoneScope handles;
1740
1741 std::string source(
1742 "function counter(arg0, arg1) {\n"
1743 " this.count = 7; this.x = arg0; this.y = arg1;\n"
1744 "}\n"
1745 "function " +
1746 InterpreterTester::function_name() +
1747 "() {\n"
1748 " var c = new counter(3, 5);\n"
1749 " return c.count + c.x + c.y;\n"
1750 "}");
1751 InterpreterTester tester(handles.main_isolate(), source.c_str());
1752 auto callable = tester.GetCallable<>();
1753
1754 Handle<Object> return_val = callable().ToHandleChecked();
1755 CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(15));
1756}
1757
1758
1759TEST(InterpreterContextVariables) {
1760 HandleAndZoneScope handles;
1761 i::Isolate* isolate = handles.main_isolate();
1762
1763 std::ostringstream unique_vars;
1764 for (int i = 0; i < 250; i++) {
1765 unique_vars << "var a" << i << " = 0;";
1766 }
1767 std::pair<std::string, Handle<Object>> context_vars[] = {
1768 std::make_pair("var a; (function() { a = 1; })(); return a;",
1769 handle(Smi::FromInt(1), isolate)),
1770 std::make_pair("var a = 10; (function() { a; })(); return a;",
1771 handle(Smi::FromInt(10), isolate)),
1772 std::make_pair("var a = 20; var b = 30;\n"
1773 "return (function() { return a + b; })();",
1774 handle(Smi::FromInt(50), isolate)),
1775 std::make_pair("'use strict'; let a = 1;\n"
1776 "{ let b = 2; return (function() { return a + b; })(); }",
1777 handle(Smi::FromInt(3), isolate)),
1778 std::make_pair("'use strict'; let a = 10;\n"
1779 "{ let b = 20; var c = function() { [a, b] };\n"
1780 " return a + b; }",
1781 handle(Smi::FromInt(30), isolate)),
1782 std::make_pair("'use strict';" + unique_vars.str() +
1783 "eval(); var b = 100; return b;",
1784 handle(Smi::FromInt(100), isolate)),
1785 };
1786
1787 for (size_t i = 0; i < arraysize(context_vars); i++) {
1788 std::string source(
1789 InterpreterTester::SourceForBody(context_vars[i].first.c_str()));
1790 InterpreterTester tester(handles.main_isolate(), source.c_str());
1791 auto callable = tester.GetCallable<>();
1792
1793 Handle<i::Object> return_value = callable().ToHandleChecked();
1794 CHECK(return_value->SameValue(*context_vars[i].second));
1795 }
1796}
1797
1798
1799TEST(InterpreterContextParameters) {
1800 HandleAndZoneScope handles;
1801 i::Isolate* isolate = handles.main_isolate();
1802
1803 std::pair<const char*, Handle<Object>> context_params[] = {
1804 std::make_pair("return (function() { return arg1; })();",
1805 handle(Smi::FromInt(1), isolate)),
1806 std::make_pair("(function() { arg1 = 4; })(); return arg1;",
1807 handle(Smi::FromInt(4), isolate)),
1808 std::make_pair("(function() { arg3 = arg2 - arg1; })(); return arg3;",
1809 handle(Smi::FromInt(1), isolate)),
1810 };
1811
1812 for (size_t i = 0; i < arraysize(context_params); i++) {
1813 std::string source = "function " + InterpreterTester::function_name() +
1814 "(arg1, arg2, arg3) {" + context_params[i].first + "}";
1815 InterpreterTester tester(handles.main_isolate(), source.c_str());
1816 auto callable =
1817 tester.GetCallable<Handle<Object>, Handle<Object>, Handle<Object>>();
1818
1819 Handle<Object> a1 = handle(Smi::FromInt(1), isolate);
1820 Handle<Object> a2 = handle(Smi::FromInt(2), isolate);
1821 Handle<Object> a3 = handle(Smi::FromInt(3), isolate);
1822 Handle<i::Object> return_value = callable(a1, a2, a3).ToHandleChecked();
1823 CHECK(return_value->SameValue(*context_params[i].second));
1824 }
1825}
1826
1827
1828TEST(InterpreterOuterContextVariables) {
1829 HandleAndZoneScope handles;
1830 i::Isolate* isolate = handles.main_isolate();
1831
1832 std::pair<const char*, Handle<Object>> context_vars[] = {
1833 std::make_pair("return outerVar * innerArg;",
1834 handle(Smi::FromInt(200), isolate)),
1835 std::make_pair("outerVar = innerArg; return outerVar",
1836 handle(Smi::FromInt(20), isolate)),
1837 };
1838
1839 std::string header(
1840 "function Outer() {"
1841 " var outerVar = 10;"
1842 " function Inner(innerArg) {"
1843 " this.innerFunc = function() { ");
1844 std::string footer(
1845 " }}"
1846 " this.getInnerFunc = function() { return new Inner(20).innerFunc; }"
1847 "}"
1848 "var f = new Outer().getInnerFunc();");
1849
1850 for (size_t i = 0; i < arraysize(context_vars); i++) {
1851 std::string source = header + context_vars[i].first + footer;
1852 InterpreterTester tester(handles.main_isolate(), source.c_str(), "*");
1853 auto callable = tester.GetCallable<>();
1854
1855 Handle<i::Object> return_value = callable().ToHandleChecked();
1856 CHECK(return_value->SameValue(*context_vars[i].second));
1857 }
1858}
1859
1860
1861TEST(InterpreterComma) {
1862 HandleAndZoneScope handles;
1863 i::Isolate* isolate = handles.main_isolate();
1864 i::Factory* factory = isolate->factory();
1865
1866 std::pair<const char*, Handle<Object>> literals[] = {
1867 std::make_pair("var a; return 0, a;\n", factory->undefined_value()),
1868 std::make_pair("return 'a', 2.2, 3;\n",
1869 handle(Smi::FromInt(3), isolate)),
1870 std::make_pair("return 'a', 'b', 'c';\n",
1871 factory->NewStringFromStaticChars("c")),
1872 std::make_pair("return 3.2, 2.3, 4.5;\n", factory->NewNumber(4.5)),
1873 std::make_pair("var a = 10; return b = a, b = b+1;\n",
1874 handle(Smi::FromInt(11), isolate)),
1875 std::make_pair("var a = 10; return b = a, b = b+1, b + 10;\n",
1876 handle(Smi::FromInt(21), isolate))};
1877
1878 for (size_t i = 0; i < arraysize(literals); i++) {
1879 std::string source(InterpreterTester::SourceForBody(literals[i].first));
1880 InterpreterTester tester(handles.main_isolate(), source.c_str());
1881 auto callable = tester.GetCallable<>();
1882
1883 Handle<i::Object> return_value = callable().ToHandleChecked();
1884 CHECK(return_value->SameValue(*literals[i].second));
1885 }
1886}
1887
1888
1889TEST(InterpreterLogicalOr) {
1890 HandleAndZoneScope handles;
1891 i::Isolate* isolate = handles.main_isolate();
1892 i::Factory* factory = isolate->factory();
1893
1894 std::pair<const char*, Handle<Object>> literals[] = {
1895 std::make_pair("var a, b; return a || b;\n", factory->undefined_value()),
1896 std::make_pair("var a, b = 10; return a || b;\n",
1897 handle(Smi::FromInt(10), isolate)),
1898 std::make_pair("var a = '0', b = 10; return a || b;\n",
1899 factory->NewStringFromStaticChars("0")),
1900 std::make_pair("return 0 || 3.2;\n", factory->NewNumber(3.2)),
1901 std::make_pair("return 'a' || 0;\n",
1902 factory->NewStringFromStaticChars("a")),
1903 std::make_pair("var a = '0', b = 10; return (a == 0) || b;\n",
1904 factory->true_value())};
1905
1906 for (size_t i = 0; i < arraysize(literals); i++) {
1907 std::string source(InterpreterTester::SourceForBody(literals[i].first));
1908 InterpreterTester tester(handles.main_isolate(), source.c_str());
1909 auto callable = tester.GetCallable<>();
1910
1911 Handle<i::Object> return_value = callable().ToHandleChecked();
1912 CHECK(return_value->SameValue(*literals[i].second));
1913 }
1914}
1915
1916
1917TEST(InterpreterLogicalAnd) {
1918 HandleAndZoneScope handles;
1919 i::Isolate* isolate = handles.main_isolate();
1920 i::Factory* factory = isolate->factory();
1921
1922 std::pair<const char*, Handle<Object>> literals[] = {
1923 std::make_pair("var a, b = 10; return a && b;\n",
1924 factory->undefined_value()),
1925 std::make_pair("var a = 0, b = 10; return a && b / a;\n",
1926 handle(Smi::FromInt(0), isolate)),
1927 std::make_pair("var a = '0', b = 10; return a && b;\n",
1928 handle(Smi::FromInt(10), isolate)),
1929 std::make_pair("return 0.0 && 3.2;\n", handle(Smi::FromInt(0), isolate)),
1930 std::make_pair("return 'a' && 'b';\n",
1931 factory->NewStringFromStaticChars("b")),
1932 std::make_pair("return 'a' && 0 || 'b', 'c';\n",
1933 factory->NewStringFromStaticChars("c")),
1934 std::make_pair("var x = 1, y = 3; return x && 0 + 1 || y;\n",
1935 handle(Smi::FromInt(1), isolate)),
1936 std::make_pair("var x = 1, y = 3; return (x == 1) && (3 == 3) || y;\n",
1937 factory->true_value())};
1938
1939 for (size_t i = 0; i < arraysize(literals); i++) {
1940 std::string source(InterpreterTester::SourceForBody(literals[i].first));
1941 InterpreterTester tester(handles.main_isolate(), source.c_str());
1942 auto callable = tester.GetCallable<>();
1943
1944 Handle<i::Object> return_value = callable().ToHandleChecked();
1945 CHECK(return_value->SameValue(*literals[i].second));
1946 }
1947}
1948
1949
1950TEST(InterpreterTryCatch) {
1951 HandleAndZoneScope handles;
Ben Murdoch097c5b22016-05-18 11:27:45 +01001952 i::Isolate* isolate = handles.main_isolate();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001953
Ben Murdoch097c5b22016-05-18 11:27:45 +01001954 std::pair<const char*, Handle<Object>> catches[] = {
1955 std::make_pair("var a = 1; try { a = 2 } catch(e) { a = 3 }; return a;",
1956 handle(Smi::FromInt(2), isolate)),
1957 std::make_pair("var a; try { undef.x } catch(e) { a = 2 }; return a;",
1958 handle(Smi::FromInt(2), isolate)),
1959 std::make_pair("var a; try { throw 1 } catch(e) { a = e + 2 }; return a;",
1960 handle(Smi::FromInt(3), isolate)),
1961 std::make_pair("var a; try { throw 1 } catch(e) { a = e + 2 };"
1962 " try { throw a } catch(e) { a = e + 3 }; return a;",
1963 handle(Smi::FromInt(6), isolate)),
1964 };
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001965
Ben Murdoch097c5b22016-05-18 11:27:45 +01001966 for (size_t i = 0; i < arraysize(catches); i++) {
1967 std::string source(InterpreterTester::SourceForBody(catches[i].first));
1968 InterpreterTester tester(handles.main_isolate(), source.c_str());
1969 auto callable = tester.GetCallable<>();
1970
1971 Handle<i::Object> return_value = callable().ToHandleChecked();
1972 CHECK(return_value->SameValue(*catches[i].second));
1973 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001974}
1975
1976
1977TEST(InterpreterTryFinally) {
1978 HandleAndZoneScope handles;
Ben Murdoch097c5b22016-05-18 11:27:45 +01001979 i::Isolate* isolate = handles.main_isolate();
1980 i::Factory* factory = isolate->factory();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001981
Ben Murdoch097c5b22016-05-18 11:27:45 +01001982 std::pair<const char*, Handle<Object>> finallies[] = {
1983 std::make_pair(
1984 "var a = 1; try { a = a + 1; } finally { a = a + 2; }; return a;",
1985 factory->NewStringFromStaticChars("R4")),
1986 std::make_pair(
1987 "var a = 1; try { a = 2; return 23; } finally { a = 3 }; return a;",
1988 factory->NewStringFromStaticChars("R23")),
1989 std::make_pair(
1990 "var a = 1; try { a = 2; throw 23; } finally { a = 3 }; return a;",
1991 factory->NewStringFromStaticChars("E23")),
1992 std::make_pair(
1993 "var a = 1; try { a = 2; throw 23; } finally { return a; };",
1994 factory->NewStringFromStaticChars("R2")),
1995 std::make_pair(
1996 "var a = 1; try { a = 2; throw 23; } finally { throw 42; };",
1997 factory->NewStringFromStaticChars("E42")),
1998 std::make_pair("var a = 1; for (var i = 10; i < 20; i += 5) {"
1999 " try { a = 2; break; } finally { a = 3; }"
2000 "} return a + i;",
2001 factory->NewStringFromStaticChars("R13")),
2002 std::make_pair("var a = 1; for (var i = 10; i < 20; i += 5) {"
2003 " try { a = 2; continue; } finally { a = 3; }"
2004 "} return a + i;",
2005 factory->NewStringFromStaticChars("R23")),
2006 std::make_pair("var a = 1; try { a = 2;"
2007 " try { a = 3; throw 23; } finally { a = 4; }"
2008 "} catch(e) { a = a + e; } return a;",
2009 factory->NewStringFromStaticChars("R27")),
2010 };
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002011
Ben Murdoch097c5b22016-05-18 11:27:45 +01002012 const char* try_wrapper =
2013 "(function() { try { return 'R' + f() } catch(e) { return 'E' + e }})()";
2014
2015 for (size_t i = 0; i < arraysize(finallies); i++) {
2016 std::string source(InterpreterTester::SourceForBody(finallies[i].first));
2017 InterpreterTester tester(handles.main_isolate(), source.c_str());
2018 tester.GetCallable<>();
2019 Handle<Object> wrapped = v8::Utils::OpenHandle(*CompileRun(try_wrapper));
2020 CHECK(wrapped->SameValue(*finallies[i].second));
2021 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002022}
2023
2024
2025TEST(InterpreterThrow) {
2026 HandleAndZoneScope handles;
2027 i::Isolate* isolate = handles.main_isolate();
2028 i::Factory* factory = isolate->factory();
2029
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002030 std::pair<const char*, Handle<Object>> throws[] = {
2031 std::make_pair("throw undefined;\n",
2032 factory->undefined_value()),
2033 std::make_pair("throw 1;\n",
2034 handle(Smi::FromInt(1), isolate)),
2035 std::make_pair("throw 'Error';\n",
2036 factory->NewStringFromStaticChars("Error")),
2037 std::make_pair("var a = true; if (a) { throw 'Error'; }\n",
2038 factory->NewStringFromStaticChars("Error")),
2039 std::make_pair("var a = false; if (a) { throw 'Error'; }\n",
2040 factory->undefined_value()),
2041 std::make_pair("throw 'Error1'; throw 'Error2'\n",
2042 factory->NewStringFromStaticChars("Error1")),
2043 };
2044
2045 const char* try_wrapper =
2046 "(function() { try { f(); } catch(e) { return e; }})()";
2047
2048 for (size_t i = 0; i < arraysize(throws); i++) {
2049 std::string source(InterpreterTester::SourceForBody(throws[i].first));
2050 InterpreterTester tester(handles.main_isolate(), source.c_str());
2051 tester.GetCallable<>();
2052 Handle<Object> thrown_obj = v8::Utils::OpenHandle(*CompileRun(try_wrapper));
2053 CHECK(thrown_obj->SameValue(*throws[i].second));
2054 }
2055}
2056
2057
2058TEST(InterpreterCountOperators) {
2059 HandleAndZoneScope handles;
2060 i::Isolate* isolate = handles.main_isolate();
2061 i::Factory* factory = isolate->factory();
2062
2063 std::pair<const char*, Handle<Object>> count_ops[] = {
2064 std::make_pair("var a = 1; return ++a;",
2065 handle(Smi::FromInt(2), isolate)),
2066 std::make_pair("var a = 1; return a++;",
2067 handle(Smi::FromInt(1), isolate)),
2068 std::make_pair("var a = 5; return --a;",
2069 handle(Smi::FromInt(4), isolate)),
2070 std::make_pair("var a = 5; return a--;",
2071 handle(Smi::FromInt(5), isolate)),
2072 std::make_pair("var a = 5.2; return --a;",
2073 factory->NewHeapNumber(4.2)),
2074 std::make_pair("var a = 'string'; return ++a;",
2075 factory->nan_value()),
2076 std::make_pair("var a = 'string'; return a--;",
2077 factory->nan_value()),
2078 std::make_pair("var a = true; return ++a;",
2079 handle(Smi::FromInt(2), isolate)),
2080 std::make_pair("var a = false; return a--;",
2081 handle(Smi::FromInt(0), isolate)),
2082 std::make_pair("var a = { val: 11 }; return ++a.val;",
2083 handle(Smi::FromInt(12), isolate)),
2084 std::make_pair("var a = { val: 11 }; return a.val--;",
2085 handle(Smi::FromInt(11), isolate)),
2086 std::make_pair("var a = { val: 11 }; return ++a.val;",
2087 handle(Smi::FromInt(12), isolate)),
2088 std::make_pair("var name = 'val'; var a = { val: 22 }; return --a[name];",
2089 handle(Smi::FromInt(21), isolate)),
2090 std::make_pair("var name = 'val'; var a = { val: 22 }; return a[name]++;",
2091 handle(Smi::FromInt(22), isolate)),
2092 std::make_pair("var a = 1; (function() { a = 2 })(); return ++a;",
2093 handle(Smi::FromInt(3), isolate)),
2094 std::make_pair("var a = 1; (function() { a = 2 })(); return a--;",
2095 handle(Smi::FromInt(2), isolate)),
2096 std::make_pair("var i = 5; while(i--) {}; return i;",
2097 handle(Smi::FromInt(-1), isolate)),
2098 std::make_pair("var i = 1; if(i--) { return 1; } else { return 2; };",
2099 handle(Smi::FromInt(1), isolate)),
2100 std::make_pair("var i = -2; do {} while(i++) {}; return i;",
2101 handle(Smi::FromInt(1), isolate)),
2102 std::make_pair("var i = -1; for(; i++; ) {}; return i",
2103 handle(Smi::FromInt(1), isolate)),
2104 std::make_pair("var i = 20; switch(i++) {\n"
2105 " case 20: return 1;\n"
2106 " default: return 2;\n"
2107 "}",
2108 handle(Smi::FromInt(1), isolate)),
2109 };
2110
2111 for (size_t i = 0; i < arraysize(count_ops); i++) {
2112 std::string source(InterpreterTester::SourceForBody(count_ops[i].first));
2113 InterpreterTester tester(handles.main_isolate(), source.c_str());
2114 auto callable = tester.GetCallable<>();
2115
2116 Handle<i::Object> return_value = callable().ToHandleChecked();
2117 CHECK(return_value->SameValue(*count_ops[i].second));
2118 }
2119}
2120
2121
2122TEST(InterpreterGlobalCountOperators) {
2123 HandleAndZoneScope handles;
2124 i::Isolate* isolate = handles.main_isolate();
2125
2126 std::pair<const char*, Handle<Object>> count_ops[] = {
2127 std::make_pair("var global = 100;function f(){ return ++global; }",
2128 handle(Smi::FromInt(101), isolate)),
2129 std::make_pair("var global = 100; function f(){ return --global; }",
2130 handle(Smi::FromInt(99), isolate)),
2131 std::make_pair("var global = 100; function f(){ return global++; }",
2132 handle(Smi::FromInt(100), isolate)),
2133 std::make_pair("unallocated = 200; function f(){ return ++unallocated; }",
2134 handle(Smi::FromInt(201), isolate)),
2135 std::make_pair("unallocated = 200; function f(){ return --unallocated; }",
2136 handle(Smi::FromInt(199), isolate)),
2137 std::make_pair("unallocated = 200; function f(){ return unallocated++; }",
2138 handle(Smi::FromInt(200), isolate)),
2139 };
2140
2141 for (size_t i = 0; i < arraysize(count_ops); i++) {
2142 InterpreterTester tester(handles.main_isolate(), count_ops[i].first);
2143 auto callable = tester.GetCallable<>();
2144
2145 Handle<i::Object> return_value = callable().ToHandleChecked();
2146 CHECK(return_value->SameValue(*count_ops[i].second));
2147 }
2148}
2149
2150
2151TEST(InterpreterCompoundExpressions) {
2152 HandleAndZoneScope handles;
2153 i::Isolate* isolate = handles.main_isolate();
2154 i::Factory* factory = isolate->factory();
2155
2156 std::pair<const char*, Handle<Object>> compound_expr[] = {
2157 std::make_pair("var a = 1; a += 2; return a;",
2158 Handle<Object>(Smi::FromInt(3), isolate)),
2159 std::make_pair("var a = 10; a /= 2; return a;",
2160 Handle<Object>(Smi::FromInt(5), isolate)),
2161 std::make_pair("var a = 'test'; a += 'ing'; return a;",
2162 factory->NewStringFromStaticChars("testing")),
2163 std::make_pair("var a = { val: 2 }; a.val *= 2; return a.val;",
2164 Handle<Object>(Smi::FromInt(4), isolate)),
2165 std::make_pair("var a = 1; (function f() { a = 2; })(); a += 24;"
2166 "return a;",
2167 Handle<Object>(Smi::FromInt(26), isolate)),
2168 };
2169
2170 for (size_t i = 0; i < arraysize(compound_expr); i++) {
2171 std::string source(
2172 InterpreterTester::SourceForBody(compound_expr[i].first));
2173 InterpreterTester tester(handles.main_isolate(), source.c_str());
2174 auto callable = tester.GetCallable<>();
2175
2176 Handle<i::Object> return_value = callable().ToHandleChecked();
2177 CHECK(return_value->SameValue(*compound_expr[i].second));
2178 }
2179}
2180
2181
2182TEST(InterpreterGlobalCompoundExpressions) {
2183 HandleAndZoneScope handles;
2184 i::Isolate* isolate = handles.main_isolate();
2185
2186 std::pair<const char*, Handle<Object>> compound_expr[2] = {
2187 std::make_pair("var global = 100;"
2188 "function f() { global += 20; return global; }",
2189 Handle<Object>(Smi::FromInt(120), isolate)),
2190 std::make_pair("unallocated = 100;"
2191 "function f() { unallocated -= 20; return unallocated; }",
2192 Handle<Object>(Smi::FromInt(80), isolate)),
2193 };
2194
2195 for (size_t i = 0; i < arraysize(compound_expr); i++) {
2196 InterpreterTester tester(handles.main_isolate(), compound_expr[i].first);
2197 auto callable = tester.GetCallable<>();
2198
2199 Handle<i::Object> return_value = callable().ToHandleChecked();
2200 CHECK(return_value->SameValue(*compound_expr[i].second));
2201 }
2202}
2203
2204
2205TEST(InterpreterCreateArguments) {
2206 HandleAndZoneScope handles;
2207 i::Isolate* isolate = handles.main_isolate();
2208 i::Factory* factory = isolate->factory();
2209
2210 std::pair<const char*, int> create_args[] = {
2211 std::make_pair("function f() { return arguments[0]; }", 0),
2212 std::make_pair("function f(a) { return arguments[0]; }", 0),
2213 std::make_pair("function f() { return arguments[2]; }", 2),
2214 std::make_pair("function f(a) { return arguments[2]; }", 2),
2215 std::make_pair("function f(a, b, c, d) { return arguments[2]; }", 2),
2216 std::make_pair("function f(a) {"
2217 "'use strict'; return arguments[0]; }",
2218 0),
2219 std::make_pair("function f(a, b, c, d) {"
2220 "'use strict'; return arguments[2]; }",
2221 2),
2222 // Check arguments are mapped in sloppy mode and unmapped in strict.
2223 std::make_pair("function f(a, b, c, d) {"
2224 " c = b; return arguments[2]; }",
2225 1),
2226 std::make_pair("function f(a, b, c, d) {"
2227 " 'use strict'; c = b; return arguments[2]; }",
2228 2),
Ben Murdoch097c5b22016-05-18 11:27:45 +01002229 // check rest parameters
2230 std::make_pair("function f(...restArray) { return restArray[0]; }", 0),
2231 std::make_pair("function f(a, ...restArray) { return restArray[0]; }", 1),
2232 std::make_pair("function f(a, ...restArray) { return arguments[0]; }", 0),
2233 std::make_pair("function f(a, ...restArray) { return arguments[1]; }", 1),
2234 std::make_pair("function f(a, ...restArray) { return restArray[1]; }", 2),
2235 std::make_pair("function f(a, ...arguments) { return arguments[0]; }", 1),
2236 std::make_pair("function f(a, b, ...restArray) { return restArray[0]; }",
2237 2),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002238 };
2239
2240 // Test passing no arguments.
2241 for (size_t i = 0; i < arraysize(create_args); i++) {
2242 InterpreterTester tester(handles.main_isolate(), create_args[i].first);
2243 auto callable = tester.GetCallable<>();
2244 Handle<Object> return_val = callable().ToHandleChecked();
2245 CHECK(return_val.is_identical_to(factory->undefined_value()));
2246 }
2247
2248 // Test passing one argument.
2249 for (size_t i = 0; i < arraysize(create_args); i++) {
2250 InterpreterTester tester(handles.main_isolate(), create_args[i].first);
2251 auto callable = tester.GetCallable<Handle<Object>>();
2252 Handle<Object> return_val =
2253 callable(handle(Smi::FromInt(40), isolate)).ToHandleChecked();
2254 if (create_args[i].second == 0) {
2255 CHECK_EQ(Smi::cast(*return_val), Smi::FromInt(40));
2256 } else {
2257 CHECK(return_val.is_identical_to(factory->undefined_value()));
2258 }
2259 }
2260
2261 // Test passing three argument.
2262 for (size_t i = 0; i < arraysize(create_args); i++) {
2263 Handle<Object> args[3] = {
2264 handle(Smi::FromInt(40), isolate),
2265 handle(Smi::FromInt(60), isolate),
2266 handle(Smi::FromInt(80), isolate),
2267 };
2268
2269 InterpreterTester tester(handles.main_isolate(), create_args[i].first);
2270 auto callable =
2271 tester.GetCallable<Handle<Object>, Handle<Object>, Handle<Object>>();
2272 Handle<Object> return_val =
2273 callable(args[0], args[1], args[2]).ToHandleChecked();
2274 CHECK(return_val->SameValue(*args[create_args[i].second]));
2275 }
2276}
2277
2278
2279TEST(InterpreterConditional) {
2280 HandleAndZoneScope handles;
2281 i::Isolate* isolate = handles.main_isolate();
2282
2283 std::pair<const char*, Handle<Object>> conditional[] = {
2284 std::make_pair("return true ? 2 : 3;",
2285 handle(Smi::FromInt(2), isolate)),
2286 std::make_pair("return false ? 2 : 3;",
2287 handle(Smi::FromInt(3), isolate)),
2288 std::make_pair("var a = 1; return a ? 20 : 30;",
2289 handle(Smi::FromInt(20), isolate)),
2290 std::make_pair("var a = 1; return a ? 20 : 30;",
2291 handle(Smi::FromInt(20), isolate)),
2292 std::make_pair("var a = 'string'; return a ? 20 : 30;",
2293 handle(Smi::FromInt(20), isolate)),
2294 std::make_pair("var a = undefined; return a ? 20 : 30;",
2295 handle(Smi::FromInt(30), isolate)),
2296 std::make_pair("return 1 ? 2 ? 3 : 4 : 5;",
2297 handle(Smi::FromInt(3), isolate)),
2298 std::make_pair("return 0 ? 2 ? 3 : 4 : 5;",
2299 handle(Smi::FromInt(5), isolate)),
2300 };
2301
2302 for (size_t i = 0; i < arraysize(conditional); i++) {
2303 std::string source(InterpreterTester::SourceForBody(conditional[i].first));
2304 InterpreterTester tester(handles.main_isolate(), source.c_str());
2305 auto callable = tester.GetCallable<>();
2306
2307 Handle<i::Object> return_value = callable().ToHandleChecked();
2308 CHECK(return_value->SameValue(*conditional[i].second));
2309 }
2310}
2311
2312
2313TEST(InterpreterDelete) {
2314 HandleAndZoneScope handles;
2315 i::Isolate* isolate = handles.main_isolate();
2316 i::Factory* factory = isolate->factory();
2317
2318 // Tests for delete for local variables that work both in strict
2319 // and sloppy modes
2320 std::pair<const char*, Handle<Object>> test_delete[] = {
2321 std::make_pair(
2322 "var a = { x:10, y:'abc', z:30.2}; delete a.x; return a.x;\n",
2323 factory->undefined_value()),
2324 std::make_pair(
2325 "var b = { x:10, y:'abc', z:30.2}; delete b.x; return b.y;\n",
2326 factory->NewStringFromStaticChars("abc")),
2327 std::make_pair("var c = { x:10, y:'abc', z:30.2}; var d = c; delete d.x; "
2328 "return c.x;\n",
2329 factory->undefined_value()),
2330 std::make_pair("var e = { x:10, y:'abc', z:30.2}; var g = e; delete g.x; "
2331 "return e.y;\n",
2332 factory->NewStringFromStaticChars("abc")),
2333 std::make_pair("var a = { x:10, y:'abc', z:30.2};\n"
2334 "var b = a;"
2335 "delete b.x;"
2336 "return b.x;\n",
2337 factory->undefined_value()),
2338 std::make_pair("var a = {1:10};\n"
2339 "(function f1() {return a;});"
2340 "return delete a[1];",
2341 factory->ToBoolean(true)),
2342 std::make_pair("return delete this;", factory->ToBoolean(true)),
2343 std::make_pair("return delete 'test';", factory->ToBoolean(true))};
2344
2345 // Test delete in sloppy mode
2346 for (size_t i = 0; i < arraysize(test_delete); i++) {
2347 std::string source(InterpreterTester::SourceForBody(test_delete[i].first));
2348 InterpreterTester tester(handles.main_isolate(), source.c_str());
2349 auto callable = tester.GetCallable<>();
2350
2351 Handle<i::Object> return_value = callable().ToHandleChecked();
2352 CHECK(return_value->SameValue(*test_delete[i].second));
2353 }
2354
2355 // Test delete in strict mode
2356 for (size_t i = 0; i < arraysize(test_delete); i++) {
2357 std::string strict_test =
2358 "'use strict'; " + std::string(test_delete[i].first);
2359 std::string source(InterpreterTester::SourceForBody(strict_test.c_str()));
2360 InterpreterTester tester(handles.main_isolate(), source.c_str());
2361 auto callable = tester.GetCallable<>();
2362
2363 Handle<i::Object> return_value = callable().ToHandleChecked();
2364 CHECK(return_value->SameValue(*test_delete[i].second));
2365 }
2366}
2367
2368
2369TEST(InterpreterDeleteSloppyUnqualifiedIdentifier) {
2370 HandleAndZoneScope handles;
2371 i::Isolate* isolate = handles.main_isolate();
2372 i::Factory* factory = isolate->factory();
2373
2374 // These tests generate a syntax error for strict mode. We don't
2375 // test for it here.
2376 std::pair<const char*, Handle<Object>> test_delete[] = {
2377 std::make_pair("var sloppy_a = { x:10, y:'abc'};\n"
2378 "var sloppy_b = delete sloppy_a;\n"
2379 "if (delete sloppy_a) {\n"
2380 " return undefined;\n"
2381 "} else {\n"
2382 " return sloppy_a.x;\n"
2383 "}\n",
2384 Handle<Object>(Smi::FromInt(10), isolate)),
2385 // TODO(mythria) When try-catch is implemented change the tests to check
2386 // if delete actually deletes
2387 std::make_pair("sloppy_a = { x:10, y:'abc'};\n"
2388 "var sloppy_b = delete sloppy_a;\n"
2389 // "try{return a.x;} catch(e) {return b;}\n"
2390 "return sloppy_b;",
2391 factory->ToBoolean(true)),
2392 std::make_pair("sloppy_a = { x:10, y:'abc'};\n"
2393 "var sloppy_b = delete sloppy_c;\n"
2394 "return sloppy_b;",
2395 factory->ToBoolean(true))};
2396
2397 for (size_t i = 0; i < arraysize(test_delete); i++) {
2398 std::string source(InterpreterTester::SourceForBody(test_delete[i].first));
2399 InterpreterTester tester(handles.main_isolate(), source.c_str());
2400 auto callable = tester.GetCallable<>();
2401
2402 Handle<i::Object> return_value = callable().ToHandleChecked();
2403 CHECK(return_value->SameValue(*test_delete[i].second));
2404 }
2405}
2406
2407
2408TEST(InterpreterGlobalDelete) {
2409 HandleAndZoneScope handles;
2410 i::Isolate* isolate = handles.main_isolate();
2411 i::Factory* factory = isolate->factory();
2412
2413 std::pair<const char*, Handle<Object>> test_global_delete[] = {
2414 std::make_pair("var a = { x:10, y:'abc', z:30.2 };\n"
2415 "function f() {\n"
2416 " delete a.x;\n"
2417 " return a.x;\n"
2418 "}\n"
2419 "f();\n",
2420 factory->undefined_value()),
2421 std::make_pair("var b = {1:10, 2:'abc', 3:30.2 };\n"
2422 "function f() {\n"
2423 " delete b[2];\n"
2424 " return b[1];\n"
2425 " }\n"
2426 "f();\n",
2427 Handle<Object>(Smi::FromInt(10), isolate)),
2428 std::make_pair("var c = { x:10, y:'abc', z:30.2 };\n"
2429 "function f() {\n"
2430 " var d = c;\n"
2431 " delete d.y;\n"
2432 " return d.x;\n"
2433 "}\n"
2434 "f();\n",
2435 Handle<Object>(Smi::FromInt(10), isolate)),
2436 std::make_pair("e = { x:10, y:'abc' };\n"
2437 "function f() {\n"
2438 " return delete e;\n"
2439 "}\n"
2440 "f();\n",
2441 factory->ToBoolean(true)),
2442 std::make_pair("var g = { x:10, y:'abc' };\n"
2443 "function f() {\n"
2444 " return delete g;\n"
2445 "}\n"
2446 "f();\n",
2447 factory->ToBoolean(false)),
2448 std::make_pair("function f() {\n"
2449 " var obj = {h:10, f1() {return delete this;}};\n"
2450 " return obj.f1();\n"
2451 "}\n"
2452 "f();",
2453 factory->ToBoolean(true)),
2454 std::make_pair("function f() {\n"
2455 " var obj = {h:10,\n"
2456 " f1() {\n"
2457 " 'use strict';\n"
2458 " return delete this.h;}};\n"
2459 " return obj.f1();\n"
2460 "}\n"
2461 "f();",
2462 factory->ToBoolean(true))};
2463
2464 for (size_t i = 0; i < arraysize(test_global_delete); i++) {
2465 InterpreterTester tester(handles.main_isolate(),
2466 test_global_delete[i].first);
2467 auto callable = tester.GetCallable<>();
2468
2469 Handle<i::Object> return_value = callable().ToHandleChecked();
2470 CHECK(return_value->SameValue(*test_global_delete[i].second));
2471 }
2472}
2473
2474
2475TEST(InterpreterBasicLoops) {
2476 HandleAndZoneScope handles;
2477 i::Isolate* isolate = handles.main_isolate();
2478 i::Factory* factory = isolate->factory();
2479
2480 std::pair<const char*, Handle<Object>> loops[] = {
2481 std::make_pair("var a = 10; var b = 1;\n"
2482 "while (a) {\n"
2483 " b = b * 2;\n"
2484 " a = a - 1;\n"
2485 "};\n"
2486 "return b;\n",
2487 factory->NewHeapNumber(1024)),
2488 std::make_pair("var a = 1; var b = 1;\n"
2489 "do {\n"
2490 " b = b * 2;\n"
2491 " --a;\n"
2492 "} while(a);\n"
2493 "return b;\n",
2494 handle(Smi::FromInt(2), isolate)),
2495 std::make_pair("var b = 1;\n"
2496 "for ( var a = 10; a; a--) {\n"
2497 " b *= 2;\n"
2498 "}\n"
2499 "return b;",
2500 factory->NewHeapNumber(1024)),
2501 std::make_pair("var a = 10; var b = 1;\n"
2502 "while (a > 0) {\n"
2503 " b = b * 2;\n"
2504 " a = a - 1;\n"
2505 "};\n"
2506 "return b;\n",
2507 factory->NewHeapNumber(1024)),
2508 std::make_pair("var a = 1; var b = 1;\n"
2509 "do {\n"
2510 " b = b * 2;\n"
2511 " --a;\n"
2512 "} while(a);\n"
2513 "return b;\n",
2514 handle(Smi::FromInt(2), isolate)),
2515 std::make_pair("var b = 1;\n"
2516 "for ( var a = 10; a > 0; a--) {\n"
2517 " b *= 2;\n"
2518 "}\n"
2519 "return b;",
2520 factory->NewHeapNumber(1024)),
2521 std::make_pair("var a = 10; var b = 1;\n"
2522 "while (false) {\n"
2523 " b = b * 2;\n"
2524 " a = a - 1;\n"
2525 "}\n"
2526 "return b;\n",
2527 Handle<Object>(Smi::FromInt(1), isolate)),
2528 std::make_pair("var a = 10; var b = 1;\n"
2529 "while (true) {\n"
2530 " b = b * 2;\n"
2531 " a = a - 1;\n"
2532 " if (a == 0) break;"
2533 " continue;"
2534 "}\n"
2535 "return b;\n",
2536 factory->NewHeapNumber(1024)),
2537 std::make_pair("var a = 10; var b = 1;\n"
2538 "do {\n"
2539 " b = b * 2;\n"
2540 " a = a - 1;\n"
2541 " if (a == 0) break;"
2542 "} while(true);\n"
2543 "return b;\n",
2544 factory->NewHeapNumber(1024)),
2545 std::make_pair("var a = 10; var b = 1;\n"
2546 "do {\n"
2547 " b = b * 2;\n"
2548 " a = a - 1;\n"
2549 " if (a == 0) break;"
2550 "} while(false);\n"
2551 "return b;\n",
2552 Handle<Object>(Smi::FromInt(2), isolate)),
2553 std::make_pair("var a = 10; var b = 1;\n"
2554 "for ( a = 1, b = 30; false; ) {\n"
2555 " b = b * 2;\n"
2556 "}\n"
2557 "return b;\n",
2558 Handle<Object>(Smi::FromInt(30), isolate))};
2559
2560 for (size_t i = 0; i < arraysize(loops); i++) {
2561 std::string source(InterpreterTester::SourceForBody(loops[i].first));
2562 InterpreterTester tester(handles.main_isolate(), source.c_str());
2563 auto callable = tester.GetCallable<>();
2564
2565 Handle<i::Object> return_value = callable().ToHandleChecked();
2566 CHECK(return_value->SameValue(*loops[i].second));
2567 }
2568}
2569
2570
2571TEST(InterpreterForIn) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002572 std::pair<const char*, int> for_in_samples[] = {
Ben Murdoch097c5b22016-05-18 11:27:45 +01002573 {"var r = -1;\n"
2574 "for (var a in null) { r = a; }\n"
2575 "return r;\n",
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002576 -1},
Ben Murdoch097c5b22016-05-18 11:27:45 +01002577 {"var r = -1;\n"
2578 "for (var a in undefined) { r = a; }\n"
2579 "return r;\n",
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002580 -1},
Ben Murdoch097c5b22016-05-18 11:27:45 +01002581 {"var r = 0;\n"
2582 "for (var a in [0,6,7,9]) { r = r + (1 << a); }\n"
2583 "return r;\n",
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002584 0xf},
Ben Murdoch097c5b22016-05-18 11:27:45 +01002585 {"var r = 0;\n"
2586 "for (var a in [0,6,7,9]) { r = r + (1 << a); }\n"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002587 "var r = 0;\n"
Ben Murdoch097c5b22016-05-18 11:27:45 +01002588 "for (var a in [0,6,7,9]) { r = r + (1 << a); }\n"
2589 "return r;\n",
2590 0xf},
2591 {"var r = 0;\n"
2592 "for (var a in 'foobar') { r = r + (1 << a); }\n"
2593 "return r;\n",
2594 0x3f},
2595 {"var r = 0;\n"
2596 "for (var a in {1:0, 10:1, 100:2, 1000:3}) {\n"
2597 " r = r + Number(a);\n"
2598 " }\n"
2599 " return r;\n",
2600 1111},
2601 {"var r = 0;\n"
2602 "var data = {1:0, 10:1, 100:2, 1000:3};\n"
2603 "for (var a in data) {\n"
2604 " if (a == 1) delete data[1];\n"
2605 " r = r + Number(a);\n"
2606 " }\n"
2607 " return r;\n",
2608 1111},
2609 {"var r = 0;\n"
2610 "var data = {1:0, 10:1, 100:2, 1000:3};\n"
2611 "for (var a in data) {\n"
2612 " if (a == 10) delete data[100];\n"
2613 " r = r + Number(a);\n"
2614 " }\n"
2615 " return r;\n",
2616 1011},
2617 {"var r = 0;\n"
2618 "var data = {1:0, 10:1, 100:2, 1000:3};\n"
2619 "for (var a in data) {\n"
2620 " if (a == 10) data[10000] = 4;\n"
2621 " r = r + Number(a);\n"
2622 " }\n"
2623 " return r;\n",
2624 1111},
2625 {"var r = 0;\n"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002626 "var input = 'foobar';\n"
2627 "for (var a in input) {\n"
Ben Murdoch097c5b22016-05-18 11:27:45 +01002628 " if (input[a] == 'b') break;\n"
2629 " r = r + (1 << a);\n"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002630 "}\n"
Ben Murdoch097c5b22016-05-18 11:27:45 +01002631 "return r;\n",
2632 0x7},
2633 {"var r = 0;\n"
2634 "var input = 'foobar';\n"
2635 "for (var a in input) {\n"
2636 " if (input[a] == 'b') continue;\n"
2637 " r = r + (1 << a);\n"
2638 "}\n"
2639 "return r;\n",
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002640 0x37},
Ben Murdoch097c5b22016-05-18 11:27:45 +01002641 {"var r = 0;\n"
2642 "var data = {1:0, 10:1, 100:2, 1000:3};\n"
2643 "for (var a in data) {\n"
2644 " if (a == 10) {\n"
2645 " data[10000] = 4;\n"
2646 " }\n"
2647 " r = r + Number(a);\n"
2648 "}\n"
2649 "return r;\n",
2650 1111},
2651 {"var r = [ 3 ];\n"
2652 "var data = {1:0, 10:1, 100:2, 1000:3};\n"
2653 "for (r[10] in data) {\n"
2654 "}\n"
2655 "return Number(r[10]);\n",
2656 1000},
2657 {"var r = [ 3 ];\n"
2658 "var data = {1:0, 10:1, 100:2, 1000:3};\n"
2659 "for (r['100'] in data) {\n"
2660 "}\n"
2661 "return Number(r['100']);\n",
2662 1000},
2663 {"var obj = {}\n"
2664 "var descObj = new Boolean(false);\n"
2665 "var accessed = 0;\n"
2666 "descObj.enumerable = true;\n"
2667 "Object.defineProperties(obj, { prop:descObj });\n"
2668 "for (var p in obj) {\n"
2669 " if (p === 'prop') { accessed = 1; }\n"
2670 "}\n"
2671 "return accessed;",
2672 1},
2673 {"var appointment = {};\n"
2674 "Object.defineProperty(appointment, 'startTime', {\n"
2675 " value: 1001,\n"
2676 " writable: false,\n"
2677 " enumerable: false,\n"
2678 " configurable: true\n"
2679 "});\n"
2680 "Object.defineProperty(appointment, 'name', {\n"
2681 " value: 'NAME',\n"
2682 " writable: false,\n"
2683 " enumerable: false,\n"
2684 " configurable: true\n"
2685 "});\n"
2686 "var meeting = Object.create(appointment);\n"
2687 "Object.defineProperty(meeting, 'conferenceCall', {\n"
2688 " value: 'In-person meeting',\n"
2689 " writable: false,\n"
2690 " enumerable: false,\n"
2691 " configurable: true\n"
2692 "});\n"
2693 "\n"
2694 "var teamMeeting = Object.create(meeting);\n"
2695 "\n"
2696 "var flags = 0;\n"
2697 "for (var p in teamMeeting) {\n"
2698 " if (p === 'startTime') {\n"
2699 " flags |= 1;\n"
2700 " }\n"
2701 " if (p === 'name') {\n"
2702 " flags |= 2;\n"
2703 " }\n"
2704 " if (p === 'conferenceCall') {\n"
2705 " flags |= 4;\n"
2706 " }\n"
2707 "}\n"
2708 "\n"
2709 "var hasOwnProperty = !teamMeeting.hasOwnProperty('name') &&\n"
2710 " !teamMeeting.hasOwnProperty('startTime') &&\n"
2711 " !teamMeeting.hasOwnProperty('conferenceCall');\n"
2712 "if (!hasOwnProperty) {\n"
2713 " flags |= 8;\n"
2714 "}\n"
2715 "return flags;\n",
2716 0},
2717 {"var data = {x:23, y:34};\n"
2718 " var result = 0;\n"
2719 "var o = {};\n"
2720 "var arr = [o];\n"
2721 "for (arr[0].p in data)\n" // This is to test if value is loaded
2722 " result += data[arr[0].p];\n" // back from accumulator before storing
2723 "return result;\n", // named properties.
2724 57},
2725 {"var data = {x:23, y:34};\n"
2726 "var result = 0;\n"
2727 "var o = {};\n"
2728 "var i = 0;\n"
2729 "for (o[i++] in data)\n" // This is to test if value is loaded
2730 " result += data[o[i-1]];\n" // back from accumulator before
2731 "return result;\n", // storing keyed properties.
2732 57}};
2733
2734 // Two passes are made for this test. On the first, 8-bit register
2735 // operands are employed, and on the 16-bit register operands are
2736 // used.
2737 for (int pass = 0; pass < 2; pass++) {
2738 HandleAndZoneScope handles;
2739 std::ostringstream wide_os;
2740 if (pass == 1) {
2741 for (int i = 0; i < 200; i++) {
2742 wide_os << "var local" << i << " = 0;\n";
2743 }
2744 }
2745
2746 for (size_t i = 0; i < arraysize(for_in_samples); i++) {
2747 std::ostringstream body_os;
2748 body_os << wide_os.str() << for_in_samples[i].first;
2749 std::string body(body_os.str());
2750 std::string function = InterpreterTester::SourceForBody(body.c_str());
2751 InterpreterTester tester(handles.main_isolate(), function.c_str());
2752 auto callable = tester.GetCallable<>();
2753 Handle<Object> return_val = callable().ToHandleChecked();
2754 CHECK_EQ(Handle<Smi>::cast(return_val)->value(),
2755 for_in_samples[i].second);
2756 }
2757 }
2758}
2759
2760
2761TEST(InterpreterForOf) {
2762 HandleAndZoneScope handles;
2763 i::Isolate* isolate = handles.main_isolate();
2764 i::Factory* factory = isolate->factory();
2765
2766 std::pair<const char*, Handle<Object>> for_of[] = {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002767 {"function f() {\n"
2768 " var r = 0;\n"
Ben Murdoch097c5b22016-05-18 11:27:45 +01002769 " for (var a of [0,6,7,9]) { r += a; }\n"
2770 " return r;\n"
2771 "}",
2772 handle(Smi::FromInt(22), isolate)},
2773 {"function f() {\n"
2774 " var r = '';\n"
2775 " for (var a of 'foobar') { r = a + r; }\n"
2776 " return r;\n"
2777 "}",
2778 factory->NewStringFromStaticChars("raboof")},
2779 {"function f() {\n"
2780 " var a = [1, 2, 3];\n"
2781 " a.name = 4;\n"
2782 " var r = 0;\n"
2783 " for (var x of a) { r += x; }\n"
2784 " return r;\n"
2785 "}",
2786 handle(Smi::FromInt(6), isolate)},
2787 {"function f() {\n"
2788 " var r = '';\n"
2789 " var data = [1, 2, 3]; \n"
2790 " for (a of data) { delete data[0]; r += a; } return r; }",
2791 factory->NewStringFromStaticChars("123")},
2792 {"function f() {\n"
2793 " var r = '';\n"
2794 " var data = [1, 2, 3]; \n"
2795 " for (a of data) { delete data[2]; r += a; } return r; }",
2796 factory->NewStringFromStaticChars("12undefined")},
2797 {"function f() {\n"
2798 " var r = '';\n"
2799 " var data = [1, 2, 3]; \n"
2800 " for (a of data) { delete data; r += a; } return r; }",
2801 factory->NewStringFromStaticChars("123")},
2802 {"function f() {\n"
2803 " var r = '';\n"
2804 " var input = 'foobar';\n"
2805 " for (var a of input) {\n"
2806 " if (a == 'b') break;\n"
2807 " r += a;\n"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002808 " }\n"
2809 " return r;\n"
2810 "}",
Ben Murdoch097c5b22016-05-18 11:27:45 +01002811 factory->NewStringFromStaticChars("foo")},
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002812 {"function f() {\n"
Ben Murdoch097c5b22016-05-18 11:27:45 +01002813 " var r = '';\n"
2814 " var input = 'foobar';\n"
2815 " for (var a of input) {\n"
2816 " if (a == 'b') continue;\n"
2817 " r += a;\n"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002818 " }\n"
Ben Murdoch097c5b22016-05-18 11:27:45 +01002819 " return r;\n"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002820 "}",
Ben Murdoch097c5b22016-05-18 11:27:45 +01002821 factory->NewStringFromStaticChars("fooar")},
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002822 {"function f() {\n"
Ben Murdoch097c5b22016-05-18 11:27:45 +01002823 " var r = '';\n"
2824 " var data = [1, 2, 3, 4]; \n"
2825 " for (a of data) { data[2] = 567; r += a; }\n"
2826 " return r;\n"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002827 "}",
Ben Murdoch097c5b22016-05-18 11:27:45 +01002828 factory->NewStringFromStaticChars("125674")},
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002829 {"function f() {\n"
Ben Murdoch097c5b22016-05-18 11:27:45 +01002830 " var r = '';\n"
2831 " var data = [1, 2, 3, 4]; \n"
2832 " for (a of data) { data[4] = 567; r += a; }\n"
2833 " return r;\n"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002834 "}",
Ben Murdoch097c5b22016-05-18 11:27:45 +01002835 factory->NewStringFromStaticChars("1234567")},
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002836 {"function f() {\n"
Ben Murdoch097c5b22016-05-18 11:27:45 +01002837 " var r = '';\n"
2838 " var data = [1, 2, 3, 4]; \n"
2839 " for (a of data) { data[5] = 567; r += a; }\n"
2840 " return r;\n"
2841 "}",
2842 factory->NewStringFromStaticChars("1234undefined567")},
2843 {"function f() {\n"
2844 " var r = '';\n"
2845 " var obj = new Object();\n"
2846 " obj[Symbol.iterator] = function() { return {\n"
2847 " index: 3,\n"
2848 " data: ['a', 'b', 'c', 'd'],"
2849 " next: function() {"
2850 " return {"
2851 " done: this.index == -1,\n"
2852 " value: this.index < 0 ? undefined : this.data[this.index--]\n"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002853 " }\n"
Ben Murdoch097c5b22016-05-18 11:27:45 +01002854 " }\n"
2855 " }}\n"
2856 " for (a of obj) { r += a }\n"
2857 " return r;\n"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002858 "}",
Ben Murdoch097c5b22016-05-18 11:27:45 +01002859 factory->NewStringFromStaticChars("dcba")},
2860 };
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002861
Ben Murdoch097c5b22016-05-18 11:27:45 +01002862 for (size_t i = 0; i < arraysize(for_of); i++) {
2863 InterpreterTester tester(handles.main_isolate(), for_of[i].first);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002864 auto callable = tester.GetCallable<>();
2865 Handle<Object> return_val = callable().ToHandleChecked();
Ben Murdoch097c5b22016-05-18 11:27:45 +01002866 CHECK(return_val->SameValue(*for_of[i].second));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002867 }
2868}
2869
2870
2871TEST(InterpreterSwitch) {
2872 HandleAndZoneScope handles;
2873 i::Isolate* isolate = handles.main_isolate();
2874 i::Factory* factory = isolate->factory();
2875
2876 std::pair<const char*, Handle<Object>> switch_ops[] = {
2877 std::make_pair("var a = 1;\n"
2878 "switch(a) {\n"
2879 " case 1: return 2;\n"
2880 " case 2: return 3;\n"
2881 "}\n",
2882 handle(Smi::FromInt(2), isolate)),
2883 std::make_pair("var a = 1;\n"
2884 "switch(a) {\n"
2885 " case 2: a = 2; break;\n"
2886 " case 1: a = 3; break;\n"
2887 "}\n"
2888 "return a;",
2889 handle(Smi::FromInt(3), isolate)),
2890 std::make_pair("var a = 1;\n"
2891 "switch(a) {\n"
2892 " case 1: a = 2; // fall-through\n"
2893 " case 2: a = 3; break;\n"
2894 "}\n"
2895 "return a;",
2896 handle(Smi::FromInt(3), isolate)),
2897 std::make_pair("var a = 100;\n"
2898 "switch(a) {\n"
2899 " case 1: return 100;\n"
2900 " case 2: return 200;\n"
2901 "}\n"
2902 "return undefined;",
2903 factory->undefined_value()),
2904 std::make_pair("var a = 100;\n"
2905 "switch(a) {\n"
2906 " case 1: return 100;\n"
2907 " case 2: return 200;\n"
2908 " default: return 300;\n"
2909 "}\n"
2910 "return undefined;",
2911 handle(Smi::FromInt(300), isolate)),
2912 std::make_pair("var a = 100;\n"
2913 "switch(typeof(a)) {\n"
2914 " case 'string': return 1;\n"
2915 " case 'number': return 2;\n"
2916 " default: return 3;\n"
2917 "}\n",
2918 handle(Smi::FromInt(2), isolate)),
2919 std::make_pair("var a = 100;\n"
2920 "switch(a) {\n"
2921 " case a += 20: return 1;\n"
2922 " case a -= 10: return 2;\n"
2923 " case a -= 10: return 3;\n"
2924 " default: return 3;\n"
2925 "}\n",
2926 handle(Smi::FromInt(3), isolate)),
2927 std::make_pair("var a = 1;\n"
2928 "switch(a) {\n"
2929 " case 1: \n"
2930 " switch(a + 1) {\n"
2931 " case 2 : a += 1; break;\n"
2932 " default : a += 2; break;\n"
2933 " } // fall-through\n"
2934 " case 2: a += 3;\n"
2935 "}\n"
2936 "return a;",
2937 handle(Smi::FromInt(5), isolate)),
2938 };
2939
2940 for (size_t i = 0; i < arraysize(switch_ops); i++) {
2941 std::string source(InterpreterTester::SourceForBody(switch_ops[i].first));
2942 InterpreterTester tester(handles.main_isolate(), source.c_str());
2943 auto callable = tester.GetCallable<>();
2944
2945 Handle<i::Object> return_value = callable().ToHandleChecked();
2946 CHECK(return_value->SameValue(*switch_ops[i].second));
2947 }
2948}
2949
2950
2951TEST(InterpreterSloppyThis) {
2952 HandleAndZoneScope handles;
2953 i::Isolate* isolate = handles.main_isolate();
2954 i::Factory* factory = isolate->factory();
2955
2956 std::pair<const char*, Handle<Object>> sloppy_this[] = {
2957 std::make_pair("var global_val = 100;\n"
2958 "function f() { return this.global_val; }\n",
2959 handle(Smi::FromInt(100), isolate)),
2960 std::make_pair("var global_val = 110;\n"
2961 "function g() { return this.global_val; };"
2962 "function f() { return g(); }\n",
2963 handle(Smi::FromInt(110), isolate)),
2964 std::make_pair("var global_val = 110;\n"
2965 "function g() { return this.global_val };"
2966 "function f() { 'use strict'; return g(); }\n",
2967 handle(Smi::FromInt(110), isolate)),
2968 std::make_pair("function f() { 'use strict'; return this; }\n",
2969 factory->undefined_value()),
2970 std::make_pair("function g() { 'use strict'; return this; };"
2971 "function f() { return g(); }\n",
2972 factory->undefined_value()),
2973 };
2974
2975 for (size_t i = 0; i < arraysize(sloppy_this); i++) {
2976 InterpreterTester tester(handles.main_isolate(), sloppy_this[i].first);
2977 auto callable = tester.GetCallable<>();
2978
2979 Handle<i::Object> return_value = callable().ToHandleChecked();
2980 CHECK(return_value->SameValue(*sloppy_this[i].second));
2981 }
2982}
2983
2984
2985TEST(InterpreterThisFunction) {
2986 HandleAndZoneScope handles;
2987 i::Isolate* isolate = handles.main_isolate();
2988 i::Factory* factory = isolate->factory();
2989
2990 InterpreterTester tester(handles.main_isolate(),
2991 "var f;\n f = function f() { return f.name; }");
2992 auto callable = tester.GetCallable<>();
2993
2994 Handle<i::Object> return_value = callable().ToHandleChecked();
2995 CHECK(return_value->SameValue(*factory->NewStringFromStaticChars("f")));
2996}
2997
2998
2999TEST(InterpreterNewTarget) {
3000 HandleAndZoneScope handles;
3001 i::Isolate* isolate = handles.main_isolate();
3002 i::Factory* factory = isolate->factory();
3003
3004 // TODO(rmcilroy): Add tests that we get the original constructor for
3005 // superclass constructors once we have class support.
3006 InterpreterTester tester(handles.main_isolate(),
3007 "function f() { this.a = new.target; }");
3008 auto callable = tester.GetCallable<>();
3009 callable().ToHandleChecked();
3010
3011 Handle<Object> new_target_name = v8::Utils::OpenHandle(
3012 *CompileRun("(function() { return (new f()).a.name; })();"));
3013 CHECK(new_target_name->SameValue(*factory->NewStringFromStaticChars("f")));
3014}
3015
3016
3017TEST(InterpreterAssignmentInExpressions) {
3018 HandleAndZoneScope handles;
3019
3020 std::pair<const char*, int> samples[] = {
3021 {"function f() {\n"
3022 " var x = 7;\n"
3023 " var y = x + (x = 1) + (x = 2);\n"
3024 " return y;\n"
3025 "}",
3026 10},
3027 {"function f() {\n"
3028 " var x = 7;\n"
3029 " var y = x + (x = 1) + (x = 2);\n"
3030 " return x;\n"
3031 "}",
3032 2},
3033 {"function f() {\n"
3034 " var x = 55;\n"
3035 " x = x + (x = 100) + (x = 101);\n"
3036 " return x;\n"
3037 "}",
3038 256},
3039 {"function f() {\n"
3040 " var x = 7;\n"
3041 " return ++x + x + x++;\n"
3042 "}",
3043 24},
3044 {"function f() {\n"
3045 " var x = 7;\n"
3046 " var y = 1 + ++x + x + x++;\n"
3047 " return x;\n"
3048 "}",
3049 9},
3050 {"function f() {\n"
3051 " var x = 7;\n"
3052 " var y = ++x + x + x++;\n"
3053 " return x;\n"
3054 "}",
3055 9},
3056 {"function f() {\n"
3057 " var x = 7, y = 100, z = 1000;\n"
3058 " return x + (x += 3) + y + (y *= 10) + (z *= 7) + z;\n"
3059 "}",
3060 15117},
3061 {"function f() {\n"
3062 " var inner = function (x) { return x + (x = 2) + (x = 4) + x; };\n"
3063 " return inner(1);\n"
3064 "}",
3065 11},
3066 {"function f() {\n"
3067 " var x = 1, y = 2;\n"
3068 " x = x + (x = 3) + y + (y = 4), y = y + (y = 5) + y + x;\n"
3069 " return x + y;\n"
3070 "}",
3071 10 + 24},
3072 {"function f() {\n"
3073 " var x = 0;\n"
3074 " var y = x | (x = 1) | (x = 2);\n"
3075 " return x;\n"
3076 "}",
3077 2},
3078 {"function f() {\n"
3079 " var x = 0;\n"
3080 " var y = x || (x = 1);\n"
3081 " return x;\n"
3082 "}",
3083 1},
3084 {"function f() {\n"
3085 " var x = 1;\n"
3086 " var y = x && (x = 2) && (x = 3);\n"
3087 " return x;\n"
3088 "}",
3089 3},
3090 {"function f() {\n"
3091 " var x = 1;\n"
3092 " var y = x || (x = 2);\n"
3093 " return x;\n"
3094 "}",
3095 1},
3096 {"function f() {\n"
3097 " var x = 1;\n"
3098 " x = (x << (x = 3)) | (x = 16);\n"
3099 " return x;\n"
3100 "}",
3101 24},
3102 {"function f() {\n"
3103 " var r = 7;\n"
3104 " var s = 11;\n"
3105 " var t = 13;\n"
3106 " var u = r + s + t + (r = 10) + (s = 20) +"
3107 " (t = (r + s)) + r + s + t;\n"
3108 " return r + s + t + u;\n"
3109 "}",
3110 211},
3111 {"function f() {\n"
3112 " var r = 7;\n"
3113 " var s = 11;\n"
3114 " var t = 13;\n"
3115 " return r > (3 * s * (s = 1)) ? (t + (t += 1)) : (r + (r = 4));\n"
3116 "}",
3117 11},
3118 {"function f() {\n"
3119 " var r = 7;\n"
3120 " var s = 11;\n"
3121 " var t = 13;\n"
3122 " return r > (3 * s * (s = 0)) ? (t + (t += 1)) : (r + (r = 4));\n"
3123 "}",
3124 27},
3125 {"function f() {\n"
3126 " var r = 7;\n"
3127 " var s = 11;\n"
3128 " var t = 13;\n"
3129 " return (r + (r = 5)) > s ? r : t;\n"
3130 "}",
3131 5},
3132 {"function f(a) {\n"
3133 " return a + (arguments[0] = 10);\n"
3134 "}",
3135 50},
3136 {"function f(a) {\n"
3137 " return a + (arguments[0] = 10) + a;\n"
3138 "}",
3139 60},
3140 {"function f(a) {\n"
3141 " return a + (arguments[0] = 10) + arguments[0];\n"
3142 "}",
3143 60},
3144 };
3145
3146 const int arg_value = 40;
3147 for (size_t i = 0; i < arraysize(samples); i++) {
3148 InterpreterTester tester(handles.main_isolate(), samples[i].first);
3149 auto callable = tester.GetCallable<Handle<Object>>();
3150 Handle<Object> return_val =
3151 callable(handle(Smi::FromInt(arg_value), handles.main_isolate()))
3152 .ToHandleChecked();
3153 CHECK_EQ(Handle<Smi>::cast(return_val)->value(), samples[i].second);
3154 }
3155}
3156
3157
3158TEST(InterpreterToName) {
3159 HandleAndZoneScope handles;
3160 i::Isolate* isolate = handles.main_isolate();
3161 i::Factory* factory = isolate->factory();
3162
3163 std::pair<const char*, Handle<Object>> to_name_tests[] = {
3164 {"var a = 'val'; var obj = {[a] : 10}; return obj.val;",
3165 factory->NewNumberFromInt(10)},
3166 {"var a = 20; var obj = {[a] : 10}; return obj['20'];",
3167 factory->NewNumberFromInt(10)},
3168 {"var a = 20; var obj = {[a] : 10}; return obj[20];",
3169 factory->NewNumberFromInt(10)},
3170 {"var a = {val:23}; var obj = {[a] : 10}; return obj[a];",
3171 factory->NewNumberFromInt(10)},
3172 {"var a = {val:23}; var obj = {[a] : 10};\n"
3173 "return obj['[object Object]'];",
3174 factory->NewNumberFromInt(10)},
3175 {"var a = {toString : function() { return 'x'}};\n"
3176 "var obj = {[a] : 10};\n"
3177 "return obj.x;",
3178 factory->NewNumberFromInt(10)},
3179 {"var a = {valueOf : function() { return 'x'}};\n"
3180 "var obj = {[a] : 10};\n"
3181 "return obj.x;",
3182 factory->undefined_value()},
3183 {"var a = {[Symbol.toPrimitive] : function() { return 'x'}};\n"
3184 "var obj = {[a] : 10};\n"
3185 "return obj.x;",
3186 factory->NewNumberFromInt(10)},
3187 };
3188
3189 for (size_t i = 0; i < arraysize(to_name_tests); i++) {
3190 std::string source(
3191 InterpreterTester::SourceForBody(to_name_tests[i].first));
3192 InterpreterTester tester(handles.main_isolate(), source.c_str());
3193 auto callable = tester.GetCallable<>();
3194
3195 Handle<i::Object> return_value = callable().ToHandleChecked();
3196 CHECK(return_value->SameValue(*to_name_tests[i].second));
3197 }
3198}
3199
3200
3201TEST(TemporaryRegisterAllocation) {
3202 HandleAndZoneScope handles;
3203 i::Isolate* isolate = handles.main_isolate();
3204 i::Factory* factory = isolate->factory();
3205
3206 std::pair<const char*, Handle<Object>> reg_tests[] = {
3207 {"function add(a, b, c) {"
3208 " return a + b + c;"
3209 "}"
3210 "function f() {"
3211 " var a = 10, b = 10;"
3212 " return add(a, b++, b);"
3213 "}",
3214 factory->NewNumberFromInt(31)},
3215 {"function add(a, b, c, d) {"
3216 " return a + b + c + d;"
3217 "}"
3218 "function f() {"
3219 " var x = 10, y = 20, z = 30;"
3220 " return x + add(x, (y= x++), x, z);"
3221 "}",
3222 factory->NewNumberFromInt(71)},
3223 };
3224
3225 for (size_t i = 0; i < arraysize(reg_tests); i++) {
3226 InterpreterTester tester(handles.main_isolate(), reg_tests[i].first);
3227 auto callable = tester.GetCallable<>();
3228
3229 Handle<i::Object> return_value = callable().ToHandleChecked();
3230 CHECK(return_value->SameValue(*reg_tests[i].second));
3231 }
3232}
3233
3234
3235TEST(InterpreterLookupSlot) {
3236 HandleAndZoneScope handles;
3237 i::Isolate* isolate = handles.main_isolate();
3238 i::Factory* factory = isolate->factory();
3239
3240 // TODO(mythria): Add more tests when we have support for eval/with.
3241 const char* function_prologue = "var f;"
3242 "var x = 1;"
3243 "function f1() {"
3244 " eval(\"function t() {";
3245 const char* function_epilogue = " }; f = t;\");"
3246 "}"
3247 "f1();";
3248
3249
3250 std::pair<const char*, Handle<Object>> lookup_slot[] = {
3251 {"return x;", handle(Smi::FromInt(1), isolate)},
3252 {"return typeof x;", factory->NewStringFromStaticChars("number")},
3253 {"return typeof dummy;", factory->NewStringFromStaticChars("undefined")},
3254 {"x = 10; return x;", handle(Smi::FromInt(10), isolate)},
3255 {"'use strict'; x = 20; return x;", handle(Smi::FromInt(20), isolate)},
3256 };
3257
3258 for (size_t i = 0; i < arraysize(lookup_slot); i++) {
3259 std::string script = std::string(function_prologue) +
3260 std::string(lookup_slot[i].first) +
3261 std::string(function_epilogue);
3262
3263 InterpreterTester tester(handles.main_isolate(), script.c_str(), "t");
3264 auto callable = tester.GetCallable<>();
3265
3266 Handle<i::Object> return_value = callable().ToHandleChecked();
3267 CHECK(return_value->SameValue(*lookup_slot[i].second));
3268 }
3269}
3270
3271
3272TEST(InterpreterCallLookupSlot) {
3273 HandleAndZoneScope handles;
3274 i::Isolate* isolate = handles.main_isolate();
3275
3276 std::pair<const char*, Handle<Object>> call_lookup[] = {
3277 {"g = function(){ return 2 }; eval(''); return g();",
3278 handle(Smi::FromInt(2), isolate)},
3279 {"g = function(){ return 2 }; eval('g = function() {return 3}');\n"
3280 "return g();",
3281 handle(Smi::FromInt(3), isolate)},
3282 {"g = { x: function(){ return this.y }, y: 20 };\n"
3283 "eval('g = { x: g.x, y: 30 }');\n"
3284 "return g.x();",
3285 handle(Smi::FromInt(30), isolate)},
3286 };
3287
3288 for (size_t i = 0; i < arraysize(call_lookup); i++) {
3289 std::string source(InterpreterTester::SourceForBody(call_lookup[i].first));
3290 InterpreterTester tester(handles.main_isolate(), source.c_str());
3291 auto callable = tester.GetCallable<>();
3292
3293 Handle<i::Object> return_value = callable().ToHandleChecked();
3294 CHECK(return_value->SameValue(*call_lookup[i].second));
3295 }
3296}
3297
3298
3299TEST(InterpreterLookupSlotWide) {
3300 HandleAndZoneScope handles;
3301 i::Isolate* isolate = handles.main_isolate();
3302 i::Factory* factory = isolate->factory();
3303
3304 const char* function_prologue =
3305 "var f;"
3306 "var x = 1;"
3307 "function f1() {"
3308 " eval(\"function t() {";
3309 const char* function_epilogue =
3310 " }; f = t;\");"
3311 "}"
3312 "f1();";
3313 std::ostringstream str;
3314 str << "var y = 2.3;";
3315 for (int i = 1; i < 256; i++) {
3316 str << "y = " << 2.3 + i << ";";
3317 }
3318 std::string init_function_body = str.str();
3319
3320 std::pair<std::string, Handle<Object>> lookup_slot[] = {
3321 {init_function_body + "return x;", handle(Smi::FromInt(1), isolate)},
3322 {init_function_body + "return typeof x;",
3323 factory->NewStringFromStaticChars("number")},
3324 {init_function_body + "return x = 10;",
3325 handle(Smi::FromInt(10), isolate)},
3326 {"'use strict';" + init_function_body + "x = 20; return x;",
3327 handle(Smi::FromInt(20), isolate)},
3328 };
3329
3330 for (size_t i = 0; i < arraysize(lookup_slot); i++) {
3331 std::string script = std::string(function_prologue) + lookup_slot[i].first +
3332 std::string(function_epilogue);
3333
3334 InterpreterTester tester(handles.main_isolate(), script.c_str(), "t");
3335 auto callable = tester.GetCallable<>();
3336
3337 Handle<i::Object> return_value = callable().ToHandleChecked();
3338 CHECK(return_value->SameValue(*lookup_slot[i].second));
3339 }
3340}
3341
3342
3343TEST(InterpreterDeleteLookupSlot) {
3344 HandleAndZoneScope handles;
3345 i::Isolate* isolate = handles.main_isolate();
3346 i::Factory* factory = isolate->factory();
3347
3348 // TODO(mythria): Add more tests when we have support for eval/with.
3349 const char* function_prologue = "var f;"
3350 "var x = 1;"
3351 "y = 10;"
3352 "var obj = {val:10};"
3353 "var z = 30;"
3354 "function f1() {"
3355 " var z = 20;"
3356 " eval(\"function t() {";
3357 const char* function_epilogue = " }; f = t;\");"
3358 "}"
3359 "f1();";
3360
3361
3362 std::pair<const char*, Handle<Object>> delete_lookup_slot[] = {
3363 {"return delete x;", factory->false_value()},
3364 {"return delete y;", factory->true_value()},
3365 {"return delete z;", factory->false_value()},
3366 {"return delete obj.val;", factory->true_value()},
3367 {"'use strict'; return delete obj.val;", factory->true_value()},
3368 };
3369
3370 for (size_t i = 0; i < arraysize(delete_lookup_slot); i++) {
3371 std::string script = std::string(function_prologue) +
3372 std::string(delete_lookup_slot[i].first) +
3373 std::string(function_epilogue);
3374
3375 InterpreterTester tester(handles.main_isolate(), script.c_str(), "t");
3376 auto callable = tester.GetCallable<>();
3377
3378 Handle<i::Object> return_value = callable().ToHandleChecked();
3379 CHECK(return_value->SameValue(*delete_lookup_slot[i].second));
3380 }
3381}
3382
3383
3384TEST(JumpWithConstantsAndWideConstants) {
3385 HandleAndZoneScope handles;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003386 const int kStep = 13;
Ben Murdoch097c5b22016-05-18 11:27:45 +01003387 for (int constants = 11; constants < 256 + 3 * kStep; constants += kStep) {
3388 auto isolate = handles.main_isolate();
3389 auto factory = isolate->factory();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003390 std::ostringstream filler_os;
3391 // Generate a string that consumes constant pool entries and
3392 // spread out branch distances in script below.
3393 for (int i = 0; i < constants; i++) {
3394 filler_os << "var x_ = 'x_" << i << "';\n";
3395 }
3396 std::string filler(filler_os.str());
3397 std::ostringstream script_os;
3398 script_os << "function " << InterpreterTester::function_name() << "(a) {\n";
3399 script_os << " " << filler;
3400 script_os << " for (var i = a; i < 2; i++) {\n";
3401 script_os << " " << filler;
3402 script_os << " if (i == 0) { " << filler << "i = 10; continue; }\n";
3403 script_os << " else if (i == a) { " << filler << "i = 12; break; }\n";
3404 script_os << " else { " << filler << " }\n";
3405 script_os << " }\n";
3406 script_os << " return i;\n";
3407 script_os << "}\n";
3408 std::string script(script_os.str());
3409 for (int a = 0; a < 3; a++) {
3410 InterpreterTester tester(handles.main_isolate(), script.c_str());
3411 auto callable = tester.GetCallable<Handle<Object>>();
Ben Murdoch097c5b22016-05-18 11:27:45 +01003412 Handle<Object> argument = factory->NewNumberFromInt(a);
3413 Handle<Object> return_val = callable(argument).ToHandleChecked();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003414 static const int results[] = {11, 12, 2};
3415 CHECK_EQ(Handle<Smi>::cast(return_val)->value(), results[a]);
3416 }
3417 }
3418}
3419
3420
3421TEST(InterpreterEval) {
3422 HandleAndZoneScope handles;
3423 i::Isolate* isolate = handles.main_isolate();
3424 i::Factory* factory = isolate->factory();
3425
3426 std::pair<const char*, Handle<Object>> eval[] = {
3427 {"return eval('1;');", handle(Smi::FromInt(1), isolate)},
3428 {"return eval('100 * 20;');", handle(Smi::FromInt(2000), isolate)},
3429 {"var x = 10; return eval('x + 20;');",
3430 handle(Smi::FromInt(30), isolate)},
3431 {"var x = 10; eval('x = 33;'); return x;",
3432 handle(Smi::FromInt(33), isolate)},
3433 {"'use strict'; var x = 20; var z = 0;\n"
3434 "eval('var x = 33; z = x;'); return x + z;",
3435 handle(Smi::FromInt(53), isolate)},
3436 {"eval('var x = 33;'); eval('var y = x + 20'); return x + y;",
3437 handle(Smi::FromInt(86), isolate)},
3438 {"var x = 1; eval('for(i = 0; i < 10; i++) x = x + 1;'); return x",
3439 handle(Smi::FromInt(11), isolate)},
3440 {"var x = 10; eval('var x = 20;'); return x;",
3441 handle(Smi::FromInt(20), isolate)},
3442 {"var x = 1; eval('\"use strict\"; var x = 2;'); return x;",
3443 handle(Smi::FromInt(1), isolate)},
3444 {"'use strict'; var x = 1; eval('var x = 2;'); return x;",
3445 handle(Smi::FromInt(1), isolate)},
3446 {"var x = 10; eval('x + 20;'); return typeof x;",
3447 factory->NewStringFromStaticChars("number")},
3448 {"eval('var y = 10;'); return typeof unallocated;",
3449 factory->NewStringFromStaticChars("undefined")},
3450 {"'use strict'; eval('var y = 10;'); return typeof unallocated;",
3451 factory->NewStringFromStaticChars("undefined")},
3452 {"eval('var x = 10;'); return typeof x;",
3453 factory->NewStringFromStaticChars("number")},
3454 {"var x = {}; eval('var x = 10;'); return typeof x;",
3455 factory->NewStringFromStaticChars("number")},
3456 {"'use strict'; var x = {}; eval('var x = 10;'); return typeof x;",
3457 factory->NewStringFromStaticChars("object")},
3458 };
3459
3460 for (size_t i = 0; i < arraysize(eval); i++) {
3461 std::string source(InterpreterTester::SourceForBody(eval[i].first));
3462 InterpreterTester tester(handles.main_isolate(), source.c_str());
3463 auto callable = tester.GetCallable<>();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00003464 Handle<i::Object> return_value = callable().ToHandleChecked();
3465 CHECK(return_value->SameValue(*eval[i].second));
3466 }
3467}
3468
3469
3470TEST(InterpreterEvalParams) {
3471 HandleAndZoneScope handles;
3472 i::Isolate* isolate = handles.main_isolate();
3473
3474 std::pair<const char*, Handle<Object>> eval_params[] = {
3475 {"var x = 10; return eval('x + p1;');",
3476 handle(Smi::FromInt(30), isolate)},
3477 {"var x = 10; eval('p1 = x;'); return p1;",
3478 handle(Smi::FromInt(10), isolate)},
3479 {"var a = 10;"
3480 "function inner() { return eval('a + p1;');}"
3481 "return inner();",
3482 handle(Smi::FromInt(30), isolate)},
3483 };
3484
3485 for (size_t i = 0; i < arraysize(eval_params); i++) {
3486 std::string source = "function " + InterpreterTester::function_name() +
3487 "(p1) {" + eval_params[i].first + "}";
3488 InterpreterTester tester(handles.main_isolate(), source.c_str());
3489 auto callable = tester.GetCallable<Handle<Object>>();
3490
3491 Handle<i::Object> return_value =
3492 callable(handle(Smi::FromInt(20), isolate)).ToHandleChecked();
3493 CHECK(return_value->SameValue(*eval_params[i].second));
3494 }
3495}
3496
3497
3498TEST(InterpreterEvalGlobal) {
3499 HandleAndZoneScope handles;
3500 i::Isolate* isolate = handles.main_isolate();
3501 i::Factory* factory = isolate->factory();
3502
3503 std::pair<const char*, Handle<Object>> eval_global[] = {
3504 {"function add_global() { eval('function test() { z = 33; }; test()'); };"
3505 "function f() { add_global(); return z; }; f();",
3506 handle(Smi::FromInt(33), isolate)},
3507 {"function add_global() {\n"
3508 " eval('\"use strict\"; function test() { y = 33; };"
3509 " try { test() } catch(e) {}');\n"
3510 "}\n"
3511 "function f() { add_global(); return typeof y; } f();",
3512 factory->NewStringFromStaticChars("undefined")},
3513 };
3514
3515 for (size_t i = 0; i < arraysize(eval_global); i++) {
3516 InterpreterTester tester(handles.main_isolate(), eval_global[i].first,
3517 "test");
3518 auto callable = tester.GetCallable<>();
3519
3520 Handle<i::Object> return_value = callable().ToHandleChecked();
3521 CHECK(return_value->SameValue(*eval_global[i].second));
3522 }
3523}
3524
Ben Murdoch097c5b22016-05-18 11:27:45 +01003525
3526TEST(InterpreterEvalVariableDecl) {
3527 HandleAndZoneScope handles;
3528 i::Isolate* isolate = handles.main_isolate();
3529 i::Factory* factory = isolate->factory();
3530
3531 std::pair<const char*, Handle<Object>> eval_global[] = {
3532 {"function f() { eval('var x = 10; x++;'); return x; }",
3533 handle(Smi::FromInt(11), isolate)},
3534 {"function f() { var x = 20; eval('var x = 10; x++;'); return x; }",
3535 handle(Smi::FromInt(11), isolate)},
3536 {"function f() {"
3537 " var x = 20;"
3538 " eval('\"use strict\"; var x = 10; x++;');"
3539 " return x; }",
3540 handle(Smi::FromInt(20), isolate)},
3541 {"function f() {"
3542 " var y = 30;"
3543 " eval('var x = {1:20}; x[2]=y;');"
3544 " return x[2]; }",
3545 handle(Smi::FromInt(30), isolate)},
3546 {"function f() {"
3547 " eval('var x = {name:\"test\"};');"
3548 " return x.name; }",
3549 factory->NewStringFromStaticChars("test")},
3550 {"function f() {"
3551 " eval('var x = [{name:\"test\"}, {type:\"cc\"}];');"
3552 " return x[1].type+x[0].name; }",
3553 factory->NewStringFromStaticChars("cctest")},
3554 {"function f() {\n"
3555 " var x = 3;\n"
3556 " var get_eval_x;\n"
3557 " eval('\"use strict\"; "
3558 " var x = 20; "
3559 " get_eval_x = function func() {return x;};');\n"
3560 " return get_eval_x() + x;\n"
3561 "}",
3562 handle(Smi::FromInt(23), isolate)},
3563 // TODO(mythria): Add tests with const declarations.
3564 };
3565
3566 for (size_t i = 0; i < arraysize(eval_global); i++) {
3567 InterpreterTester tester(handles.main_isolate(), eval_global[i].first, "*");
3568 auto callable = tester.GetCallable<>();
3569
3570 Handle<i::Object> return_value = callable().ToHandleChecked();
3571 CHECK(return_value->SameValue(*eval_global[i].second));
3572 }
3573}
3574
3575
3576TEST(InterpreterEvalFunctionDecl) {
3577 HandleAndZoneScope handles;
3578 i::Isolate* isolate = handles.main_isolate();
3579
3580 std::pair<const char*, Handle<Object>> eval_func_decl[] = {
3581 {"function f() {\n"
3582 " var x = 3;\n"
3583 " eval('var x = 20;"
3584 " function get_x() {return x;};');\n"
3585 " return get_x() + x;\n"
3586 "}",
3587 handle(Smi::FromInt(40), isolate)},
3588 };
3589
3590 for (size_t i = 0; i < arraysize(eval_func_decl); i++) {
3591 InterpreterTester tester(handles.main_isolate(), eval_func_decl[i].first,
3592 "*");
3593 auto callable = tester.GetCallable<>();
3594
3595 Handle<i::Object> return_value = callable().ToHandleChecked();
3596 CHECK(return_value->SameValue(*eval_func_decl[i].second));
3597 }
3598}
3599
3600TEST(InterpreterWideRegisterArithmetic) {
3601 HandleAndZoneScope handles;
3602 i::Isolate* isolate = handles.main_isolate();
3603
3604 static const size_t kMaxRegisterForTest = 150;
3605 std::ostringstream os;
3606 os << "function " << InterpreterTester::function_name() << "(arg) {\n";
3607 os << " var retval = -77;\n";
3608 for (size_t i = 0; i < kMaxRegisterForTest; i++) {
3609 os << " var x" << i << " = " << i << ";\n";
3610 }
3611 for (size_t i = 0; i < kMaxRegisterForTest / 2; i++) {
3612 size_t j = kMaxRegisterForTest - i - 1;
3613 os << " var tmp = x" << j << ";\n";
3614 os << " var x" << j << " = x" << i << ";\n";
3615 os << " var x" << i << " = tmp;\n";
3616 }
3617 for (size_t i = 0; i < kMaxRegisterForTest / 2; i++) {
3618 size_t j = kMaxRegisterForTest - i - 1;
3619 os << " var tmp = x" << j << ";\n";
3620 os << " var x" << j << " = x" << i << ";\n";
3621 os << " var x" << i << " = tmp;\n";
3622 }
3623 for (size_t i = 0; i < kMaxRegisterForTest; i++) {
3624 os << " if (arg == " << i << ") {\n" //
3625 << " retval = x" << i << ";\n" //
3626 << " }\n"; //
3627 }
3628 os << " return retval;\n";
3629 os << "}\n";
3630
3631 std::string source = os.str();
3632 InterpreterTester tester(handles.main_isolate(), source.c_str());
3633 auto callable = tester.GetCallable<Handle<Object>>();
3634 for (size_t i = 0; i < kMaxRegisterForTest; i++) {
3635 Handle<Object> arg = handle(Smi::FromInt(static_cast<int>(i)), isolate);
3636 Handle<Object> return_value = callable(arg).ToHandleChecked();
3637 CHECK(return_value->SameValue(*arg));
3638 }
3639}
3640
3641TEST(InterpreterCallWideRegisters) {
3642 static const int kPeriod = 25;
3643 static const int kLength = 512;
3644 static const int kStartChar = 65;
3645
3646 for (int pass = 0; pass < 3; pass += 1) {
3647 std::ostringstream os;
3648 for (int i = 0; i < pass * 97; i += 1) {
3649 os << "var x" << i << " = " << i << "\n";
3650 }
3651 os << "return String.fromCharCode(";
3652 os << kStartChar;
3653 for (int i = 1; i < kLength; i += 1) {
3654 os << "," << kStartChar + (i % kPeriod);
3655 }
3656 os << ");";
3657 std::string source = InterpreterTester::SourceForBody(os.str().c_str());
3658 HandleAndZoneScope handles;
3659 InterpreterTester tester(handles.main_isolate(), source.c_str());
3660 auto callable = tester.GetCallable();
3661 Handle<Object> return_val = callable().ToHandleChecked();
3662 Handle<String> return_string = Handle<String>::cast(return_val);
3663 CHECK_EQ(return_string->length(), kLength);
3664 for (int i = 0; i < kLength; i += 1) {
3665 CHECK_EQ(return_string->Get(i), 65 + (i % kPeriod));
3666 }
3667 }
3668}
3669
3670TEST(InterpreterWideParametersPickOne) {
3671 static const int kParameterCount = 130;
3672 for (int parameter = 0; parameter < 10; parameter++) {
3673 HandleAndZoneScope handles;
3674 i::Isolate* isolate = handles.main_isolate();
3675 std::ostringstream os;
3676 os << "function " << InterpreterTester::function_name() << "(arg) {\n";
3677 os << " function selector(i";
3678 for (int i = 0; i < kParameterCount; i++) {
3679 os << ","
3680 << "a" << i;
3681 }
3682 os << ") {\n";
3683 os << " return a" << parameter << ";\n";
3684 os << " };\n";
3685 os << " return selector(arg";
3686 for (int i = 0; i < kParameterCount; i++) {
3687 os << "," << i;
3688 }
3689 os << ");";
3690 os << "}\n";
3691
3692 std::string source = os.str();
3693 InterpreterTester tester(handles.main_isolate(), source.c_str(), "*");
3694 auto callable = tester.GetCallable<Handle<Object>>();
3695 Handle<Object> arg = handle(Smi::FromInt(0xaa55), isolate);
3696 Handle<Object> return_value = callable(arg).ToHandleChecked();
3697 Handle<Smi> actual = Handle<Smi>::cast(return_value);
3698 CHECK_EQ(actual->value(), parameter);
3699 }
3700}
3701
3702TEST(InterpreterWideParametersSummation) {
3703 static int kParameterCount = 200;
3704 static int kBaseValue = 17000;
3705 HandleAndZoneScope handles;
3706 i::Isolate* isolate = handles.main_isolate();
3707 std::ostringstream os;
3708 os << "function " << InterpreterTester::function_name() << "(arg) {\n";
3709 os << " function summation(i";
3710 for (int i = 0; i < kParameterCount; i++) {
3711 os << ","
3712 << "a" << i;
3713 }
3714 os << ") {\n";
3715 os << " var sum = " << kBaseValue << ";\n";
3716 os << " switch(i) {\n";
3717 for (int i = 0; i < kParameterCount; i++) {
3718 int j = kParameterCount - i - 1;
3719 os << " case " << j << ": sum += a" << j << ";\n";
3720 }
3721 os << " }\n";
3722 os << " return sum;\n";
3723 os << " };\n";
3724 os << " return summation(arg";
3725 for (int i = 0; i < kParameterCount; i++) {
3726 os << "," << i;
3727 }
3728 os << ");";
3729 os << "}\n";
3730
3731 std::string source = os.str();
3732 InterpreterTester tester(handles.main_isolate(), source.c_str(), "*");
3733 auto callable = tester.GetCallable<Handle<Object>>();
3734 for (int i = 0; i < kParameterCount; i++) {
3735 Handle<Object> arg = handle(Smi::FromInt(i), isolate);
3736 Handle<Object> return_value = callable(arg).ToHandleChecked();
3737 int expected = kBaseValue + i * (i + 1) / 2;
3738 Handle<Smi> actual = Handle<Smi>::cast(return_value);
3739 CHECK_EQ(actual->value(), expected);
3740 }
3741}
3742
3743TEST(InterpreterDoExpression) {
3744 bool old_flag = FLAG_harmony_do_expressions;
3745 FLAG_harmony_do_expressions = true;
3746
3747 HandleAndZoneScope handles;
3748 i::Isolate* isolate = handles.main_isolate();
3749 Factory* factory = isolate->factory();
3750
3751 std::pair<const char*, Handle<Object>> do_expr[] = {
3752 {"var a = do {}; return a;", factory->undefined_value()},
3753 {"var a = do { var x = 100; }; return a;", factory->undefined_value()},
3754 {"var a = do { var x = 100; }; return a;", factory->undefined_value()},
3755 {"var a = do { var x = 100; x++; }; return a;",
3756 handle(Smi::FromInt(100), isolate)},
3757 {"var i = 0; for (; i < 5;) { i = do { if (i == 3) { break; }; i + 1; }};"
3758 "return i;",
3759 handle(Smi::FromInt(3), isolate)},
3760 };
3761
3762 for (size_t i = 0; i < arraysize(do_expr); i++) {
3763 std::string source(InterpreterTester::SourceForBody(do_expr[i].first));
3764 InterpreterTester tester(handles.main_isolate(), source.c_str());
3765 auto callable = tester.GetCallable<>();
3766
3767 Handle<i::Object> return_value = callable().ToHandleChecked();
3768 CHECK(return_value->SameValue(*do_expr[i].second));
3769 }
3770
3771 FLAG_harmony_do_expressions = old_flag;
3772}
3773
3774TEST(InterpreterWithStatement) {
3775 HandleAndZoneScope handles;
3776 i::Isolate* isolate = handles.main_isolate();
3777
3778 std::pair<const char*, Handle<Object>> with_stmt[] = {
3779 {"with({x:42}) return x;", handle(Smi::FromInt(42), isolate)},
3780 {"with({}) { var y = 10; return y;}", handle(Smi::FromInt(10), isolate)},
3781 {"var y = {x:42};"
3782 " function inner() {"
3783 " var x = 20;"
3784 " with(y) return x;"
3785 "}"
3786 "return inner();",
3787 handle(Smi::FromInt(42), isolate)},
3788 {"var y = {x:42};"
3789 " function inner(o) {"
3790 " var x = 20;"
3791 " with(o) return x;"
3792 "}"
3793 "return inner(y);",
3794 handle(Smi::FromInt(42), isolate)},
3795 };
3796
3797 for (size_t i = 0; i < arraysize(with_stmt); i++) {
3798 std::string source(InterpreterTester::SourceForBody(with_stmt[i].first));
3799 InterpreterTester tester(handles.main_isolate(), source.c_str());
3800 auto callable = tester.GetCallable<>();
3801
3802 Handle<i::Object> return_value = callable().ToHandleChecked();
3803 CHECK(return_value->SameValue(*with_stmt[i].second));
3804 }
3805}
3806
3807TEST(InterpreterClassLiterals) {
3808 HandleAndZoneScope handles;
3809 i::Isolate* isolate = handles.main_isolate();
3810 std::pair<const char*, Handle<Object>> examples[] = {
3811 {"class C {\n"
3812 " constructor(x) { this.x_ = x; }\n"
3813 " method() { return this.x_; }\n"
3814 "}\n"
3815 "return new C(99).method();",
3816 handle(Smi::FromInt(99), isolate)},
3817 {"class C {\n"
3818 " constructor(x) { this.x_ = x; }\n"
3819 " static static_method(x) { return x; }\n"
3820 "}\n"
3821 "return C.static_method(101);",
3822 handle(Smi::FromInt(101), isolate)},
3823 {"class C {\n"
3824 " get x() { return 102; }\n"
3825 "}\n"
3826 "return new C().x",
3827 handle(Smi::FromInt(102), isolate)},
3828 {"class C {\n"
3829 " static get x() { return 103; }\n"
3830 "}\n"
3831 "return C.x",
3832 handle(Smi::FromInt(103), isolate)},
3833 {"class C {\n"
3834 " constructor() { this.x_ = 0; }"
3835 " set x(value) { this.x_ = value; }\n"
3836 " get x() { return this.x_; }\n"
3837 "}\n"
3838 "var c = new C();"
3839 "c.x = 104;"
3840 "return c.x;",
3841 handle(Smi::FromInt(104), isolate)},
3842 {"var x = 0;"
3843 "class C {\n"
3844 " static set x(value) { x = value; }\n"
3845 " static get x() { return x; }\n"
3846 "}\n"
3847 "C.x = 105;"
3848 "return C.x;",
3849 handle(Smi::FromInt(105), isolate)},
3850 {"var method = 'f';"
3851 "class C {\n"
3852 " [method]() { return 106; }\n"
3853 "}\n"
3854 "return new C().f();",
3855 handle(Smi::FromInt(106), isolate)},
3856 };
3857
3858 for (size_t i = 0; i < arraysize(examples); ++i) {
3859 std::string source(InterpreterTester::SourceForBody(examples[i].first));
3860 InterpreterTester tester(handles.main_isolate(), source.c_str());
3861 auto callable = tester.GetCallable<>();
3862
3863 Handle<i::Object> return_value = callable().ToHandleChecked();
3864 CHECK(return_value->SameValue(*examples[i].second));
3865 }
3866}
3867
3868TEST(InterpreterClassAndSuperClass) {
3869 HandleAndZoneScope handles;
3870 i::Isolate* isolate = handles.main_isolate();
3871 std::pair<const char*, Handle<Object>> examples[] = {
3872 {"class A {\n"
3873 " constructor(x) { this.x_ = x; }\n"
3874 " method() { return this.x_; }\n"
3875 "}\n"
3876 "class B extends A {\n"
3877 " constructor(x, y) { super(x); this.y_ = y; }\n"
3878 " method() { return super.method() + 1; }\n"
3879 "}\n"
3880 "return new B(998, 0).method();\n",
3881 handle(Smi::FromInt(999), isolate)},
3882 {"class A {\n"
3883 " constructor() { this.x_ = 2; this.y_ = 3; }\n"
3884 "}\n"
3885 "class B extends A {\n"
3886 " constructor() { super(); }"
3887 " method() { this.x_++; this.y_++; return this.x_ + this.y_; }\n"
3888 "}\n"
3889 "return new B().method();\n",
3890 handle(Smi::FromInt(7), isolate)},
3891 {"var calls = 0;\n"
3892 "class B {}\n"
3893 "B.prototype.x = 42;\n"
3894 "class C extends B {\n"
3895 " constructor() {\n"
3896 " super();\n"
3897 " calls++;\n"
3898 " }\n"
3899 "}\n"
3900 "new C;\n"
3901 "return calls;\n",
3902 handle(Smi::FromInt(1), isolate)},
3903 {"class A {\n"
3904 " method() { return 1; }\n"
3905 " get x() { return 2; }\n"
3906 "}\n"
3907 "class B extends A {\n"
3908 " method() { return super.x === 2 ? super.method() : -1; }\n"
3909 "}\n"
3910 "return new B().method();\n",
3911 handle(Smi::FromInt(1), isolate)},
3912 {"var object = { setY(v) { super.y = v; }};\n"
3913 "object.setY(10);\n"
3914 "return object.y;\n",
3915 handle(Smi::FromInt(10), isolate)},
3916 };
3917
3918 for (size_t i = 0; i < arraysize(examples); ++i) {
3919 std::string source(InterpreterTester::SourceForBody(examples[i].first));
3920 InterpreterTester tester(handles.main_isolate(), source.c_str());
3921 auto callable = tester.GetCallable<>();
3922 Handle<i::Object> return_value = callable().ToHandleChecked();
3923 CHECK(return_value->SameValue(*examples[i].second));
3924 }
3925}
3926
3927TEST(InterpreterConstDeclaration) {
3928 HandleAndZoneScope handles;
3929 i::Isolate* isolate = handles.main_isolate();
3930 i::Factory* factory = isolate->factory();
3931
3932 std::pair<const char*, Handle<Object>> const_decl[] = {
3933 {"const x = 3; return x;", handle(Smi::FromInt(3), isolate)},
3934 {"let x = 10; x = x + 20; return x;", handle(Smi::FromInt(30), isolate)},
3935 {"let x = 10; x = 20; return x;", handle(Smi::FromInt(20), isolate)},
3936 {"let x; x = 20; return x;", handle(Smi::FromInt(20), isolate)},
3937 {"let x; return x;", factory->undefined_value()},
3938 {"var x = 10; { let x = 30; } return x;",
3939 handle(Smi::FromInt(10), isolate)},
3940 {"let x = 10; { let x = 20; } return x;",
3941 handle(Smi::FromInt(10), isolate)},
3942 {"var x = 10; eval('let x = 20;'); return x;",
3943 handle(Smi::FromInt(10), isolate)},
3944 {"var x = 10; eval('const x = 20;'); return x;",
3945 handle(Smi::FromInt(10), isolate)},
3946 {"var x = 10; { const x = 20; } return x;",
3947 handle(Smi::FromInt(10), isolate)},
3948 {"var x = 10; { const x = 20; return x;} return -1;",
3949 handle(Smi::FromInt(20), isolate)},
3950 {"var a = 10;\n"
3951 "for (var i = 0; i < 10; ++i) {\n"
3952 " const x = i;\n" // const declarations are block scoped.
3953 " a = a + x;\n"
3954 "}\n"
3955 "return a;\n",
3956 handle(Smi::FromInt(55), isolate)},
3957 };
3958
3959 // Tests for sloppy mode.
3960 for (size_t i = 0; i < arraysize(const_decl); i++) {
3961 std::string source(InterpreterTester::SourceForBody(const_decl[i].first));
3962 InterpreterTester tester(handles.main_isolate(), source.c_str());
3963 auto callable = tester.GetCallable<>();
3964
3965 Handle<i::Object> return_value = callable().ToHandleChecked();
3966 CHECK(return_value->SameValue(*const_decl[i].second));
3967 }
3968
3969 // Tests for strict mode.
3970 for (size_t i = 0; i < arraysize(const_decl); i++) {
3971 std::string strict_body =
3972 "'use strict'; " + std::string(const_decl[i].first);
3973 std::string source(InterpreterTester::SourceForBody(strict_body.c_str()));
3974 InterpreterTester tester(handles.main_isolate(), source.c_str());
3975 auto callable = tester.GetCallable<>();
3976
3977 Handle<i::Object> return_value = callable().ToHandleChecked();
3978 CHECK(return_value->SameValue(*const_decl[i].second));
3979 }
3980}
3981
3982TEST(InterpreterConstDeclarationLookupSlots) {
3983 HandleAndZoneScope handles;
3984 i::Isolate* isolate = handles.main_isolate();
3985 i::Factory* factory = isolate->factory();
3986
3987 std::pair<const char*, Handle<Object>> const_decl[] = {
3988 {"const x = 3; function f1() {return x;}; return x;",
3989 handle(Smi::FromInt(3), isolate)},
3990 {"let x = 10; x = x + 20; function f1() {return x;}; return x;",
3991 handle(Smi::FromInt(30), isolate)},
3992 {"let x; x = 20; function f1() {return x;}; return x;",
3993 handle(Smi::FromInt(20), isolate)},
3994 {"let x; function f1() {return x;}; return x;",
3995 factory->undefined_value()},
3996 };
3997
3998 // Tests for sloppy mode.
3999 for (size_t i = 0; i < arraysize(const_decl); i++) {
4000 std::string source(InterpreterTester::SourceForBody(const_decl[i].first));
4001 InterpreterTester tester(handles.main_isolate(), source.c_str());
4002 auto callable = tester.GetCallable<>();
4003
4004 Handle<i::Object> return_value = callable().ToHandleChecked();
4005 CHECK(return_value->SameValue(*const_decl[i].second));
4006 }
4007
4008 // Tests for strict mode.
4009 for (size_t i = 0; i < arraysize(const_decl); i++) {
4010 std::string strict_body =
4011 "'use strict'; " + std::string(const_decl[i].first);
4012 std::string source(InterpreterTester::SourceForBody(strict_body.c_str()));
4013 InterpreterTester tester(handles.main_isolate(), source.c_str());
4014 auto callable = tester.GetCallable<>();
4015
4016 Handle<i::Object> return_value = callable().ToHandleChecked();
4017 CHECK(return_value->SameValue(*const_decl[i].second));
4018 }
4019}
4020
4021TEST(InterpreterConstInLookupContextChain) {
4022 HandleAndZoneScope handles;
4023 i::Isolate* isolate = handles.main_isolate();
4024
4025 const char* prologue =
4026 "function OuterMost() {\n"
4027 " const outerConst = 10;\n"
4028 " let outerLet = 20;\n"
4029 " function Outer() {\n"
4030 " function Inner() {\n"
4031 " this.innerFunc = function() { ";
4032 const char* epilogue =
4033 " }\n"
4034 " }\n"
4035 " this.getInnerFunc ="
4036 " function() {return new Inner().innerFunc;}\n"
4037 " }\n"
4038 " this.getOuterFunc ="
4039 " function() {return new Outer().getInnerFunc();}"
4040 "}\n"
4041 "var f = new OuterMost().getOuterFunc();\n"
4042 "f();\n";
4043 std::pair<const char*, Handle<Object>> const_decl[] = {
4044 {"return outerConst;", handle(Smi::FromInt(10), isolate)},
4045 {"return outerLet;", handle(Smi::FromInt(20), isolate)},
4046 {"outerLet = 30; return outerLet;", handle(Smi::FromInt(30), isolate)},
4047 {"var outerLet = 40; return outerLet;",
4048 handle(Smi::FromInt(40), isolate)},
4049 {"var outerConst = 50; return outerConst;",
4050 handle(Smi::FromInt(50), isolate)},
4051 {"try { outerConst = 30 } catch(e) { return -1; }",
4052 handle(Smi::FromInt(-1), isolate)}};
4053
4054 for (size_t i = 0; i < arraysize(const_decl); i++) {
4055 std::string script = std::string(prologue) +
4056 std::string(const_decl[i].first) +
4057 std::string(epilogue);
4058 InterpreterTester tester(handles.main_isolate(), script.c_str(), "*");
4059 auto callable = tester.GetCallable<>();
4060
4061 Handle<i::Object> return_value = callable().ToHandleChecked();
4062 CHECK(return_value->SameValue(*const_decl[i].second));
4063 }
4064
4065 // Tests for Legacy constant.
4066 bool old_flag_legacy_const = FLAG_legacy_const;
4067 FLAG_legacy_const = true;
4068
4069 std::pair<const char*, Handle<Object>> legacy_const_decl[] = {
4070 {"return outerConst = 23;", handle(Smi::FromInt(23), isolate)},
4071 {"outerConst = 30; return outerConst;",
4072 handle(Smi::FromInt(10), isolate)},
4073 };
4074
4075 for (size_t i = 0; i < arraysize(legacy_const_decl); i++) {
4076 std::string script = std::string(prologue) +
4077 std::string(legacy_const_decl[i].first) +
4078 std::string(epilogue);
4079 InterpreterTester tester(handles.main_isolate(), script.c_str(), "*");
4080 auto callable = tester.GetCallable<>();
4081
4082 Handle<i::Object> return_value = callable().ToHandleChecked();
4083 CHECK(return_value->SameValue(*legacy_const_decl[i].second));
4084 }
4085
4086 FLAG_legacy_const = old_flag_legacy_const;
4087}
4088
4089TEST(InterpreterIllegalConstDeclaration) {
4090 HandleAndZoneScope handles;
4091
4092 std::pair<const char*, const char*> const_decl[] = {
4093 {"const x = x = 10 + 3; return x;",
4094 "Uncaught ReferenceError: x is not defined"},
4095 {"const x = 10; x = 20; return x;",
4096 "Uncaught TypeError: Assignment to constant variable."},
4097 {"const x = 10; { x = 20; } return x;",
4098 "Uncaught TypeError: Assignment to constant variable."},
4099 {"const x = 10; eval('x = 20;'); return x;",
4100 "Uncaught TypeError: Assignment to constant variable."},
4101 {"let x = x + 10; return x;",
4102 "Uncaught ReferenceError: x is not defined"},
4103 {"'use strict'; (function f1() { f1 = 123; })() ",
4104 "Uncaught TypeError: Assignment to constant variable."},
4105 };
4106
4107 // Tests for sloppy mode.
4108 for (size_t i = 0; i < arraysize(const_decl); i++) {
4109 std::string source(InterpreterTester::SourceForBody(const_decl[i].first));
4110 InterpreterTester tester(handles.main_isolate(), source.c_str());
4111 v8::Local<v8::String> message = tester.CheckThrowsReturnMessage()->Get();
4112 v8::Local<v8::String> expected_string = v8_str(const_decl[i].second);
4113 CHECK(
4114 message->Equals(CcTest::isolate()->GetCurrentContext(), expected_string)
4115 .FromJust());
4116 }
4117
4118 // Tests for strict mode.
4119 for (size_t i = 0; i < arraysize(const_decl); i++) {
4120 std::string strict_body =
4121 "'use strict'; " + std::string(const_decl[i].first);
4122 std::string source(InterpreterTester::SourceForBody(strict_body.c_str()));
4123 InterpreterTester tester(handles.main_isolate(), source.c_str());
4124 v8::Local<v8::String> message = tester.CheckThrowsReturnMessage()->Get();
4125 v8::Local<v8::String> expected_string = v8_str(const_decl[i].second);
4126 CHECK(
4127 message->Equals(CcTest::isolate()->GetCurrentContext(), expected_string)
4128 .FromJust());
4129 }
4130}
4131
4132TEST(InterpreterLegacyConstDeclaration) {
4133 bool old_flag_legacy_const = FLAG_legacy_const;
4134 FLAG_legacy_const = true;
4135
4136 HandleAndZoneScope handles;
4137 i::Isolate* isolate = handles.main_isolate();
4138
4139 std::pair<const char*, Handle<Object>> const_decl[] = {
4140 {"const x = (x = 10) + 3; return x;", handle(Smi::FromInt(13), isolate)},
4141 {"const x = 10; x = 20; return x;", handle(Smi::FromInt(10), isolate)},
4142 {"var a = 10;\n"
4143 "for (var i = 0; i < 10; ++i) {\n"
4144 " const x = i;\n" // Legacy constants are not block scoped.
4145 " a = a + x;\n"
4146 "}\n"
4147 "return a;\n",
4148 handle(Smi::FromInt(10), isolate)},
4149 {"const x = 20; eval('x = 10;'); return x;",
4150 handle(Smi::FromInt(20), isolate)},
4151 };
4152
4153 for (size_t i = 0; i < arraysize(const_decl); i++) {
4154 std::string source(InterpreterTester::SourceForBody(const_decl[i].first));
4155 InterpreterTester tester(handles.main_isolate(), source.c_str());
4156 auto callable = tester.GetCallable<>();
4157
4158 Handle<i::Object> return_value = callable().ToHandleChecked();
4159 CHECK(return_value->SameValue(*const_decl[i].second));
4160 }
4161
4162 FLAG_legacy_const = old_flag_legacy_const;
4163}
4164
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00004165} // namespace interpreter
4166} // namespace internal
4167} // namespace v8