1 // Copyright 2014 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/interpreter/bytecode-array-builder.h"
8 #include "src/interpreter/bytecode-array-iterator.h"
9 #include "src/interpreter/bytecode-register-allocator.h"
10 #include "test/unittests/test-utils.h"
11 
12 namespace v8 {
13 namespace internal {
14 namespace interpreter {
15 
16 class BytecodeArrayBuilderTest : public TestWithIsolateAndZone {
17  public:
BytecodeArrayBuilderTest()18   BytecodeArrayBuilderTest() {}
~BytecodeArrayBuilderTest()19   ~BytecodeArrayBuilderTest() override {}
20 };
21 
22 
TEST_F(BytecodeArrayBuilderTest,AllBytecodesGenerated)23 TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) {
24   BytecodeArrayBuilder builder(isolate(), zone());
25 
26   builder.set_locals_count(200);
27   builder.set_context_count(1);
28   builder.set_parameter_count(0);
29   CHECK_EQ(builder.locals_count(), 200);
30   CHECK_EQ(builder.context_count(), 1);
31   CHECK_EQ(builder.fixed_register_count(), 201);
32 
33   // Emit constant loads.
34   builder.LoadLiteral(Smi::FromInt(0))
35       .LoadLiteral(Smi::FromInt(8))
36       .LoadLiteral(Smi::FromInt(10000000))
37       .LoadUndefined()
38       .LoadNull()
39       .LoadTheHole()
40       .LoadTrue()
41       .LoadFalse();
42 
43   // Emit accumulator transfers. Stores followed by loads to the same register
44   // are not generated. Hence, a dummy instruction in between.
45   Register reg(0);
46   builder.LoadAccumulatorWithRegister(reg)
47       .LoadNull()
48       .StoreAccumulatorInRegister(reg);
49 
50   // Emit register-register transfer.
51   Register other(1);
52   builder.MoveRegister(reg, other);
53 
54   // Emit register-register exchanges.
55   Register wide(150);
56   builder.ExchangeRegisters(reg, wide);
57   builder.ExchangeRegisters(wide, reg);
58   Register wider(151);
59   builder.ExchangeRegisters(wide, wider);
60 
61   // Emit global load / store operations.
62   Factory* factory = isolate()->factory();
63   Handle<String> name = factory->NewStringFromStaticChars("var_name");
64   builder.LoadGlobal(name, 1, LanguageMode::SLOPPY,
65                      TypeofMode::NOT_INSIDE_TYPEOF)
66       .LoadGlobal(name, 1, LanguageMode::STRICT, TypeofMode::NOT_INSIDE_TYPEOF)
67       .LoadGlobal(name, 1, LanguageMode::SLOPPY, TypeofMode::INSIDE_TYPEOF)
68       .LoadGlobal(name, 1, LanguageMode::STRICT, TypeofMode::INSIDE_TYPEOF)
69       .StoreGlobal(name, 1, LanguageMode::SLOPPY)
70       .StoreGlobal(name, 1, LanguageMode::STRICT);
71 
72   // Emit context operations.
73   builder.PushContext(reg)
74       .PopContext(reg)
75       .LoadContextSlot(reg, 1)
76       .StoreContextSlot(reg, 1);
77 
78   // Emit load / store property operations.
79   builder.LoadNamedProperty(reg, name, 0, LanguageMode::SLOPPY)
80       .LoadKeyedProperty(reg, 0, LanguageMode::SLOPPY)
81       .StoreNamedProperty(reg, name, 0, LanguageMode::SLOPPY)
82       .StoreKeyedProperty(reg, reg, 0, LanguageMode::SLOPPY)
83       .LoadNamedProperty(reg, name, 0, LanguageMode::STRICT)
84       .LoadKeyedProperty(reg, 0, LanguageMode::STRICT)
85       .StoreNamedProperty(reg, name, 0, LanguageMode::STRICT)
86       .StoreKeyedProperty(reg, reg, 0, LanguageMode::STRICT);
87 
88   // Emit load / store lookup slots.
89   builder.LoadLookupSlot(name, TypeofMode::NOT_INSIDE_TYPEOF)
90       .LoadLookupSlot(name, TypeofMode::INSIDE_TYPEOF)
91       .StoreLookupSlot(name, LanguageMode::SLOPPY)
92       .StoreLookupSlot(name, LanguageMode::STRICT);
93 
94   // Emit closure operations.
95   Handle<SharedFunctionInfo> shared_info = factory->NewSharedFunctionInfo(
96       factory->NewStringFromStaticChars("function_a"), MaybeHandle<Code>(),
97       false);
98   builder.CreateClosure(shared_info, NOT_TENURED);
99 
100   // Emit argument creation operations.
101   builder.CreateArguments(CreateArgumentsType::kMappedArguments)
102       .CreateArguments(CreateArgumentsType::kUnmappedArguments);
103 
104   // Emit literal creation operations.
105   builder.CreateRegExpLiteral(factory->NewStringFromStaticChars("a"), 0, 0)
106       .CreateArrayLiteral(factory->NewFixedArray(1), 0, 0)
107       .CreateObjectLiteral(factory->NewFixedArray(1), 0, 0);
108 
109   // Call operations.
110   builder.Call(reg, reg, 0, 0)
111       .Call(reg, reg, 0, 1024)
112       .CallRuntime(Runtime::kIsArray, reg, 1)
113       .CallRuntimeForPair(Runtime::kLoadLookupSlot, reg, 1, reg)
114       .CallJSRuntime(Context::SPREAD_ITERABLE_INDEX, reg, 1);
115 
116   // Emit binary operator invocations.
117   builder.BinaryOperation(Token::Value::ADD, reg, Strength::WEAK)
118       .BinaryOperation(Token::Value::SUB, reg, Strength::WEAK)
119       .BinaryOperation(Token::Value::MUL, reg, Strength::WEAK)
120       .BinaryOperation(Token::Value::DIV, reg, Strength::WEAK)
121       .BinaryOperation(Token::Value::MOD, reg, Strength::WEAK);
122 
123   // Emit bitwise operator invocations
124   builder.BinaryOperation(Token::Value::BIT_OR, reg, Strength::WEAK)
125       .BinaryOperation(Token::Value::BIT_XOR, reg, Strength::WEAK)
126       .BinaryOperation(Token::Value::BIT_AND, reg, Strength::WEAK);
127 
128   // Emit shift operator invocations
129   builder.BinaryOperation(Token::Value::SHL, reg, Strength::WEAK)
130       .BinaryOperation(Token::Value::SAR, reg, Strength::WEAK)
131       .BinaryOperation(Token::Value::SHR, reg, Strength::WEAK);
132 
133   // Emit count operatior invocations
134   builder.CountOperation(Token::Value::ADD, Strength::WEAK)
135       .CountOperation(Token::Value::SUB, Strength::WEAK);
136 
137   // Emit unary operator invocations.
138   builder.LogicalNot().TypeOf();
139 
140   // Emit delete
141   builder.Delete(reg, LanguageMode::SLOPPY)
142       .Delete(reg, LanguageMode::STRICT)
143       .DeleteLookupSlot();
144 
145   // Emit new.
146   builder.New(reg, reg, 0);
147 
148   // Emit test operator invocations.
149   builder.CompareOperation(Token::Value::EQ, reg, Strength::WEAK)
150       .CompareOperation(Token::Value::NE, reg, Strength::WEAK)
151       .CompareOperation(Token::Value::EQ_STRICT, reg, Strength::WEAK)
152       .CompareOperation(Token::Value::NE_STRICT, reg, Strength::WEAK)
153       .CompareOperation(Token::Value::LT, reg, Strength::WEAK)
154       .CompareOperation(Token::Value::GT, reg, Strength::WEAK)
155       .CompareOperation(Token::Value::LTE, reg, Strength::WEAK)
156       .CompareOperation(Token::Value::GTE, reg, Strength::WEAK)
157       .CompareOperation(Token::Value::INSTANCEOF, reg, Strength::WEAK)
158       .CompareOperation(Token::Value::IN, reg, Strength::WEAK);
159 
160   // Emit cast operator invocations.
161   builder.CastAccumulatorToNumber()
162       .CastAccumulatorToJSObject()
163       .CastAccumulatorToName();
164 
165   // Emit control flow. Return must be the last instruction.
166   BytecodeLabel start;
167   builder.Bind(&start);
168   // Short jumps with Imm8 operands
169   builder.Jump(&start)
170       .JumpIfNull(&start)
171       .JumpIfUndefined(&start);
172   // Perform an operation that returns boolean value to
173   // generate JumpIfTrue/False
174   builder.CompareOperation(Token::Value::EQ, reg, Strength::WEAK)
175       .JumpIfTrue(&start)
176       .CompareOperation(Token::Value::EQ, reg, Strength::WEAK)
177       .JumpIfFalse(&start);
178   // Perform an operation that returns a non-boolean operation to
179   // generate JumpIfToBooleanTrue/False.
180   builder.BinaryOperation(Token::Value::ADD, reg, Strength::WEAK)
181       .JumpIfTrue(&start)
182       .BinaryOperation(Token::Value::ADD, reg, Strength::WEAK)
183       .JumpIfFalse(&start);
184   // Insert dummy ops to force longer jumps
185   for (int i = 0; i < 128; i++) {
186     builder.LoadTrue();
187   }
188   // Longer jumps requiring Constant operand
189   builder.Jump(&start)
190       .JumpIfNull(&start)
191       .JumpIfUndefined(&start);
192   // Perform an operation that returns boolean value to
193   // generate JumpIfTrue/False
194   builder.CompareOperation(Token::Value::EQ, reg, Strength::WEAK)
195       .JumpIfTrue(&start)
196       .CompareOperation(Token::Value::EQ, reg, Strength::WEAK)
197       .JumpIfFalse(&start);
198   // Perform an operation that returns a non-boolean operation to
199   // generate JumpIfToBooleanTrue/False.
200   builder.BinaryOperation(Token::Value::ADD, reg, Strength::WEAK)
201       .JumpIfTrue(&start)
202       .BinaryOperation(Token::Value::ADD, reg, Strength::WEAK)
203       .JumpIfFalse(&start);
204 
205   // Emit throw in it's own basic block so that the rest of the code isn't
206   // omitted due to being dead.
207   BytecodeLabel after_throw;
208   builder.Jump(&after_throw)
209     .Throw()
210     .Bind(&after_throw);
211 
212   builder.ForInPrepare(reg, reg, reg)
213       .ForInDone(reg, reg)
214       .ForInNext(reg, reg, reg, reg)
215       .ForInStep(reg);
216 
217   // Wide constant pool loads
218   for (int i = 0; i < 256; i++) {
219     // Emit junk in constant pool to force wide constant pool index.
220     builder.LoadLiteral(factory->NewNumber(2.5321 + i));
221   }
222   builder.LoadLiteral(Smi::FromInt(20000000));
223   Handle<String> wide_name = factory->NewStringFromStaticChars("var_wide_name");
224 
225   // Emit wide global load / store operations.
226   builder.LoadGlobal(name, 1024, LanguageMode::SLOPPY,
227                      TypeofMode::NOT_INSIDE_TYPEOF)
228       .LoadGlobal(wide_name, 1, LanguageMode::STRICT,
229                   TypeofMode::NOT_INSIDE_TYPEOF)
230       .LoadGlobal(name, 1024, LanguageMode::SLOPPY, TypeofMode::INSIDE_TYPEOF)
231       .LoadGlobal(wide_name, 1, LanguageMode::STRICT, TypeofMode::INSIDE_TYPEOF)
232       .StoreGlobal(name, 1024, LanguageMode::SLOPPY)
233       .StoreGlobal(wide_name, 1, LanguageMode::STRICT);
234 
235   // Emit wide load / store property operations.
236   builder.LoadNamedProperty(reg, wide_name, 0, LanguageMode::SLOPPY)
237       .LoadKeyedProperty(reg, 2056, LanguageMode::SLOPPY)
238       .StoreNamedProperty(reg, wide_name, 0, LanguageMode::SLOPPY)
239       .StoreKeyedProperty(reg, reg, 2056, LanguageMode::SLOPPY)
240       .LoadNamedProperty(reg, wide_name, 0, LanguageMode::STRICT)
241       .LoadKeyedProperty(reg, 2056, LanguageMode::STRICT)
242       .StoreNamedProperty(reg, wide_name, 0, LanguageMode::STRICT)
243       .StoreKeyedProperty(reg, reg, 2056, LanguageMode::STRICT);
244 
245   // Emit wide context operations.
246   builder.LoadContextSlot(reg, 1024)
247       .StoreContextSlot(reg, 1024);
248 
249   // Emit wide load / store lookup slots.
250   builder.LoadLookupSlot(wide_name, TypeofMode::NOT_INSIDE_TYPEOF)
251       .LoadLookupSlot(wide_name, TypeofMode::INSIDE_TYPEOF)
252       .StoreLookupSlot(wide_name, LanguageMode::SLOPPY)
253       .StoreLookupSlot(wide_name, LanguageMode::STRICT);
254 
255   // CreateClosureWide
256   Handle<SharedFunctionInfo> shared_info2 = factory->NewSharedFunctionInfo(
257       factory->NewStringFromStaticChars("function_b"), MaybeHandle<Code>(),
258       false);
259   builder.CreateClosure(shared_info2, NOT_TENURED);
260 
261   // Emit wide variant of literal creation operations.
262   builder.CreateRegExpLiteral(factory->NewStringFromStaticChars("wide_literal"),
263                               0, 0)
264       .CreateArrayLiteral(factory->NewFixedArray(2), 0, 0)
265       .CreateObjectLiteral(factory->NewFixedArray(2), 0, 0);
266 
267   // Longer jumps requiring ConstantWide operand
268   builder.Jump(&start).JumpIfNull(&start).JumpIfUndefined(&start);
269   // Perform an operation that returns boolean value to
270   // generate JumpIfTrue/False
271   builder.CompareOperation(Token::Value::EQ, reg, Strength::WEAK)
272       .JumpIfTrue(&start)
273       .CompareOperation(Token::Value::EQ, reg, Strength::WEAK)
274       .JumpIfFalse(&start);
275   // Perform an operation that returns a non-boolean operation to
276   // generate JumpIfToBooleanTrue/False.
277   builder.BinaryOperation(Token::Value::ADD, reg, Strength::WEAK)
278       .JumpIfTrue(&start)
279       .BinaryOperation(Token::Value::ADD, reg, Strength::WEAK)
280       .JumpIfFalse(&start);
281 
282   builder.Return();
283 
284   // Generate BytecodeArray.
285   Handle<BytecodeArray> the_array = builder.ToBytecodeArray();
286   CHECK_EQ(the_array->frame_size(),
287            builder.fixed_register_count() * kPointerSize);
288 
289   // Build scorecard of bytecodes encountered in the BytecodeArray.
290   std::vector<int> scorecard(Bytecodes::ToByte(Bytecode::kLast) + 1);
291   Bytecode final_bytecode = Bytecode::kLdaZero;
292   int i = 0;
293   while (i < the_array->length()) {
294     uint8_t code = the_array->get(i);
295     scorecard[code] += 1;
296     final_bytecode = Bytecodes::FromByte(code);
297     i += Bytecodes::Size(Bytecodes::FromByte(code));
298   }
299 
300   // Check return occurs at the end and only once in the BytecodeArray.
301   CHECK_EQ(final_bytecode, Bytecode::kReturn);
302   CHECK_EQ(scorecard[Bytecodes::ToByte(final_bytecode)], 1);
303 
304 #define CHECK_BYTECODE_PRESENT(Name, ...)     \
305   /* Check Bytecode is marked in scorecard */ \
306   CHECK_GE(scorecard[Bytecodes::ToByte(Bytecode::k##Name)], 1);
307   BYTECODE_LIST(CHECK_BYTECODE_PRESENT)
308 #undef CHECK_BYTECODE_PRESENT
309 }
310 
311 
TEST_F(BytecodeArrayBuilderTest,FrameSizesLookGood)312 TEST_F(BytecodeArrayBuilderTest, FrameSizesLookGood) {
313   for (int locals = 0; locals < 5; locals++) {
314     for (int contexts = 0; contexts < 4; contexts++) {
315       for (int temps = 0; temps < 3; temps++) {
316         BytecodeArrayBuilder builder(isolate(), zone());
317         builder.set_parameter_count(0);
318         builder.set_locals_count(locals);
319         builder.set_context_count(contexts);
320 
321         BytecodeRegisterAllocator temporaries(&builder);
322         for (int i = 0; i < temps; i++) {
323           builder.StoreAccumulatorInRegister(temporaries.NewRegister());
324         }
325         builder.Return();
326 
327         Handle<BytecodeArray> the_array = builder.ToBytecodeArray();
328         int total_registers = locals + contexts + temps;
329         CHECK_EQ(the_array->frame_size(), total_registers * kPointerSize);
330       }
331     }
332   }
333 }
334 
335 
TEST_F(BytecodeArrayBuilderTest,RegisterValues)336 TEST_F(BytecodeArrayBuilderTest, RegisterValues) {
337   int index = 1;
338   uint8_t operand = static_cast<uint8_t>(-index);
339 
340   Register the_register(index);
341   CHECK_EQ(the_register.index(), index);
342 
343   int actual_operand = the_register.ToOperand();
344   CHECK_EQ(actual_operand, operand);
345 
346   int actual_index = Register::FromOperand(actual_operand).index();
347   CHECK_EQ(actual_index, index);
348 }
349 
350 
TEST_F(BytecodeArrayBuilderTest,Parameters)351 TEST_F(BytecodeArrayBuilderTest, Parameters) {
352   BytecodeArrayBuilder builder(isolate(), zone());
353   builder.set_parameter_count(10);
354   builder.set_locals_count(0);
355   builder.set_context_count(0);
356 
357   Register param0(builder.Parameter(0));
358   Register param9(builder.Parameter(9));
359   CHECK_EQ(param9.index() - param0.index(), 9);
360 }
361 
362 
TEST_F(BytecodeArrayBuilderTest,RegisterType)363 TEST_F(BytecodeArrayBuilderTest, RegisterType) {
364   BytecodeArrayBuilder builder(isolate(), zone());
365   builder.set_parameter_count(10);
366   builder.set_locals_count(3);
367   builder.set_context_count(0);
368 
369   BytecodeRegisterAllocator register_allocator(&builder);
370   Register temp0 = register_allocator.NewRegister();
371   Register param0(builder.Parameter(0));
372   Register param9(builder.Parameter(9));
373   Register temp1 = register_allocator.NewRegister();
374   Register reg0(0);
375   Register reg1(1);
376   Register reg2(2);
377   Register temp2 = register_allocator.NewRegister();
378   CHECK_EQ(builder.RegisterIsParameterOrLocal(temp0), false);
379   CHECK_EQ(builder.RegisterIsParameterOrLocal(temp1), false);
380   CHECK_EQ(builder.RegisterIsParameterOrLocal(temp2), false);
381   CHECK_EQ(builder.RegisterIsParameterOrLocal(param0), true);
382   CHECK_EQ(builder.RegisterIsParameterOrLocal(param9), true);
383   CHECK_EQ(builder.RegisterIsParameterOrLocal(reg0), true);
384   CHECK_EQ(builder.RegisterIsParameterOrLocal(reg1), true);
385   CHECK_EQ(builder.RegisterIsParameterOrLocal(reg2), true);
386 }
387 
388 
TEST_F(BytecodeArrayBuilderTest,Constants)389 TEST_F(BytecodeArrayBuilderTest, Constants) {
390   BytecodeArrayBuilder builder(isolate(), zone());
391   builder.set_parameter_count(0);
392   builder.set_locals_count(0);
393   builder.set_context_count(0);
394 
395   Factory* factory = isolate()->factory();
396   Handle<HeapObject> heap_num_1 = factory->NewHeapNumber(3.14);
397   Handle<HeapObject> heap_num_2 = factory->NewHeapNumber(5.2);
398   Handle<Object> large_smi(Smi::FromInt(0x12345678), isolate());
399   Handle<HeapObject> heap_num_2_copy(*heap_num_2);
400   builder.LoadLiteral(heap_num_1)
401       .LoadLiteral(heap_num_2)
402       .LoadLiteral(large_smi)
403       .LoadLiteral(heap_num_1)
404       .LoadLiteral(heap_num_1)
405       .LoadLiteral(heap_num_2_copy);
406 
407   Handle<BytecodeArray> array = builder.ToBytecodeArray();
408   // Should only have one entry for each identical constant.
409   CHECK_EQ(array->constant_pool()->length(), 3);
410 }
411 
412 
TEST_F(BytecodeArrayBuilderTest,ForwardJumps)413 TEST_F(BytecodeArrayBuilderTest, ForwardJumps) {
414   static const int kFarJumpDistance = 256;
415 
416   BytecodeArrayBuilder builder(isolate(), zone());
417   builder.set_parameter_count(0);
418   builder.set_locals_count(1);
419   builder.set_context_count(0);
420 
421   Register reg(0);
422   BytecodeLabel far0, far1, far2, far3, far4;
423   BytecodeLabel near0, near1, near2, near3, near4;
424 
425   builder.Jump(&near0)
426       .CompareOperation(Token::Value::EQ, reg, Strength::WEAK)
427       .JumpIfTrue(&near1)
428       .CompareOperation(Token::Value::EQ, reg, Strength::WEAK)
429       .JumpIfFalse(&near2)
430       .BinaryOperation(Token::Value::ADD, reg, Strength::WEAK)
431       .JumpIfTrue(&near3)
432       .BinaryOperation(Token::Value::ADD, reg, Strength::WEAK)
433       .JumpIfFalse(&near4)
434       .Bind(&near0)
435       .Bind(&near1)
436       .Bind(&near2)
437       .Bind(&near3)
438       .Bind(&near4)
439       .Jump(&far0)
440       .CompareOperation(Token::Value::EQ, reg, Strength::WEAK)
441       .JumpIfTrue(&far1)
442       .CompareOperation(Token::Value::EQ, reg, Strength::WEAK)
443       .JumpIfFalse(&far2)
444       .BinaryOperation(Token::Value::ADD, reg, Strength::WEAK)
445       .JumpIfTrue(&far3)
446       .BinaryOperation(Token::Value::ADD, reg, Strength::WEAK)
447       .JumpIfFalse(&far4);
448   for (int i = 0; i < kFarJumpDistance - 18; i++) {
449     builder.LoadUndefined();
450   }
451   builder.Bind(&far0).Bind(&far1).Bind(&far2).Bind(&far3).Bind(&far4);
452   builder.Return();
453 
454   Handle<BytecodeArray> array = builder.ToBytecodeArray();
455   DCHECK_EQ(array->length(), 36 + kFarJumpDistance - 18 + 1);
456 
457   BytecodeArrayIterator iterator(array);
458   CHECK_EQ(iterator.current_bytecode(), Bytecode::kJump);
459   CHECK_EQ(iterator.GetImmediateOperand(0), 18);
460   iterator.Advance();
461 
462   // Ignore compare operation.
463   iterator.Advance();
464 
465   CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfTrue);
466   CHECK_EQ(iterator.GetImmediateOperand(0), 14);
467   iterator.Advance();
468 
469   // Ignore compare operation.
470   iterator.Advance();
471 
472   CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfFalse);
473   CHECK_EQ(iterator.GetImmediateOperand(0), 10);
474   iterator.Advance();
475 
476   // Ignore add operation.
477   iterator.Advance();
478 
479   CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfToBooleanTrue);
480   CHECK_EQ(iterator.GetImmediateOperand(0), 6);
481   iterator.Advance();
482 
483   // Ignore add operation.
484   iterator.Advance();
485 
486   CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfToBooleanFalse);
487   CHECK_EQ(iterator.GetImmediateOperand(0), 2);
488   iterator.Advance();
489 
490 
491   CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpConstant);
492   CHECK_EQ(*iterator.GetConstantForIndexOperand(0),
493            Smi::FromInt(kFarJumpDistance));
494   iterator.Advance();
495 
496   // Ignore compare operation.
497   iterator.Advance();
498 
499   CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfTrueConstant);
500   CHECK_EQ(*iterator.GetConstantForIndexOperand(0),
501            Smi::FromInt(kFarJumpDistance - 4));
502   iterator.Advance();
503 
504   // Ignore compare operation.
505   iterator.Advance();
506 
507   CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfFalseConstant);
508   CHECK_EQ(*iterator.GetConstantForIndexOperand(0),
509            Smi::FromInt(kFarJumpDistance - 8));
510   iterator.Advance();
511 
512   // Ignore add operation.
513   iterator.Advance();
514 
515   CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfToBooleanTrueConstant);
516   CHECK_EQ(*iterator.GetConstantForIndexOperand(0),
517            Smi::FromInt(kFarJumpDistance - 12));
518   iterator.Advance();
519 
520   // Ignore add operation.
521   iterator.Advance();
522 
523   CHECK_EQ(iterator.current_bytecode(),
524            Bytecode::kJumpIfToBooleanFalseConstant);
525   CHECK_EQ(*iterator.GetConstantForIndexOperand(0),
526            Smi::FromInt(kFarJumpDistance - 16));
527   iterator.Advance();
528 }
529 
530 
TEST_F(BytecodeArrayBuilderTest,BackwardJumps)531 TEST_F(BytecodeArrayBuilderTest, BackwardJumps) {
532   BytecodeArrayBuilder builder(isolate(), zone());
533   builder.set_parameter_count(0);
534   builder.set_locals_count(1);
535   builder.set_context_count(0);
536   Register reg(0);
537 
538   BytecodeLabel label0, label1, label2, label3, label4;
539   builder.Bind(&label0)
540       .Jump(&label0)
541       .Bind(&label1)
542       .CompareOperation(Token::Value::EQ, reg, Strength::WEAK)
543       .JumpIfTrue(&label1)
544       .Bind(&label2)
545       .CompareOperation(Token::Value::EQ, reg, Strength::WEAK)
546       .JumpIfFalse(&label2)
547       .Bind(&label3)
548       .BinaryOperation(Token::Value::ADD, reg, Strength::WEAK)
549       .JumpIfTrue(&label3)
550       .Bind(&label4)
551       .BinaryOperation(Token::Value::ADD, reg, Strength::WEAK)
552       .JumpIfFalse(&label4);
553   for (int i = 0; i < 63; i++) {
554     builder.Jump(&label4);
555   }
556   builder.BinaryOperation(Token::Value::ADD, reg, Strength::WEAK)
557       .JumpIfFalse(&label4);
558   builder.BinaryOperation(Token::Value::ADD, reg, Strength::WEAK)
559       .JumpIfTrue(&label3);
560   builder.CompareOperation(Token::Value::EQ, reg, Strength::WEAK)
561       .JumpIfFalse(&label2);
562   builder.CompareOperation(Token::Value::EQ, reg, Strength::WEAK)
563       .JumpIfTrue(&label1);
564   builder.Jump(&label0);
565   builder.Return();
566 
567   Handle<BytecodeArray> array = builder.ToBytecodeArray();
568   BytecodeArrayIterator iterator(array);
569   CHECK_EQ(iterator.current_bytecode(), Bytecode::kJump);
570   CHECK_EQ(iterator.GetImmediateOperand(0), 0);
571   iterator.Advance();
572   // Ignore compare operation.
573   iterator.Advance();
574   CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfTrue);
575   CHECK_EQ(iterator.GetImmediateOperand(0), -2);
576   iterator.Advance();
577   // Ignore compare operation.
578   iterator.Advance();
579   CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfFalse);
580   CHECK_EQ(iterator.GetImmediateOperand(0), -2);
581   iterator.Advance();
582   // Ignore binary operation.
583   iterator.Advance();
584   CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfToBooleanTrue);
585   CHECK_EQ(iterator.GetImmediateOperand(0), -2);
586   iterator.Advance();
587   // Ignore binary operation.
588   iterator.Advance();
589   CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfToBooleanFalse);
590   CHECK_EQ(iterator.GetImmediateOperand(0), -2);
591   iterator.Advance();
592   for (int i = 0; i < 63; i++) {
593     CHECK_EQ(iterator.current_bytecode(), Bytecode::kJump);
594     CHECK_EQ(iterator.GetImmediateOperand(0), -i * 2 - 4);
595     iterator.Advance();
596   }
597   // Ignore binary operation.
598   iterator.Advance();
599   CHECK_EQ(iterator.current_bytecode(),
600            Bytecode::kJumpIfToBooleanFalseConstant);
601   CHECK_EQ(Smi::cast(*iterator.GetConstantForIndexOperand(0))->value(), -132);
602   iterator.Advance();
603   // Ignore binary operation.
604   iterator.Advance();
605   CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfToBooleanTrueConstant);
606   CHECK_EQ(Smi::cast(*iterator.GetConstantForIndexOperand(0))->value(), -140);
607   iterator.Advance();
608   // Ignore compare operation.
609   iterator.Advance();
610   CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfFalseConstant);
611   CHECK_EQ(Smi::cast(*iterator.GetConstantForIndexOperand(0))->value(), -148);
612   iterator.Advance();
613   // Ignore compare operation.
614   iterator.Advance();
615   CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfTrueConstant);
616   CHECK_EQ(Smi::cast(*iterator.GetConstantForIndexOperand(0))->value(), -156);
617   iterator.Advance();
618   CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpConstant);
619   CHECK_EQ(Smi::cast(*iterator.GetConstantForIndexOperand(0))->value(), -160);
620   iterator.Advance();
621   CHECK_EQ(iterator.current_bytecode(), Bytecode::kReturn);
622   iterator.Advance();
623   CHECK(iterator.done());
624 }
625 
626 
TEST_F(BytecodeArrayBuilderTest,LabelReuse)627 TEST_F(BytecodeArrayBuilderTest, LabelReuse) {
628   BytecodeArrayBuilder builder(isolate(), zone());
629   builder.set_parameter_count(0);
630   builder.set_locals_count(0);
631   builder.set_context_count(0);
632 
633   // Labels can only have 1 forward reference, but
634   // can be referred to mulitple times once bound.
635   BytecodeLabel label;
636 
637   builder.Jump(&label).Bind(&label).Jump(&label).Jump(&label).Return();
638 
639   Handle<BytecodeArray> array = builder.ToBytecodeArray();
640   BytecodeArrayIterator iterator(array);
641   CHECK_EQ(iterator.current_bytecode(), Bytecode::kJump);
642   CHECK_EQ(iterator.GetImmediateOperand(0), 2);
643   iterator.Advance();
644   CHECK_EQ(iterator.current_bytecode(), Bytecode::kJump);
645   CHECK_EQ(iterator.GetImmediateOperand(0), 0);
646   iterator.Advance();
647   CHECK_EQ(iterator.current_bytecode(), Bytecode::kJump);
648   CHECK_EQ(iterator.GetImmediateOperand(0), -2);
649   iterator.Advance();
650   CHECK_EQ(iterator.current_bytecode(), Bytecode::kReturn);
651   iterator.Advance();
652   CHECK(iterator.done());
653 }
654 
655 
TEST_F(BytecodeArrayBuilderTest,LabelAddressReuse)656 TEST_F(BytecodeArrayBuilderTest, LabelAddressReuse) {
657   static const int kRepeats = 3;
658 
659   BytecodeArrayBuilder builder(isolate(), zone());
660   builder.set_parameter_count(0);
661   builder.set_locals_count(0);
662   builder.set_context_count(0);
663 
664   for (int i = 0; i < kRepeats; i++) {
665     BytecodeLabel label;
666     builder.Jump(&label).Bind(&label).Jump(&label).Jump(&label);
667   }
668 
669   builder.Return();
670 
671   Handle<BytecodeArray> array = builder.ToBytecodeArray();
672   BytecodeArrayIterator iterator(array);
673   for (int i = 0; i < kRepeats; i++) {
674     CHECK_EQ(iterator.current_bytecode(), Bytecode::kJump);
675     CHECK_EQ(iterator.GetImmediateOperand(0), 2);
676     iterator.Advance();
677     CHECK_EQ(iterator.current_bytecode(), Bytecode::kJump);
678     CHECK_EQ(iterator.GetImmediateOperand(0), 0);
679     iterator.Advance();
680     CHECK_EQ(iterator.current_bytecode(), Bytecode::kJump);
681     CHECK_EQ(iterator.GetImmediateOperand(0), -2);
682     iterator.Advance();
683   }
684   CHECK_EQ(iterator.current_bytecode(), Bytecode::kReturn);
685   iterator.Advance();
686   CHECK(iterator.done());
687 }
688 
689 
690 }  // namespace interpreter
691 }  // namespace internal
692 }  // namespace v8
693