blob: 839215f743220550b256ae52c875eb2f62cfaf84 [file] [log] [blame]
Ben Murdoch014dc512016-03-22 12:00:34 +00001// 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
12namespace v8 {
13namespace internal {
14namespace interpreter {
15
16class BytecodeArrayBuilderTest : public TestWithIsolateAndZone {
17 public:
18 BytecodeArrayBuilderTest() {}
19 ~BytecodeArrayBuilderTest() override {}
20};
21
22
23TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) {
Ben Murdoch109988c2016-05-18 11:27:45 +010024 BytecodeArrayBuilder builder(isolate(), zone(), 0, 1, 131);
Ben Murdoch014dc512016-03-22 12:00:34 +000025
Ben Murdoch109988c2016-05-18 11:27:45 +010026 CHECK_EQ(builder.locals_count(), 131);
Ben Murdoch014dc512016-03-22 12:00:34 +000027 CHECK_EQ(builder.context_count(), 1);
Ben Murdoch109988c2016-05-18 11:27:45 +010028 CHECK_EQ(builder.fixed_register_count(), 132);
29
30 // Emit argument creation operations.
31 builder.CreateArguments(CreateArgumentsType::kMappedArguments)
32 .CreateArguments(CreateArgumentsType::kUnmappedArguments)
33 .CreateArguments(CreateArgumentsType::kRestParameter);
Ben Murdoch014dc512016-03-22 12:00:34 +000034
35 // Emit constant loads.
36 builder.LoadLiteral(Smi::FromInt(0))
37 .LoadLiteral(Smi::FromInt(8))
38 .LoadLiteral(Smi::FromInt(10000000))
39 .LoadUndefined()
40 .LoadNull()
41 .LoadTheHole()
42 .LoadTrue()
43 .LoadFalse();
44
Ben Murdoch014dc512016-03-22 12:00:34 +000045 Register reg(0);
Ben Murdoch109988c2016-05-18 11:27:45 +010046 Register other(reg.index() + 1);
47 Register wide(128);
48
Ben Murdoch014dc512016-03-22 12:00:34 +000049 builder.LoadAccumulatorWithRegister(reg)
50 .LoadNull()
51 .StoreAccumulatorInRegister(reg);
52
53 // Emit register-register transfer.
Ben Murdoch014dc512016-03-22 12:00:34 +000054 builder.MoveRegister(reg, other);
Ben Murdoch109988c2016-05-18 11:27:45 +010055 builder.MoveRegister(reg, wide);
Ben Murdoch014dc512016-03-22 12:00:34 +000056
57 // Emit global load / store operations.
58 Factory* factory = isolate()->factory();
59 Handle<String> name = factory->NewStringFromStaticChars("var_name");
Ben Murdoch109988c2016-05-18 11:27:45 +010060 builder.LoadGlobal(name, 1, TypeofMode::NOT_INSIDE_TYPEOF)
61 .LoadGlobal(name, 1, TypeofMode::INSIDE_TYPEOF)
Ben Murdoch014dc512016-03-22 12:00:34 +000062 .StoreGlobal(name, 1, LanguageMode::SLOPPY)
63 .StoreGlobal(name, 1, LanguageMode::STRICT);
64
65 // Emit context operations.
66 builder.PushContext(reg)
67 .PopContext(reg)
68 .LoadContextSlot(reg, 1)
69 .StoreContextSlot(reg, 1);
70
71 // Emit load / store property operations.
Ben Murdoch109988c2016-05-18 11:27:45 +010072 builder.LoadNamedProperty(reg, name, 0)
73 .LoadKeyedProperty(reg, 0)
Ben Murdoch014dc512016-03-22 12:00:34 +000074 .StoreNamedProperty(reg, name, 0, LanguageMode::SLOPPY)
75 .StoreKeyedProperty(reg, reg, 0, LanguageMode::SLOPPY)
Ben Murdoch014dc512016-03-22 12:00:34 +000076 .StoreNamedProperty(reg, name, 0, LanguageMode::STRICT)
77 .StoreKeyedProperty(reg, reg, 0, LanguageMode::STRICT);
78
79 // Emit load / store lookup slots.
80 builder.LoadLookupSlot(name, TypeofMode::NOT_INSIDE_TYPEOF)
81 .LoadLookupSlot(name, TypeofMode::INSIDE_TYPEOF)
82 .StoreLookupSlot(name, LanguageMode::SLOPPY)
83 .StoreLookupSlot(name, LanguageMode::STRICT);
84
85 // Emit closure operations.
86 Handle<SharedFunctionInfo> shared_info = factory->NewSharedFunctionInfo(
87 factory->NewStringFromStaticChars("function_a"), MaybeHandle<Code>(),
88 false);
89 builder.CreateClosure(shared_info, NOT_TENURED);
90
Ben Murdoch014dc512016-03-22 12:00:34 +000091 // Emit literal creation operations.
92 builder.CreateRegExpLiteral(factory->NewStringFromStaticChars("a"), 0, 0)
93 .CreateArrayLiteral(factory->NewFixedArray(1), 0, 0)
94 .CreateObjectLiteral(factory->NewFixedArray(1), 0, 0);
95
96 // Call operations.
Ben Murdoch109988c2016-05-18 11:27:45 +010097 builder.Call(reg, other, 1, 0)
98 .Call(reg, wide, 1, 0)
99 .TailCall(reg, other, 1, 0)
100 .TailCall(reg, wide, 1, 0)
Ben Murdoch014dc512016-03-22 12:00:34 +0000101 .CallRuntime(Runtime::kIsArray, reg, 1)
Ben Murdoch109988c2016-05-18 11:27:45 +0100102 .CallRuntime(Runtime::kIsArray, wide, 1)
103 .CallRuntimeForPair(Runtime::kLoadLookupSlotForCall, reg, 1, other)
104 .CallRuntimeForPair(Runtime::kLoadLookupSlotForCall, wide, 1, other)
105 .CallJSRuntime(Context::SPREAD_ITERABLE_INDEX, reg, 1)
106 .CallJSRuntime(Context::SPREAD_ITERABLE_INDEX, wide, 1);
Ben Murdoch014dc512016-03-22 12:00:34 +0000107
108 // Emit binary operator invocations.
Ben Murdoch109988c2016-05-18 11:27:45 +0100109 builder.BinaryOperation(Token::Value::ADD, reg)
110 .BinaryOperation(Token::Value::SUB, reg)
111 .BinaryOperation(Token::Value::MUL, reg)
112 .BinaryOperation(Token::Value::DIV, reg)
113 .BinaryOperation(Token::Value::MOD, reg);
Ben Murdoch014dc512016-03-22 12:00:34 +0000114
115 // Emit bitwise operator invocations
Ben Murdoch109988c2016-05-18 11:27:45 +0100116 builder.BinaryOperation(Token::Value::BIT_OR, reg)
117 .BinaryOperation(Token::Value::BIT_XOR, reg)
118 .BinaryOperation(Token::Value::BIT_AND, reg);
Ben Murdoch014dc512016-03-22 12:00:34 +0000119
120 // Emit shift operator invocations
Ben Murdoch109988c2016-05-18 11:27:45 +0100121 builder.BinaryOperation(Token::Value::SHL, reg)
122 .BinaryOperation(Token::Value::SAR, reg)
123 .BinaryOperation(Token::Value::SHR, reg);
Ben Murdoch014dc512016-03-22 12:00:34 +0000124
125 // Emit count operatior invocations
Ben Murdoch109988c2016-05-18 11:27:45 +0100126 builder.CountOperation(Token::Value::ADD).CountOperation(Token::Value::SUB);
Ben Murdoch014dc512016-03-22 12:00:34 +0000127
128 // Emit unary operator invocations.
129 builder.LogicalNot().TypeOf();
130
131 // Emit delete
Ben Murdoch109988c2016-05-18 11:27:45 +0100132 builder.Delete(reg, LanguageMode::SLOPPY).Delete(reg, LanguageMode::STRICT);
Ben Murdoch014dc512016-03-22 12:00:34 +0000133
134 // Emit new.
135 builder.New(reg, reg, 0);
Ben Murdoch109988c2016-05-18 11:27:45 +0100136 builder.New(wide, wide, 0);
Ben Murdoch014dc512016-03-22 12:00:34 +0000137
138 // Emit test operator invocations.
Ben Murdoch109988c2016-05-18 11:27:45 +0100139 builder.CompareOperation(Token::Value::EQ, reg)
140 .CompareOperation(Token::Value::NE, reg)
141 .CompareOperation(Token::Value::EQ_STRICT, reg)
142 .CompareOperation(Token::Value::NE_STRICT, reg)
143 .CompareOperation(Token::Value::LT, reg)
144 .CompareOperation(Token::Value::GT, reg)
145 .CompareOperation(Token::Value::LTE, reg)
146 .CompareOperation(Token::Value::GTE, reg)
147 .CompareOperation(Token::Value::INSTANCEOF, reg)
148 .CompareOperation(Token::Value::IN, reg);
Ben Murdoch014dc512016-03-22 12:00:34 +0000149
150 // Emit cast operator invocations.
151 builder.CastAccumulatorToNumber()
152 .CastAccumulatorToJSObject()
153 .CastAccumulatorToName();
154
155 // Emit control flow. Return must be the last instruction.
156 BytecodeLabel start;
157 builder.Bind(&start);
158 // Short jumps with Imm8 operands
159 builder.Jump(&start)
160 .JumpIfNull(&start)
Ben Murdoch109988c2016-05-18 11:27:45 +0100161 .JumpIfUndefined(&start)
162 .JumpIfNotHole(&start);
163
Ben Murdoch014dc512016-03-22 12:00:34 +0000164 // Perform an operation that returns boolean value to
165 // generate JumpIfTrue/False
Ben Murdoch109988c2016-05-18 11:27:45 +0100166 builder.CompareOperation(Token::Value::EQ, reg)
Ben Murdoch014dc512016-03-22 12:00:34 +0000167 .JumpIfTrue(&start)
Ben Murdoch109988c2016-05-18 11:27:45 +0100168 .CompareOperation(Token::Value::EQ, reg)
Ben Murdoch014dc512016-03-22 12:00:34 +0000169 .JumpIfFalse(&start);
170 // Perform an operation that returns a non-boolean operation to
171 // generate JumpIfToBooleanTrue/False.
Ben Murdoch109988c2016-05-18 11:27:45 +0100172 builder.BinaryOperation(Token::Value::ADD, reg)
Ben Murdoch014dc512016-03-22 12:00:34 +0000173 .JumpIfTrue(&start)
Ben Murdoch109988c2016-05-18 11:27:45 +0100174 .BinaryOperation(Token::Value::ADD, reg)
Ben Murdoch014dc512016-03-22 12:00:34 +0000175 .JumpIfFalse(&start);
176 // Insert dummy ops to force longer jumps
177 for (int i = 0; i < 128; i++) {
178 builder.LoadTrue();
179 }
180 // Longer jumps requiring Constant operand
Ben Murdoch109988c2016-05-18 11:27:45 +0100181 builder.Jump(&start).JumpIfNull(&start).JumpIfUndefined(&start).JumpIfNotHole(
182 &start);
Ben Murdoch014dc512016-03-22 12:00:34 +0000183 // Perform an operation that returns boolean value to
184 // generate JumpIfTrue/False
Ben Murdoch109988c2016-05-18 11:27:45 +0100185 builder.CompareOperation(Token::Value::EQ, reg)
Ben Murdoch014dc512016-03-22 12:00:34 +0000186 .JumpIfTrue(&start)
Ben Murdoch109988c2016-05-18 11:27:45 +0100187 .CompareOperation(Token::Value::EQ, reg)
Ben Murdoch014dc512016-03-22 12:00:34 +0000188 .JumpIfFalse(&start);
189 // Perform an operation that returns a non-boolean operation to
190 // generate JumpIfToBooleanTrue/False.
Ben Murdoch109988c2016-05-18 11:27:45 +0100191 builder.BinaryOperation(Token::Value::ADD, reg)
Ben Murdoch014dc512016-03-22 12:00:34 +0000192 .JumpIfTrue(&start)
Ben Murdoch109988c2016-05-18 11:27:45 +0100193 .BinaryOperation(Token::Value::ADD, reg)
Ben Murdoch014dc512016-03-22 12:00:34 +0000194 .JumpIfFalse(&start);
195
Ben Murdoch109988c2016-05-18 11:27:45 +0100196 // Emit stack check bytecode.
197 builder.StackCheck();
Ben Murdoch83897452016-05-17 11:12:09 +0100198
Ben Murdoch109988c2016-05-18 11:27:45 +0100199 // Emit throw and re-throw in it's own basic block so that the rest of the
200 // code isn't omitted due to being dead.
201 BytecodeLabel after_throw;
202 builder.Jump(&after_throw).Throw().Bind(&after_throw);
203 BytecodeLabel after_rethrow;
204 builder.Jump(&after_rethrow).ReThrow().Bind(&after_rethrow);
205
206 builder.ForInPrepare(reg)
Ben Murdoch014dc512016-03-22 12:00:34 +0000207 .ForInDone(reg, reg)
Ben Murdoch109988c2016-05-18 11:27:45 +0100208 .ForInNext(reg, reg, reg)
209 .ForInStep(reg);
210 builder.ForInPrepare(wide)
211 .ForInDone(reg, other)
212 .ForInNext(wide, wide, wide)
Ben Murdoch014dc512016-03-22 12:00:34 +0000213 .ForInStep(reg);
214
215 // Wide constant pool loads
216 for (int i = 0; i < 256; i++) {
217 // Emit junk in constant pool to force wide constant pool index.
218 builder.LoadLiteral(factory->NewNumber(2.5321 + i));
219 }
220 builder.LoadLiteral(Smi::FromInt(20000000));
221 Handle<String> wide_name = factory->NewStringFromStaticChars("var_wide_name");
222
223 // Emit wide global load / store operations.
Ben Murdoch109988c2016-05-18 11:27:45 +0100224 builder.LoadGlobal(name, 1024, TypeofMode::NOT_INSIDE_TYPEOF)
225 .LoadGlobal(name, 1024, TypeofMode::INSIDE_TYPEOF)
Ben Murdoch014dc512016-03-22 12:00:34 +0000226 .StoreGlobal(name, 1024, LanguageMode::SLOPPY)
227 .StoreGlobal(wide_name, 1, LanguageMode::STRICT);
228
229 // Emit wide load / store property operations.
Ben Murdoch109988c2016-05-18 11:27:45 +0100230 builder.LoadNamedProperty(reg, wide_name, 0)
231 .LoadKeyedProperty(reg, 2056)
Ben Murdoch014dc512016-03-22 12:00:34 +0000232 .StoreNamedProperty(reg, wide_name, 0, LanguageMode::SLOPPY)
233 .StoreKeyedProperty(reg, reg, 2056, LanguageMode::SLOPPY)
Ben Murdoch014dc512016-03-22 12:00:34 +0000234 .StoreNamedProperty(reg, wide_name, 0, LanguageMode::STRICT)
235 .StoreKeyedProperty(reg, reg, 2056, LanguageMode::STRICT);
236
237 // Emit wide context operations.
Ben Murdoch109988c2016-05-18 11:27:45 +0100238 builder.LoadContextSlot(reg, 1024).StoreContextSlot(reg, 1024);
Ben Murdoch014dc512016-03-22 12:00:34 +0000239
240 // Emit wide load / store lookup slots.
241 builder.LoadLookupSlot(wide_name, TypeofMode::NOT_INSIDE_TYPEOF)
242 .LoadLookupSlot(wide_name, TypeofMode::INSIDE_TYPEOF)
243 .StoreLookupSlot(wide_name, LanguageMode::SLOPPY)
244 .StoreLookupSlot(wide_name, LanguageMode::STRICT);
245
246 // CreateClosureWide
247 Handle<SharedFunctionInfo> shared_info2 = factory->NewSharedFunctionInfo(
248 factory->NewStringFromStaticChars("function_b"), MaybeHandle<Code>(),
249 false);
250 builder.CreateClosure(shared_info2, NOT_TENURED);
251
252 // Emit wide variant of literal creation operations.
253 builder.CreateRegExpLiteral(factory->NewStringFromStaticChars("wide_literal"),
254 0, 0)
255 .CreateArrayLiteral(factory->NewFixedArray(2), 0, 0)
256 .CreateObjectLiteral(factory->NewFixedArray(2), 0, 0);
257
258 // Longer jumps requiring ConstantWide operand
Ben Murdoch109988c2016-05-18 11:27:45 +0100259 builder.Jump(&start).JumpIfNull(&start).JumpIfUndefined(&start).JumpIfNotHole(
260 &start);
Ben Murdoch014dc512016-03-22 12:00:34 +0000261 // Perform an operation that returns boolean value to
262 // generate JumpIfTrue/False
Ben Murdoch109988c2016-05-18 11:27:45 +0100263 builder.CompareOperation(Token::Value::EQ, reg)
Ben Murdoch014dc512016-03-22 12:00:34 +0000264 .JumpIfTrue(&start)
Ben Murdoch109988c2016-05-18 11:27:45 +0100265 .CompareOperation(Token::Value::EQ, reg)
Ben Murdoch014dc512016-03-22 12:00:34 +0000266 .JumpIfFalse(&start);
267 // Perform an operation that returns a non-boolean operation to
268 // generate JumpIfToBooleanTrue/False.
Ben Murdoch109988c2016-05-18 11:27:45 +0100269 builder.BinaryOperation(Token::Value::ADD, reg)
Ben Murdoch014dc512016-03-22 12:00:34 +0000270 .JumpIfTrue(&start)
Ben Murdoch109988c2016-05-18 11:27:45 +0100271 .BinaryOperation(Token::Value::ADD, reg)
Ben Murdoch014dc512016-03-22 12:00:34 +0000272 .JumpIfFalse(&start);
273
Ben Murdoch109988c2016-05-18 11:27:45 +0100274 builder.Debugger();
275
Ben Murdoch014dc512016-03-22 12:00:34 +0000276 builder.Return();
277
278 // Generate BytecodeArray.
279 Handle<BytecodeArray> the_array = builder.ToBytecodeArray();
280 CHECK_EQ(the_array->frame_size(),
Ben Murdoch109988c2016-05-18 11:27:45 +0100281 (builder.fixed_and_temporary_register_count() +
282 builder.translation_register_count()) *
283 kPointerSize);
Ben Murdoch014dc512016-03-22 12:00:34 +0000284
285 // Build scorecard of bytecodes encountered in the BytecodeArray.
286 std::vector<int> scorecard(Bytecodes::ToByte(Bytecode::kLast) + 1);
287 Bytecode final_bytecode = Bytecode::kLdaZero;
288 int i = 0;
289 while (i < the_array->length()) {
290 uint8_t code = the_array->get(i);
291 scorecard[code] += 1;
292 final_bytecode = Bytecodes::FromByte(code);
293 i += Bytecodes::Size(Bytecodes::FromByte(code));
294 }
295
296 // Check return occurs at the end and only once in the BytecodeArray.
297 CHECK_EQ(final_bytecode, Bytecode::kReturn);
298 CHECK_EQ(scorecard[Bytecodes::ToByte(final_bytecode)], 1);
299
Ben Murdoch109988c2016-05-18 11:27:45 +0100300#define CHECK_BYTECODE_PRESENT(Name, ...) \
301 /* Check Bytecode is marked in scorecard, unless it's a debug break */ \
302 if (!Bytecodes::IsDebugBreak(Bytecode::k##Name)) { \
303 CHECK_GE(scorecard[Bytecodes::ToByte(Bytecode::k##Name)], 1); \
304 }
Ben Murdoch014dc512016-03-22 12:00:34 +0000305 BYTECODE_LIST(CHECK_BYTECODE_PRESENT)
306#undef CHECK_BYTECODE_PRESENT
307}
308
309
310TEST_F(BytecodeArrayBuilderTest, FrameSizesLookGood) {
311 for (int locals = 0; locals < 5; locals++) {
312 for (int contexts = 0; contexts < 4; contexts++) {
313 for (int temps = 0; temps < 3; temps++) {
Ben Murdoch109988c2016-05-18 11:27:45 +0100314 BytecodeArrayBuilder builder(isolate(), zone(), 0, contexts, locals);
315 BytecodeRegisterAllocator temporaries(
316 zone(), builder.temporary_register_allocator());
Ben Murdoch014dc512016-03-22 12:00:34 +0000317 for (int i = 0; i < temps; i++) {
318 builder.StoreAccumulatorInRegister(temporaries.NewRegister());
319 }
320 builder.Return();
321
322 Handle<BytecodeArray> the_array = builder.ToBytecodeArray();
323 int total_registers = locals + contexts + temps;
324 CHECK_EQ(the_array->frame_size(), total_registers * kPointerSize);
325 }
326 }
327 }
328}
329
330
331TEST_F(BytecodeArrayBuilderTest, RegisterValues) {
332 int index = 1;
333 uint8_t operand = static_cast<uint8_t>(-index);
334
335 Register the_register(index);
336 CHECK_EQ(the_register.index(), index);
337
338 int actual_operand = the_register.ToOperand();
339 CHECK_EQ(actual_operand, operand);
340
341 int actual_index = Register::FromOperand(actual_operand).index();
342 CHECK_EQ(actual_index, index);
343}
344
345
346TEST_F(BytecodeArrayBuilderTest, Parameters) {
Ben Murdoch109988c2016-05-18 11:27:45 +0100347 BytecodeArrayBuilder builder(isolate(), zone(), 10, 0, 0);
Ben Murdoch014dc512016-03-22 12:00:34 +0000348 Register param0(builder.Parameter(0));
349 Register param9(builder.Parameter(9));
350 CHECK_EQ(param9.index() - param0.index(), 9);
351}
352
353
354TEST_F(BytecodeArrayBuilderTest, RegisterType) {
Ben Murdoch109988c2016-05-18 11:27:45 +0100355 BytecodeArrayBuilder builder(isolate(), zone(), 10, 0, 3);
356 BytecodeRegisterAllocator register_allocator(
357 zone(), builder.temporary_register_allocator());
Ben Murdoch014dc512016-03-22 12:00:34 +0000358 Register temp0 = register_allocator.NewRegister();
359 Register param0(builder.Parameter(0));
360 Register param9(builder.Parameter(9));
361 Register temp1 = register_allocator.NewRegister();
362 Register reg0(0);
363 Register reg1(1);
364 Register reg2(2);
365 Register temp2 = register_allocator.NewRegister();
366 CHECK_EQ(builder.RegisterIsParameterOrLocal(temp0), false);
367 CHECK_EQ(builder.RegisterIsParameterOrLocal(temp1), false);
368 CHECK_EQ(builder.RegisterIsParameterOrLocal(temp2), false);
369 CHECK_EQ(builder.RegisterIsParameterOrLocal(param0), true);
370 CHECK_EQ(builder.RegisterIsParameterOrLocal(param9), true);
371 CHECK_EQ(builder.RegisterIsParameterOrLocal(reg0), true);
372 CHECK_EQ(builder.RegisterIsParameterOrLocal(reg1), true);
373 CHECK_EQ(builder.RegisterIsParameterOrLocal(reg2), true);
374}
375
376
377TEST_F(BytecodeArrayBuilderTest, Constants) {
Ben Murdoch109988c2016-05-18 11:27:45 +0100378 BytecodeArrayBuilder builder(isolate(), zone(), 0, 0, 0);
Ben Murdoch014dc512016-03-22 12:00:34 +0000379 Factory* factory = isolate()->factory();
380 Handle<HeapObject> heap_num_1 = factory->NewHeapNumber(3.14);
381 Handle<HeapObject> heap_num_2 = factory->NewHeapNumber(5.2);
382 Handle<Object> large_smi(Smi::FromInt(0x12345678), isolate());
383 Handle<HeapObject> heap_num_2_copy(*heap_num_2);
384 builder.LoadLiteral(heap_num_1)
385 .LoadLiteral(heap_num_2)
386 .LoadLiteral(large_smi)
387 .LoadLiteral(heap_num_1)
388 .LoadLiteral(heap_num_1)
Ben Murdoch109988c2016-05-18 11:27:45 +0100389 .LoadLiteral(heap_num_2_copy)
390 .Return();
Ben Murdoch014dc512016-03-22 12:00:34 +0000391
392 Handle<BytecodeArray> array = builder.ToBytecodeArray();
393 // Should only have one entry for each identical constant.
394 CHECK_EQ(array->constant_pool()->length(), 3);
395}
396
397
398TEST_F(BytecodeArrayBuilderTest, ForwardJumps) {
399 static const int kFarJumpDistance = 256;
400
Ben Murdoch109988c2016-05-18 11:27:45 +0100401 BytecodeArrayBuilder builder(isolate(), zone(), 0, 0, 1);
Ben Murdoch014dc512016-03-22 12:00:34 +0000402 Register reg(0);
403 BytecodeLabel far0, far1, far2, far3, far4;
404 BytecodeLabel near0, near1, near2, near3, near4;
405
406 builder.Jump(&near0)
Ben Murdoch109988c2016-05-18 11:27:45 +0100407 .CompareOperation(Token::Value::EQ, reg)
Ben Murdoch014dc512016-03-22 12:00:34 +0000408 .JumpIfTrue(&near1)
Ben Murdoch109988c2016-05-18 11:27:45 +0100409 .CompareOperation(Token::Value::EQ, reg)
Ben Murdoch014dc512016-03-22 12:00:34 +0000410 .JumpIfFalse(&near2)
Ben Murdoch109988c2016-05-18 11:27:45 +0100411 .BinaryOperation(Token::Value::ADD, reg)
Ben Murdoch014dc512016-03-22 12:00:34 +0000412 .JumpIfTrue(&near3)
Ben Murdoch109988c2016-05-18 11:27:45 +0100413 .BinaryOperation(Token::Value::ADD, reg)
Ben Murdoch014dc512016-03-22 12:00:34 +0000414 .JumpIfFalse(&near4)
415 .Bind(&near0)
416 .Bind(&near1)
417 .Bind(&near2)
418 .Bind(&near3)
419 .Bind(&near4)
420 .Jump(&far0)
Ben Murdoch109988c2016-05-18 11:27:45 +0100421 .CompareOperation(Token::Value::EQ, reg)
Ben Murdoch014dc512016-03-22 12:00:34 +0000422 .JumpIfTrue(&far1)
Ben Murdoch109988c2016-05-18 11:27:45 +0100423 .CompareOperation(Token::Value::EQ, reg)
Ben Murdoch014dc512016-03-22 12:00:34 +0000424 .JumpIfFalse(&far2)
Ben Murdoch109988c2016-05-18 11:27:45 +0100425 .BinaryOperation(Token::Value::ADD, reg)
Ben Murdoch014dc512016-03-22 12:00:34 +0000426 .JumpIfTrue(&far3)
Ben Murdoch109988c2016-05-18 11:27:45 +0100427 .BinaryOperation(Token::Value::ADD, reg)
Ben Murdoch014dc512016-03-22 12:00:34 +0000428 .JumpIfFalse(&far4);
429 for (int i = 0; i < kFarJumpDistance - 18; i++) {
430 builder.LoadUndefined();
431 }
432 builder.Bind(&far0).Bind(&far1).Bind(&far2).Bind(&far3).Bind(&far4);
433 builder.Return();
434
435 Handle<BytecodeArray> array = builder.ToBytecodeArray();
436 DCHECK_EQ(array->length(), 36 + kFarJumpDistance - 18 + 1);
437
438 BytecodeArrayIterator iterator(array);
439 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJump);
440 CHECK_EQ(iterator.GetImmediateOperand(0), 18);
441 iterator.Advance();
442
443 // Ignore compare operation.
444 iterator.Advance();
445
446 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfTrue);
447 CHECK_EQ(iterator.GetImmediateOperand(0), 14);
448 iterator.Advance();
449
450 // Ignore compare operation.
451 iterator.Advance();
452
453 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfFalse);
454 CHECK_EQ(iterator.GetImmediateOperand(0), 10);
455 iterator.Advance();
456
457 // Ignore add operation.
458 iterator.Advance();
459
460 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfToBooleanTrue);
461 CHECK_EQ(iterator.GetImmediateOperand(0), 6);
462 iterator.Advance();
463
464 // Ignore add operation.
465 iterator.Advance();
466
467 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfToBooleanFalse);
468 CHECK_EQ(iterator.GetImmediateOperand(0), 2);
469 iterator.Advance();
470
471
472 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpConstant);
473 CHECK_EQ(*iterator.GetConstantForIndexOperand(0),
474 Smi::FromInt(kFarJumpDistance));
475 iterator.Advance();
476
477 // Ignore compare operation.
478 iterator.Advance();
479
480 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfTrueConstant);
481 CHECK_EQ(*iterator.GetConstantForIndexOperand(0),
482 Smi::FromInt(kFarJumpDistance - 4));
483 iterator.Advance();
484
485 // Ignore compare operation.
486 iterator.Advance();
487
488 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfFalseConstant);
489 CHECK_EQ(*iterator.GetConstantForIndexOperand(0),
490 Smi::FromInt(kFarJumpDistance - 8));
491 iterator.Advance();
492
493 // Ignore add operation.
494 iterator.Advance();
495
496 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfToBooleanTrueConstant);
497 CHECK_EQ(*iterator.GetConstantForIndexOperand(0),
498 Smi::FromInt(kFarJumpDistance - 12));
499 iterator.Advance();
500
501 // Ignore add operation.
502 iterator.Advance();
503
504 CHECK_EQ(iterator.current_bytecode(),
505 Bytecode::kJumpIfToBooleanFalseConstant);
506 CHECK_EQ(*iterator.GetConstantForIndexOperand(0),
507 Smi::FromInt(kFarJumpDistance - 16));
508 iterator.Advance();
509}
510
511
512TEST_F(BytecodeArrayBuilderTest, BackwardJumps) {
Ben Murdoch109988c2016-05-18 11:27:45 +0100513 BytecodeArrayBuilder builder(isolate(), zone(), 0, 0, 1);
Ben Murdoch014dc512016-03-22 12:00:34 +0000514 Register reg(0);
515
516 BytecodeLabel label0, label1, label2, label3, label4;
517 builder.Bind(&label0)
518 .Jump(&label0)
519 .Bind(&label1)
Ben Murdoch109988c2016-05-18 11:27:45 +0100520 .CompareOperation(Token::Value::EQ, reg)
Ben Murdoch014dc512016-03-22 12:00:34 +0000521 .JumpIfTrue(&label1)
522 .Bind(&label2)
Ben Murdoch109988c2016-05-18 11:27:45 +0100523 .CompareOperation(Token::Value::EQ, reg)
Ben Murdoch014dc512016-03-22 12:00:34 +0000524 .JumpIfFalse(&label2)
525 .Bind(&label3)
Ben Murdoch109988c2016-05-18 11:27:45 +0100526 .BinaryOperation(Token::Value::ADD, reg)
Ben Murdoch014dc512016-03-22 12:00:34 +0000527 .JumpIfTrue(&label3)
528 .Bind(&label4)
Ben Murdoch109988c2016-05-18 11:27:45 +0100529 .BinaryOperation(Token::Value::ADD, reg)
Ben Murdoch014dc512016-03-22 12:00:34 +0000530 .JumpIfFalse(&label4);
531 for (int i = 0; i < 63; i++) {
532 builder.Jump(&label4);
533 }
Ben Murdoch109988c2016-05-18 11:27:45 +0100534 builder.BinaryOperation(Token::Value::ADD, reg).JumpIfFalse(&label4);
535 builder.BinaryOperation(Token::Value::ADD, reg).JumpIfTrue(&label3);
536 builder.CompareOperation(Token::Value::EQ, reg).JumpIfFalse(&label2);
537 builder.CompareOperation(Token::Value::EQ, reg).JumpIfTrue(&label1);
Ben Murdoch014dc512016-03-22 12:00:34 +0000538 builder.Jump(&label0);
539 builder.Return();
540
541 Handle<BytecodeArray> array = builder.ToBytecodeArray();
542 BytecodeArrayIterator iterator(array);
543 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJump);
544 CHECK_EQ(iterator.GetImmediateOperand(0), 0);
545 iterator.Advance();
546 // Ignore compare operation.
547 iterator.Advance();
548 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfTrue);
549 CHECK_EQ(iterator.GetImmediateOperand(0), -2);
550 iterator.Advance();
551 // Ignore compare operation.
552 iterator.Advance();
553 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfFalse);
554 CHECK_EQ(iterator.GetImmediateOperand(0), -2);
555 iterator.Advance();
556 // Ignore binary operation.
557 iterator.Advance();
558 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfToBooleanTrue);
559 CHECK_EQ(iterator.GetImmediateOperand(0), -2);
560 iterator.Advance();
561 // Ignore binary operation.
562 iterator.Advance();
563 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfToBooleanFalse);
564 CHECK_EQ(iterator.GetImmediateOperand(0), -2);
565 iterator.Advance();
566 for (int i = 0; i < 63; i++) {
567 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJump);
568 CHECK_EQ(iterator.GetImmediateOperand(0), -i * 2 - 4);
569 iterator.Advance();
570 }
571 // Ignore binary operation.
572 iterator.Advance();
573 CHECK_EQ(iterator.current_bytecode(),
574 Bytecode::kJumpIfToBooleanFalseConstant);
575 CHECK_EQ(Smi::cast(*iterator.GetConstantForIndexOperand(0))->value(), -132);
576 iterator.Advance();
577 // Ignore binary operation.
578 iterator.Advance();
579 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfToBooleanTrueConstant);
580 CHECK_EQ(Smi::cast(*iterator.GetConstantForIndexOperand(0))->value(), -140);
581 iterator.Advance();
582 // Ignore compare operation.
583 iterator.Advance();
584 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfFalseConstant);
585 CHECK_EQ(Smi::cast(*iterator.GetConstantForIndexOperand(0))->value(), -148);
586 iterator.Advance();
587 // Ignore compare operation.
588 iterator.Advance();
589 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfTrueConstant);
590 CHECK_EQ(Smi::cast(*iterator.GetConstantForIndexOperand(0))->value(), -156);
591 iterator.Advance();
592 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpConstant);
593 CHECK_EQ(Smi::cast(*iterator.GetConstantForIndexOperand(0))->value(), -160);
594 iterator.Advance();
595 CHECK_EQ(iterator.current_bytecode(), Bytecode::kReturn);
596 iterator.Advance();
597 CHECK(iterator.done());
598}
599
600
601TEST_F(BytecodeArrayBuilderTest, LabelReuse) {
Ben Murdoch109988c2016-05-18 11:27:45 +0100602 BytecodeArrayBuilder builder(isolate(), zone(), 0, 0, 0);
Ben Murdoch014dc512016-03-22 12:00:34 +0000603
604 // Labels can only have 1 forward reference, but
605 // can be referred to mulitple times once bound.
606 BytecodeLabel label;
607
608 builder.Jump(&label).Bind(&label).Jump(&label).Jump(&label).Return();
609
610 Handle<BytecodeArray> array = builder.ToBytecodeArray();
611 BytecodeArrayIterator iterator(array);
612 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJump);
613 CHECK_EQ(iterator.GetImmediateOperand(0), 2);
614 iterator.Advance();
615 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJump);
616 CHECK_EQ(iterator.GetImmediateOperand(0), 0);
617 iterator.Advance();
618 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJump);
619 CHECK_EQ(iterator.GetImmediateOperand(0), -2);
620 iterator.Advance();
621 CHECK_EQ(iterator.current_bytecode(), Bytecode::kReturn);
622 iterator.Advance();
623 CHECK(iterator.done());
624}
625
626
627TEST_F(BytecodeArrayBuilderTest, LabelAddressReuse) {
628 static const int kRepeats = 3;
629
Ben Murdoch109988c2016-05-18 11:27:45 +0100630 BytecodeArrayBuilder builder(isolate(), zone(), 0, 0, 0);
Ben Murdoch014dc512016-03-22 12:00:34 +0000631 for (int i = 0; i < kRepeats; i++) {
632 BytecodeLabel label;
633 builder.Jump(&label).Bind(&label).Jump(&label).Jump(&label);
634 }
Ben Murdoch014dc512016-03-22 12:00:34 +0000635 builder.Return();
636
637 Handle<BytecodeArray> array = builder.ToBytecodeArray();
638 BytecodeArrayIterator iterator(array);
639 for (int i = 0; i < kRepeats; i++) {
640 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJump);
641 CHECK_EQ(iterator.GetImmediateOperand(0), 2);
642 iterator.Advance();
643 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJump);
644 CHECK_EQ(iterator.GetImmediateOperand(0), 0);
645 iterator.Advance();
646 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJump);
647 CHECK_EQ(iterator.GetImmediateOperand(0), -2);
648 iterator.Advance();
649 }
650 CHECK_EQ(iterator.current_bytecode(), Bytecode::kReturn);
651 iterator.Advance();
652 CHECK(iterator.done());
653}
654
Ben Murdoch014dc512016-03-22 12:00:34 +0000655} // namespace interpreter
656} // namespace internal
657} // namespace v8