Line data Source code
1 : // Copyright 2015 the V8 project authors. All rights reserved.
2 : // Use of this source code is governed by a BSD-style license that can be
3 : // found in the LICENSE file.
4 :
5 : #include "src/code-factory.h"
6 : #include "src/compiler/code-assembler.h"
7 : #include "src/compiler/node-properties.h"
8 : #include "src/compiler/opcodes.h"
9 : #include "src/isolate.h"
10 : #include "src/objects-inl.h"
11 : #include "test/cctest/compiler/code-assembler-tester.h"
12 : #include "test/cctest/compiler/function-tester.h"
13 :
14 : namespace v8 {
15 : namespace internal {
16 : namespace compiler {
17 :
18 : namespace {
19 :
20 : typedef CodeAssemblerLabel Label;
21 : typedef CodeAssemblerVariable Variable;
22 :
23 78 : Node* SmiTag(CodeAssembler& m, Node* value) {
24 : int32_t constant_value;
25 78 : if (m.ToInt32Constant(value, constant_value) &&
26 : Smi::IsValid(constant_value)) {
27 234 : return m.SmiConstant(Smi::FromInt(constant_value));
28 : }
29 0 : return m.WordShl(value, m.IntPtrConstant(kSmiShiftSize + kSmiTagSize));
30 : }
31 :
32 : Node* UndefinedConstant(CodeAssembler& m) {
33 48 : return m.LoadRoot(Heap::kUndefinedValueRootIndex);
34 : }
35 :
36 12 : Node* SmiFromWord32(CodeAssembler& m, Node* value) {
37 24 : value = m.ChangeInt32ToIntPtr(value);
38 : return m.BitcastWordToTaggedSigned(
39 36 : m.WordShl(value, kSmiShiftSize + kSmiTagSize));
40 : }
41 :
42 6 : Node* LoadObjectField(CodeAssembler& m, Node* object, int offset,
43 : MachineType rep = MachineType::AnyTagged()) {
44 12 : return m.Load(rep, object, m.IntPtrConstant(offset - kHeapObjectTag));
45 : }
46 :
47 : Node* LoadMap(CodeAssembler& m, Node* object) {
48 6 : return LoadObjectField(m, object, JSObject::kMapOffset);
49 : }
50 :
51 : } // namespace
52 :
53 23724 : TEST(SimpleSmiReturn) {
54 6 : Isolate* isolate(CcTest::InitIsolateOnce());
55 6 : CodeAssemblerTester asm_tester(isolate);
56 6 : CodeAssembler m(asm_tester.state());
57 18 : m.Return(SmiTag(m, m.Int32Constant(37)));
58 6 : FunctionTester ft(asm_tester.GenerateCode());
59 18 : CHECK_EQ(37, ft.CallChecked<Smi>()->value());
60 6 : }
61 :
62 23724 : TEST(SimpleIntPtrReturn) {
63 6 : Isolate* isolate(CcTest::InitIsolateOnce());
64 6 : CodeAssemblerTester asm_tester(isolate);
65 6 : CodeAssembler m(asm_tester.state());
66 : int test;
67 : m.Return(m.BitcastWordToTagged(
68 18 : m.IntPtrConstant(reinterpret_cast<intptr_t>(&test))));
69 6 : FunctionTester ft(asm_tester.GenerateCode());
70 6 : MaybeHandle<Object> result = ft.Call();
71 6 : CHECK_EQ(reinterpret_cast<intptr_t>(&test),
72 6 : reinterpret_cast<intptr_t>(*result.ToHandleChecked()));
73 6 : }
74 :
75 23724 : TEST(SimpleDoubleReturn) {
76 6 : Isolate* isolate(CcTest::InitIsolateOnce());
77 6 : CodeAssemblerTester asm_tester(isolate);
78 6 : CodeAssembler m(asm_tester.state());
79 12 : m.Return(m.NumberConstant(0.5));
80 6 : FunctionTester ft(asm_tester.GenerateCode());
81 18 : CHECK_EQ(0.5, ft.CallChecked<HeapNumber>()->value());
82 6 : }
83 :
84 23724 : TEST(SimpleCallRuntime1Arg) {
85 6 : Isolate* isolate(CcTest::InitIsolateOnce());
86 6 : CodeAssemblerTester asm_tester(isolate);
87 6 : CodeAssembler m(asm_tester.state());
88 6 : Node* context = m.HeapConstant(Handle<Context>(isolate->native_context()));
89 12 : Node* b = SmiTag(m, m.Int32Constant(0));
90 6 : m.Return(m.CallRuntime(Runtime::kNumberToSmi, context, b));
91 6 : FunctionTester ft(asm_tester.GenerateCode());
92 18 : CHECK_EQ(0, ft.CallChecked<Smi>()->value());
93 6 : }
94 :
95 23724 : TEST(SimpleTailCallRuntime1Arg) {
96 6 : Isolate* isolate(CcTest::InitIsolateOnce());
97 6 : CodeAssemblerTester asm_tester(isolate);
98 6 : CodeAssembler m(asm_tester.state());
99 6 : Node* context = m.HeapConstant(Handle<Context>(isolate->native_context()));
100 12 : Node* b = SmiTag(m, m.Int32Constant(0));
101 : m.TailCallRuntime(Runtime::kNumberToSmi, context, b);
102 6 : FunctionTester ft(asm_tester.GenerateCode());
103 18 : CHECK_EQ(0, ft.CallChecked<Smi>()->value());
104 6 : }
105 :
106 23724 : TEST(SimpleCallRuntime2Arg) {
107 6 : Isolate* isolate(CcTest::InitIsolateOnce());
108 6 : CodeAssemblerTester asm_tester(isolate);
109 6 : CodeAssembler m(asm_tester.state());
110 6 : Node* context = m.HeapConstant(Handle<Context>(isolate->native_context()));
111 12 : Node* a = SmiTag(m, m.Int32Constant(2));
112 12 : Node* b = SmiTag(m, m.Int32Constant(4));
113 6 : m.Return(m.CallRuntime(Runtime::kAdd, context, a, b));
114 6 : FunctionTester ft(asm_tester.GenerateCode());
115 18 : CHECK_EQ(6, ft.CallChecked<Smi>()->value());
116 6 : }
117 :
118 23724 : TEST(SimpleTailCallRuntime2Arg) {
119 6 : Isolate* isolate(CcTest::InitIsolateOnce());
120 6 : CodeAssemblerTester asm_tester(isolate);
121 6 : CodeAssembler m(asm_tester.state());
122 6 : Node* context = m.HeapConstant(Handle<Context>(isolate->native_context()));
123 12 : Node* a = SmiTag(m, m.Int32Constant(2));
124 12 : Node* b = SmiTag(m, m.Int32Constant(4));
125 : m.TailCallRuntime(Runtime::kAdd, context, a, b);
126 6 : FunctionTester ft(asm_tester.GenerateCode());
127 18 : CHECK_EQ(6, ft.CallChecked<Smi>()->value());
128 6 : }
129 :
130 : namespace {
131 :
132 : Handle<JSFunction> CreateSumAllArgumentsFunction(FunctionTester& ft) {
133 : const char* source =
134 : "(function() {\n"
135 : " var sum = 0 + this;\n"
136 : " for (var i = 0; i < arguments.length; i++) {\n"
137 : " sum += arguments[i];\n"
138 : " }\n"
139 : " return sum;\n"
140 : "})";
141 18 : return ft.NewFunction(source);
142 : }
143 :
144 : } // namespace
145 :
146 23724 : TEST(SimpleCallJSFunction0Arg) {
147 6 : Isolate* isolate(CcTest::InitIsolateOnce());
148 : const int kNumParams = 1;
149 6 : CodeAssemblerTester asm_tester(isolate, kNumParams);
150 6 : CodeAssembler m(asm_tester.state());
151 : {
152 6 : Node* function = m.Parameter(0);
153 6 : Node* context = m.Parameter(kNumParams + 2);
154 :
155 12 : Node* receiver = SmiTag(m, m.Int32Constant(42));
156 :
157 6 : Callable callable = CodeFactory::Call(isolate);
158 6 : Node* result = m.CallJS(callable, context, function, receiver);
159 6 : m.Return(result);
160 : }
161 6 : FunctionTester ft(asm_tester.GenerateCode(), kNumParams);
162 :
163 6 : Handle<JSFunction> sum = CreateSumAllArgumentsFunction(ft);
164 6 : MaybeHandle<Object> result = ft.Call(sum);
165 12 : CHECK_EQ(Smi::FromInt(42), *result.ToHandleChecked());
166 6 : }
167 :
168 23724 : TEST(SimpleCallJSFunction1Arg) {
169 6 : Isolate* isolate(CcTest::InitIsolateOnce());
170 : const int kNumParams = 2;
171 6 : CodeAssemblerTester asm_tester(isolate, kNumParams);
172 6 : CodeAssembler m(asm_tester.state());
173 : {
174 6 : Node* function = m.Parameter(0);
175 6 : Node* context = m.Parameter(1);
176 :
177 12 : Node* receiver = SmiTag(m, m.Int32Constant(42));
178 12 : Node* a = SmiTag(m, m.Int32Constant(13));
179 :
180 6 : Callable callable = CodeFactory::Call(isolate);
181 6 : Node* result = m.CallJS(callable, context, function, receiver, a);
182 6 : m.Return(result);
183 : }
184 6 : FunctionTester ft(asm_tester.GenerateCode(), kNumParams);
185 :
186 6 : Handle<JSFunction> sum = CreateSumAllArgumentsFunction(ft);
187 6 : MaybeHandle<Object> result = ft.Call(sum);
188 12 : CHECK_EQ(Smi::FromInt(55), *result.ToHandleChecked());
189 6 : }
190 :
191 23724 : TEST(SimpleCallJSFunction2Arg) {
192 6 : Isolate* isolate(CcTest::InitIsolateOnce());
193 : const int kNumParams = 2;
194 6 : CodeAssemblerTester asm_tester(isolate, kNumParams);
195 6 : CodeAssembler m(asm_tester.state());
196 : {
197 6 : Node* function = m.Parameter(0);
198 6 : Node* context = m.Parameter(1);
199 :
200 12 : Node* receiver = SmiTag(m, m.Int32Constant(42));
201 12 : Node* a = SmiTag(m, m.Int32Constant(13));
202 12 : Node* b = SmiTag(m, m.Int32Constant(153));
203 :
204 6 : Callable callable = CodeFactory::Call(isolate);
205 6 : Node* result = m.CallJS(callable, context, function, receiver, a, b);
206 6 : m.Return(result);
207 : }
208 6 : FunctionTester ft(asm_tester.GenerateCode(), kNumParams);
209 :
210 6 : Handle<JSFunction> sum = CreateSumAllArgumentsFunction(ft);
211 6 : MaybeHandle<Object> result = ft.Call(sum);
212 12 : CHECK_EQ(Smi::FromInt(208), *result.ToHandleChecked());
213 6 : }
214 :
215 23724 : TEST(VariableMerge1) {
216 6 : Isolate* isolate(CcTest::InitIsolateOnce());
217 6 : CodeAssemblerTester asm_tester(isolate);
218 6 : CodeAssembler m(asm_tester.state());
219 12 : Variable var1(&m, MachineRepresentation::kTagged);
220 6 : Label l1(&m), l2(&m), merge(&m);
221 12 : Node* temp = m.Int32Constant(0);
222 6 : var1.Bind(temp);
223 12 : m.Branch(m.Int32Constant(1), &l1, &l2);
224 6 : m.Bind(&l1);
225 6 : CHECK_EQ(var1.value(), temp);
226 6 : m.Goto(&merge);
227 6 : m.Bind(&l2);
228 6 : CHECK_EQ(var1.value(), temp);
229 6 : m.Goto(&merge);
230 6 : m.Bind(&merge);
231 12 : CHECK_EQ(var1.value(), temp);
232 6 : }
233 :
234 23724 : TEST(VariableMerge2) {
235 6 : Isolate* isolate(CcTest::InitIsolateOnce());
236 6 : CodeAssemblerTester asm_tester(isolate);
237 6 : CodeAssembler m(asm_tester.state());
238 12 : Variable var1(&m, MachineRepresentation::kTagged);
239 6 : Label l1(&m), l2(&m), merge(&m);
240 12 : Node* temp = m.Int32Constant(0);
241 6 : var1.Bind(temp);
242 12 : m.Branch(m.Int32Constant(1), &l1, &l2);
243 6 : m.Bind(&l1);
244 6 : CHECK_EQ(var1.value(), temp);
245 6 : m.Goto(&merge);
246 6 : m.Bind(&l2);
247 12 : Node* temp2 = m.Int32Constant(2);
248 6 : var1.Bind(temp2);
249 6 : CHECK_EQ(var1.value(), temp2);
250 6 : m.Goto(&merge);
251 6 : m.Bind(&merge);
252 12 : CHECK_NE(var1.value(), temp);
253 6 : }
254 :
255 23724 : TEST(VariableMerge3) {
256 6 : Isolate* isolate(CcTest::InitIsolateOnce());
257 6 : CodeAssemblerTester asm_tester(isolate);
258 6 : CodeAssembler m(asm_tester.state());
259 12 : Variable var1(&m, MachineRepresentation::kTagged);
260 12 : Variable var2(&m, MachineRepresentation::kTagged);
261 6 : Label l1(&m), l2(&m), merge(&m);
262 12 : Node* temp = m.Int32Constant(0);
263 6 : var1.Bind(temp);
264 6 : var2.Bind(temp);
265 12 : m.Branch(m.Int32Constant(1), &l1, &l2);
266 6 : m.Bind(&l1);
267 6 : CHECK_EQ(var1.value(), temp);
268 6 : m.Goto(&merge);
269 6 : m.Bind(&l2);
270 12 : Node* temp2 = m.Int32Constant(2);
271 6 : var1.Bind(temp2);
272 6 : CHECK_EQ(var1.value(), temp2);
273 6 : m.Goto(&merge);
274 6 : m.Bind(&merge);
275 6 : CHECK_NE(var1.value(), temp);
276 6 : CHECK_NE(var1.value(), temp2);
277 12 : CHECK_EQ(var2.value(), temp);
278 6 : }
279 :
280 23724 : TEST(VariableMergeBindFirst) {
281 6 : Isolate* isolate(CcTest::InitIsolateOnce());
282 6 : CodeAssemblerTester asm_tester(isolate);
283 6 : CodeAssembler m(asm_tester.state());
284 12 : Variable var1(&m, MachineRepresentation::kTagged);
285 6 : Label l1(&m), l2(&m), merge(&m, &var1), end(&m);
286 12 : Node* temp = m.Int32Constant(0);
287 6 : var1.Bind(temp);
288 12 : m.Branch(m.Int32Constant(1), &l1, &l2);
289 6 : m.Bind(&l1);
290 6 : CHECK_EQ(var1.value(), temp);
291 6 : m.Goto(&merge);
292 6 : m.Bind(&merge);
293 6 : CHECK(var1.value() != temp);
294 6 : CHECK_NOT_NULL(var1.value());
295 6 : m.Goto(&end);
296 6 : m.Bind(&l2);
297 12 : Node* temp2 = m.Int32Constant(2);
298 6 : var1.Bind(temp2);
299 6 : CHECK_EQ(var1.value(), temp2);
300 6 : m.Goto(&merge);
301 6 : m.Bind(&end);
302 6 : CHECK(var1.value() != temp);
303 12 : CHECK_NOT_NULL(var1.value());
304 6 : }
305 :
306 23724 : TEST(VariableMergeSwitch) {
307 6 : Isolate* isolate(CcTest::InitIsolateOnce());
308 6 : CodeAssemblerTester asm_tester(isolate);
309 6 : CodeAssembler m(asm_tester.state());
310 12 : Variable var1(&m, MachineRepresentation::kTagged);
311 6 : Label l1(&m), l2(&m), default_label(&m);
312 6 : Label* labels[] = {&l1, &l2};
313 6 : int32_t values[] = {1, 2};
314 12 : Node* temp1 = m.Int32Constant(0);
315 6 : var1.Bind(temp1);
316 12 : m.Switch(m.Int32Constant(2), &default_label, values, labels, 2);
317 6 : m.Bind(&l1);
318 6 : CHECK_EQ(temp1, var1.value());
319 6 : m.Return(temp1);
320 6 : m.Bind(&l2);
321 6 : CHECK_EQ(temp1, var1.value());
322 12 : Node* temp2 = m.Int32Constant(7);
323 6 : var1.Bind(temp2);
324 6 : m.Goto(&default_label);
325 6 : m.Bind(&default_label);
326 12 : CHECK_EQ(IrOpcode::kPhi, var1.value()->opcode());
327 6 : CHECK_EQ(2, var1.value()->op()->ValueInputCount());
328 6 : CHECK_EQ(temp1, NodeProperties::GetValueInput(var1.value(), 0));
329 6 : CHECK_EQ(temp2, NodeProperties::GetValueInput(var1.value(), 1));
330 12 : m.Return(temp1);
331 6 : }
332 :
333 23724 : TEST(SplitEdgeBranchMerge) {
334 6 : Isolate* isolate(CcTest::InitIsolateOnce());
335 6 : CodeAssemblerTester asm_tester(isolate);
336 6 : CodeAssembler m(asm_tester.state());
337 6 : Label l1(&m), merge(&m);
338 12 : m.Branch(m.Int32Constant(1), &l1, &merge);
339 6 : m.Bind(&l1);
340 6 : m.Goto(&merge);
341 6 : m.Bind(&merge);
342 6 : USE(asm_tester.GenerateCode());
343 6 : }
344 :
345 23724 : TEST(SplitEdgeSwitchMerge) {
346 6 : Isolate* isolate(CcTest::InitIsolateOnce());
347 6 : CodeAssemblerTester asm_tester(isolate);
348 6 : CodeAssembler m(asm_tester.state());
349 6 : Label l1(&m), l2(&m), l3(&m), default_label(&m);
350 6 : Label* labels[] = {&l1, &l2};
351 6 : int32_t values[] = {1, 2};
352 12 : m.Branch(m.Int32Constant(1), &l3, &l1);
353 6 : m.Bind(&l3);
354 12 : m.Switch(m.Int32Constant(2), &default_label, values, labels, 2);
355 6 : m.Bind(&l1);
356 6 : m.Goto(&l2);
357 6 : m.Bind(&l2);
358 6 : m.Goto(&default_label);
359 6 : m.Bind(&default_label);
360 6 : USE(asm_tester.GenerateCode());
361 6 : }
362 :
363 23724 : TEST(TestToConstant) {
364 6 : Isolate* isolate(CcTest::InitIsolateOnce());
365 6 : CodeAssemblerTester asm_tester(isolate);
366 6 : CodeAssembler m(asm_tester.state());
367 : int32_t value32;
368 : int64_t value64;
369 12 : Node* a = m.Int32Constant(5);
370 6 : CHECK(m.ToInt32Constant(a, value32));
371 6 : CHECK(m.ToInt64Constant(a, value64));
372 :
373 12 : a = m.Int64Constant(static_cast<int64_t>(1) << 32);
374 6 : CHECK(!m.ToInt32Constant(a, value32));
375 6 : CHECK(m.ToInt64Constant(a, value64));
376 :
377 12 : a = m.Int64Constant(13);
378 6 : CHECK(m.ToInt32Constant(a, value32));
379 6 : CHECK(m.ToInt64Constant(a, value64));
380 :
381 : a = UndefinedConstant(m);
382 6 : CHECK(!m.ToInt32Constant(a, value32));
383 6 : CHECK(!m.ToInt64Constant(a, value64));
384 :
385 : a = UndefinedConstant(m);
386 6 : CHECK(!m.ToInt32Constant(a, value32));
387 12 : CHECK(!m.ToInt64Constant(a, value64));
388 6 : }
389 :
390 23724 : TEST(DeferredCodePhiHints) {
391 6 : Isolate* isolate(CcTest::InitIsolateOnce());
392 6 : CodeAssemblerTester asm_tester(isolate);
393 6 : CodeAssembler m(asm_tester.state());
394 6 : Label block1(&m, Label::kDeferred);
395 6 : m.Goto(&block1);
396 6 : m.Bind(&block1);
397 : {
398 6 : Variable var_object(&m, MachineRepresentation::kTagged);
399 6 : Label loop(&m, &var_object);
400 12 : var_object.Bind(m.SmiConstant(0));
401 6 : m.Goto(&loop);
402 6 : m.Bind(&loop);
403 : {
404 6 : Node* map = LoadMap(m, var_object.value());
405 6 : var_object.Bind(map);
406 6 : m.Goto(&loop);
407 6 : }
408 : }
409 12 : CHECK(!asm_tester.GenerateCode().is_null());
410 6 : }
411 :
412 23724 : TEST(TestOutOfScopeVariable) {
413 6 : Isolate* isolate(CcTest::InitIsolateOnce());
414 6 : CodeAssemblerTester asm_tester(isolate);
415 6 : CodeAssembler m(asm_tester.state());
416 6 : Label block1(&m);
417 6 : Label block2(&m);
418 6 : Label block3(&m);
419 6 : Label block4(&m);
420 6 : m.Branch(m.WordEqual(m.UncheckedCast<IntPtrT>(m.Parameter(0)),
421 12 : m.IntPtrConstant(0)),
422 12 : &block1, &block4);
423 6 : m.Bind(&block4);
424 : {
425 6 : Variable var_object(&m, MachineRepresentation::kTagged);
426 6 : m.Branch(m.WordEqual(m.UncheckedCast<IntPtrT>(m.Parameter(0)),
427 12 : m.IntPtrConstant(0)),
428 12 : &block2, &block3);
429 :
430 6 : m.Bind(&block2);
431 12 : var_object.Bind(m.IntPtrConstant(55));
432 6 : m.Goto(&block1);
433 :
434 6 : m.Bind(&block3);
435 12 : var_object.Bind(m.IntPtrConstant(66));
436 6 : m.Goto(&block1);
437 : }
438 6 : m.Bind(&block1);
439 12 : CHECK(!asm_tester.GenerateCode().is_null());
440 6 : }
441 :
442 23724 : TEST(GotoIfException) {
443 6 : Isolate* isolate(CcTest::InitIsolateOnce());
444 :
445 : const int kNumParams = 1;
446 6 : CodeAssemblerTester asm_tester(isolate, kNumParams);
447 6 : CodeAssembler m(asm_tester.state());
448 :
449 6 : Node* context = m.HeapConstant(Handle<Context>(isolate->native_context()));
450 : Node* to_string_tag =
451 : m.HeapConstant(isolate->factory()->to_string_tag_symbol());
452 12 : Variable exception(&m, MachineRepresentation::kTagged);
453 :
454 6 : Label exception_handler(&m);
455 6 : Callable to_string = Builtins::CallableFor(isolate, Builtins::kToString);
456 6 : Node* string = m.CallStub(to_string, context, to_string_tag);
457 6 : m.GotoIfException(string, &exception_handler, &exception);
458 6 : m.Return(string);
459 :
460 6 : m.Bind(&exception_handler);
461 12 : m.Return(exception.value());
462 :
463 6 : FunctionTester ft(asm_tester.GenerateCode(), kNumParams);
464 12 : Handle<Object> result = ft.Call().ToHandleChecked();
465 :
466 : // Should be a TypeError.
467 6 : CHECK(result->IsJSObject());
468 :
469 : Handle<Object> constructor =
470 : Object::GetPropertyOrElement(result,
471 6 : isolate->factory()->constructor_string())
472 12 : .ToHandleChecked();
473 18 : CHECK(constructor->SameValue(*isolate->type_error_function()));
474 6 : }
475 :
476 23724 : TEST(GotoIfExceptionMultiple) {
477 6 : Isolate* isolate(CcTest::InitIsolateOnce());
478 :
479 : const int kNumParams = 4; // receiver, first, second, third
480 6 : CodeAssemblerTester asm_tester(isolate, kNumParams);
481 6 : CodeAssembler m(asm_tester.state());
482 :
483 6 : Node* context = m.HeapConstant(Handle<Context>(isolate->native_context()));
484 6 : Node* first_value = m.Parameter(0);
485 6 : Node* second_value = m.Parameter(1);
486 6 : Node* third_value = m.Parameter(2);
487 :
488 6 : Label exception_handler1(&m);
489 6 : Label exception_handler2(&m);
490 6 : Label exception_handler3(&m);
491 12 : Variable return_value(&m, MachineRepresentation::kWord32);
492 12 : Variable error(&m, MachineRepresentation::kTagged);
493 :
494 12 : return_value.Bind(m.Int32Constant(0));
495 :
496 : // try { return ToString(param1) } catch (e) { ... }
497 6 : Callable to_string = Builtins::CallableFor(isolate, Builtins::kToString);
498 6 : Node* string = m.CallStub(to_string, context, first_value);
499 6 : m.GotoIfException(string, &exception_handler1, &error);
500 6 : m.Return(string);
501 :
502 : // try { ToString(param2); return 7 } catch (e) { ... }
503 6 : m.Bind(&exception_handler1);
504 12 : return_value.Bind(m.Int32Constant(7));
505 6 : error.Bind(UndefinedConstant(m));
506 6 : string = m.CallStub(to_string, context, second_value);
507 6 : m.GotoIfException(string, &exception_handler2, &error);
508 12 : m.Return(SmiFromWord32(m, return_value.value()));
509 :
510 : // try { ToString(param3); return 7 & ~2; } catch (e) { return e; }
511 6 : m.Bind(&exception_handler2);
512 : // Return returnValue & ~2
513 6 : error.Bind(UndefinedConstant(m));
514 6 : string = m.CallStub(to_string, context, third_value);
515 6 : m.GotoIfException(string, &exception_handler3, &error);
516 : m.Return(SmiFromWord32(
517 : m, m.Word32And(return_value.value(),
518 42 : m.Word32Xor(m.Int32Constant(2), m.Int32Constant(-1)))));
519 :
520 6 : m.Bind(&exception_handler3);
521 12 : m.Return(error.value());
522 :
523 6 : FunctionTester ft(asm_tester.GenerateCode(), kNumParams);
524 :
525 : Handle<Object> result;
526 : // First handler does not throw, returns result of first value.
527 : result = ft.Call(isolate->factory()->undefined_value(),
528 : isolate->factory()->to_string_tag_symbol())
529 12 : .ToHandleChecked();
530 6 : CHECK(String::cast(*result)->IsOneByteEqualTo(OneByteVector("undefined")));
531 :
532 : // First handler returns a number.
533 : result = ft.Call(isolate->factory()->to_string_tag_symbol(),
534 : isolate->factory()->undefined_value())
535 12 : .ToHandleChecked();
536 6 : CHECK_EQ(7, Smi::ToInt(*result));
537 :
538 : // First handler throws, second handler returns a number.
539 : result = ft.Call(isolate->factory()->to_string_tag_symbol(),
540 : isolate->factory()->to_primitive_symbol())
541 12 : .ToHandleChecked();
542 6 : CHECK_EQ(7 & ~2, Smi::ToInt(*result));
543 :
544 : // First handler throws, second handler throws, third handler returns thrown
545 : // value.
546 : result = ft.Call(isolate->factory()->to_string_tag_symbol(),
547 : isolate->factory()->to_primitive_symbol(),
548 : isolate->factory()->unscopables_symbol())
549 12 : .ToHandleChecked();
550 :
551 : // Should be a TypeError.
552 6 : CHECK(result->IsJSObject());
553 :
554 : Handle<Object> constructor =
555 : Object::GetPropertyOrElement(result,
556 6 : isolate->factory()->constructor_string())
557 12 : .ToHandleChecked();
558 18 : CHECK(constructor->SameValue(*isolate->type_error_function()));
559 6 : }
560 :
561 : } // namespace compiler
562 : } // namespace internal
563 71154 : } // namespace v8
|