blob: a569c9404785a965af2a0ac16c8796f3f895a767 [file] [log] [blame]
Ben Murdoch4a90d5f2016-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 Murdoch097c5b22016-05-18 11:27:45 +010024 BytecodeArrayBuilder builder(isolate(), zone(), 0, 1, 131);
Ben Murdochc5610432016-08-08 18:44:38 +010025 Factory* factory = isolate()->factory();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000026
Ben Murdoch097c5b22016-05-18 11:27:45 +010027 CHECK_EQ(builder.locals_count(), 131);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000028 CHECK_EQ(builder.context_count(), 1);
Ben Murdoch097c5b22016-05-18 11:27:45 +010029 CHECK_EQ(builder.fixed_register_count(), 132);
30
Ben Murdochc5610432016-08-08 18:44:38 +010031 Register reg(0);
32 Register other(reg.index() + 1);
33 Register wide(128);
34
Ben Murdoch097c5b22016-05-18 11:27:45 +010035 // Emit argument creation operations.
36 builder.CreateArguments(CreateArgumentsType::kMappedArguments)
37 .CreateArguments(CreateArgumentsType::kUnmappedArguments)
38 .CreateArguments(CreateArgumentsType::kRestParameter);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000039
40 // Emit constant loads.
41 builder.LoadLiteral(Smi::FromInt(0))
Ben Murdochc5610432016-08-08 18:44:38 +010042 .StoreAccumulatorInRegister(reg)
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000043 .LoadLiteral(Smi::FromInt(8))
Ben Murdochc5610432016-08-08 18:44:38 +010044 .StoreAccumulatorInRegister(reg)
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000045 .LoadLiteral(Smi::FromInt(10000000))
Ben Murdochc5610432016-08-08 18:44:38 +010046 .StoreAccumulatorInRegister(reg)
47 .LoadLiteral(factory->NewStringFromStaticChars("A constant"))
48 .StoreAccumulatorInRegister(reg)
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000049 .LoadUndefined()
Ben Murdochc5610432016-08-08 18:44:38 +010050 .StoreAccumulatorInRegister(reg)
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000051 .LoadNull()
Ben Murdochc5610432016-08-08 18:44:38 +010052 .StoreAccumulatorInRegister(reg)
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000053 .LoadTheHole()
Ben Murdochc5610432016-08-08 18:44:38 +010054 .StoreAccumulatorInRegister(reg)
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000055 .LoadTrue()
Ben Murdochc5610432016-08-08 18:44:38 +010056 .StoreAccumulatorInRegister(reg)
57 .LoadFalse()
58 .StoreAccumulatorInRegister(wide);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000059
Ben Murdochc5610432016-08-08 18:44:38 +010060 builder.StackCheck(0)
61 .LoadAccumulatorWithRegister(other)
62 .StoreAccumulatorInRegister(reg)
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000063 .LoadNull()
64 .StoreAccumulatorInRegister(reg);
65
66 // Emit register-register transfer.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000067 builder.MoveRegister(reg, other);
Ben Murdoch097c5b22016-05-18 11:27:45 +010068 builder.MoveRegister(reg, wide);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000069
70 // Emit global load / store operations.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000071 Handle<String> name = factory->NewStringFromStaticChars("var_name");
Ben Murdoch097c5b22016-05-18 11:27:45 +010072 builder.LoadGlobal(name, 1, TypeofMode::NOT_INSIDE_TYPEOF)
73 .LoadGlobal(name, 1, TypeofMode::INSIDE_TYPEOF)
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000074 .StoreGlobal(name, 1, LanguageMode::SLOPPY)
75 .StoreGlobal(name, 1, LanguageMode::STRICT);
76
77 // Emit context operations.
78 builder.PushContext(reg)
79 .PopContext(reg)
80 .LoadContextSlot(reg, 1)
81 .StoreContextSlot(reg, 1);
82
83 // Emit load / store property operations.
Ben Murdoch097c5b22016-05-18 11:27:45 +010084 builder.LoadNamedProperty(reg, name, 0)
85 .LoadKeyedProperty(reg, 0)
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000086 .StoreNamedProperty(reg, name, 0, LanguageMode::SLOPPY)
87 .StoreKeyedProperty(reg, reg, 0, LanguageMode::SLOPPY)
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000088 .StoreNamedProperty(reg, name, 0, LanguageMode::STRICT)
89 .StoreKeyedProperty(reg, reg, 0, LanguageMode::STRICT);
90
91 // Emit load / store lookup slots.
92 builder.LoadLookupSlot(name, TypeofMode::NOT_INSIDE_TYPEOF)
93 .LoadLookupSlot(name, TypeofMode::INSIDE_TYPEOF)
94 .StoreLookupSlot(name, LanguageMode::SLOPPY)
95 .StoreLookupSlot(name, LanguageMode::STRICT);
96
97 // Emit closure operations.
98 Handle<SharedFunctionInfo> shared_info = factory->NewSharedFunctionInfo(
99 factory->NewStringFromStaticChars("function_a"), MaybeHandle<Code>(),
100 false);
101 builder.CreateClosure(shared_info, NOT_TENURED);
102
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000103 // Emit literal creation operations.
104 builder.CreateRegExpLiteral(factory->NewStringFromStaticChars("a"), 0, 0)
105 .CreateArrayLiteral(factory->NewFixedArray(1), 0, 0)
106 .CreateObjectLiteral(factory->NewFixedArray(1), 0, 0);
107
108 // Call operations.
Ben Murdoch097c5b22016-05-18 11:27:45 +0100109 builder.Call(reg, other, 1, 0)
110 .Call(reg, wide, 1, 0)
111 .TailCall(reg, other, 1, 0)
112 .TailCall(reg, wide, 1, 0)
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000113 .CallRuntime(Runtime::kIsArray, reg, 1)
Ben Murdoch097c5b22016-05-18 11:27:45 +0100114 .CallRuntime(Runtime::kIsArray, wide, 1)
115 .CallRuntimeForPair(Runtime::kLoadLookupSlotForCall, reg, 1, other)
116 .CallRuntimeForPair(Runtime::kLoadLookupSlotForCall, wide, 1, other)
117 .CallJSRuntime(Context::SPREAD_ITERABLE_INDEX, reg, 1)
118 .CallJSRuntime(Context::SPREAD_ITERABLE_INDEX, wide, 1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000119
120 // Emit binary operator invocations.
Ben Murdoch097c5b22016-05-18 11:27:45 +0100121 builder.BinaryOperation(Token::Value::ADD, reg)
122 .BinaryOperation(Token::Value::SUB, reg)
123 .BinaryOperation(Token::Value::MUL, reg)
124 .BinaryOperation(Token::Value::DIV, reg)
125 .BinaryOperation(Token::Value::MOD, reg);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000126
127 // Emit bitwise operator invocations
Ben Murdoch097c5b22016-05-18 11:27:45 +0100128 builder.BinaryOperation(Token::Value::BIT_OR, reg)
129 .BinaryOperation(Token::Value::BIT_XOR, reg)
130 .BinaryOperation(Token::Value::BIT_AND, reg);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000131
132 // Emit shift operator invocations
Ben Murdoch097c5b22016-05-18 11:27:45 +0100133 builder.BinaryOperation(Token::Value::SHL, reg)
134 .BinaryOperation(Token::Value::SAR, reg)
135 .BinaryOperation(Token::Value::SHR, reg);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000136
137 // Emit count operatior invocations
Ben Murdoch097c5b22016-05-18 11:27:45 +0100138 builder.CountOperation(Token::Value::ADD).CountOperation(Token::Value::SUB);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000139
140 // Emit unary operator invocations.
Ben Murdochc5610432016-08-08 18:44:38 +0100141 builder
142 .LogicalNot() // ToBooleanLogicalNot
143 .LogicalNot() // non-ToBoolean LogicalNot
144 .TypeOf();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000145
146 // Emit delete
Ben Murdoch097c5b22016-05-18 11:27:45 +0100147 builder.Delete(reg, LanguageMode::SLOPPY).Delete(reg, LanguageMode::STRICT);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000148
149 // Emit new.
150 builder.New(reg, reg, 0);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100151 builder.New(wide, wide, 0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000152
153 // Emit test operator invocations.
Ben Murdoch097c5b22016-05-18 11:27:45 +0100154 builder.CompareOperation(Token::Value::EQ, reg)
155 .CompareOperation(Token::Value::NE, reg)
156 .CompareOperation(Token::Value::EQ_STRICT, reg)
Ben Murdoch097c5b22016-05-18 11:27:45 +0100157 .CompareOperation(Token::Value::LT, reg)
158 .CompareOperation(Token::Value::GT, reg)
159 .CompareOperation(Token::Value::LTE, reg)
160 .CompareOperation(Token::Value::GTE, reg)
161 .CompareOperation(Token::Value::INSTANCEOF, reg)
162 .CompareOperation(Token::Value::IN, reg);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000163
164 // Emit cast operator invocations.
165 builder.CastAccumulatorToNumber()
166 .CastAccumulatorToJSObject()
167 .CastAccumulatorToName();
168
169 // Emit control flow. Return must be the last instruction.
170 BytecodeLabel start;
171 builder.Bind(&start);
172 // Short jumps with Imm8 operands
173 builder.Jump(&start)
174 .JumpIfNull(&start)
Ben Murdoch097c5b22016-05-18 11:27:45 +0100175 .JumpIfUndefined(&start)
176 .JumpIfNotHole(&start);
177
Ben Murdochda12d292016-06-02 14:46:10 +0100178 // Longer jumps with constant operands
179 BytecodeLabel end[8];
180 builder.Jump(&end[0])
181 .LoadTrue()
182 .JumpIfTrue(&end[1])
183 .LoadTrue()
184 .JumpIfFalse(&end[2])
185 .LoadLiteral(Smi::FromInt(0))
186 .JumpIfTrue(&end[3])
187 .LoadLiteral(Smi::FromInt(0))
188 .JumpIfFalse(&end[4])
189 .JumpIfNull(&end[5])
190 .JumpIfUndefined(&end[6])
191 .JumpIfNotHole(&end[7]);
192
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000193 // Perform an operation that returns boolean value to
194 // generate JumpIfTrue/False
Ben Murdoch097c5b22016-05-18 11:27:45 +0100195 builder.CompareOperation(Token::Value::EQ, reg)
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000196 .JumpIfTrue(&start)
Ben Murdoch097c5b22016-05-18 11:27:45 +0100197 .CompareOperation(Token::Value::EQ, reg)
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000198 .JumpIfFalse(&start);
199 // Perform an operation that returns a non-boolean operation to
200 // generate JumpIfToBooleanTrue/False.
Ben Murdoch097c5b22016-05-18 11:27:45 +0100201 builder.BinaryOperation(Token::Value::ADD, reg)
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000202 .JumpIfTrue(&start)
Ben Murdoch097c5b22016-05-18 11:27:45 +0100203 .BinaryOperation(Token::Value::ADD, reg)
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000204 .JumpIfFalse(&start);
205 // Insert dummy ops to force longer jumps
206 for (int i = 0; i < 128; i++) {
207 builder.LoadTrue();
208 }
209 // Longer jumps requiring Constant operand
Ben Murdoch097c5b22016-05-18 11:27:45 +0100210 builder.Jump(&start).JumpIfNull(&start).JumpIfUndefined(&start).JumpIfNotHole(
211 &start);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000212 // Perform an operation that returns boolean value to
213 // generate JumpIfTrue/False
Ben Murdoch097c5b22016-05-18 11:27:45 +0100214 builder.CompareOperation(Token::Value::EQ, reg)
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000215 .JumpIfTrue(&start)
Ben Murdoch097c5b22016-05-18 11:27:45 +0100216 .CompareOperation(Token::Value::EQ, reg)
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000217 .JumpIfFalse(&start);
218 // Perform an operation that returns a non-boolean operation to
219 // generate JumpIfToBooleanTrue/False.
Ben Murdoch097c5b22016-05-18 11:27:45 +0100220 builder.BinaryOperation(Token::Value::ADD, reg)
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000221 .JumpIfTrue(&start)
Ben Murdoch097c5b22016-05-18 11:27:45 +0100222 .BinaryOperation(Token::Value::ADD, reg)
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000223 .JumpIfFalse(&start);
224
Ben Murdoch097c5b22016-05-18 11:27:45 +0100225 // Emit stack check bytecode.
Ben Murdochc5610432016-08-08 18:44:38 +0100226 builder.StackCheck(0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000227
Ben Murdoch097c5b22016-05-18 11:27:45 +0100228 // Emit throw and re-throw in it's own basic block so that the rest of the
229 // code isn't omitted due to being dead.
230 BytecodeLabel after_throw;
231 builder.Jump(&after_throw).Throw().Bind(&after_throw);
232 BytecodeLabel after_rethrow;
233 builder.Jump(&after_rethrow).ReThrow().Bind(&after_rethrow);
234
235 builder.ForInPrepare(reg)
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000236 .ForInDone(reg, reg)
Ben Murdochda12d292016-06-02 14:46:10 +0100237 .ForInNext(reg, reg, reg, 1)
Ben Murdoch097c5b22016-05-18 11:27:45 +0100238 .ForInStep(reg);
239 builder.ForInPrepare(wide)
240 .ForInDone(reg, other)
Ben Murdochda12d292016-06-02 14:46:10 +0100241 .ForInNext(wide, wide, wide, 1024)
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000242 .ForInStep(reg);
243
244 // Wide constant pool loads
245 for (int i = 0; i < 256; i++) {
246 // Emit junk in constant pool to force wide constant pool index.
247 builder.LoadLiteral(factory->NewNumber(2.5321 + i));
248 }
249 builder.LoadLiteral(Smi::FromInt(20000000));
250 Handle<String> wide_name = factory->NewStringFromStaticChars("var_wide_name");
251
252 // Emit wide global load / store operations.
Ben Murdoch097c5b22016-05-18 11:27:45 +0100253 builder.LoadGlobal(name, 1024, TypeofMode::NOT_INSIDE_TYPEOF)
254 .LoadGlobal(name, 1024, TypeofMode::INSIDE_TYPEOF)
Ben Murdochda12d292016-06-02 14:46:10 +0100255 .LoadGlobal(name, 1024, TypeofMode::INSIDE_TYPEOF)
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000256 .StoreGlobal(name, 1024, LanguageMode::SLOPPY)
257 .StoreGlobal(wide_name, 1, LanguageMode::STRICT);
258
Ben Murdochda12d292016-06-02 14:46:10 +0100259 // Emit extra wide global load.
260 builder.LoadGlobal(name, 1024 * 1024, TypeofMode::NOT_INSIDE_TYPEOF);
261
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000262 // Emit wide load / store property operations.
Ben Murdoch097c5b22016-05-18 11:27:45 +0100263 builder.LoadNamedProperty(reg, wide_name, 0)
264 .LoadKeyedProperty(reg, 2056)
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000265 .StoreNamedProperty(reg, wide_name, 0, LanguageMode::SLOPPY)
266 .StoreKeyedProperty(reg, reg, 2056, LanguageMode::SLOPPY)
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000267 .StoreNamedProperty(reg, wide_name, 0, LanguageMode::STRICT)
268 .StoreKeyedProperty(reg, reg, 2056, LanguageMode::STRICT);
269
270 // Emit wide context operations.
Ben Murdoch097c5b22016-05-18 11:27:45 +0100271 builder.LoadContextSlot(reg, 1024).StoreContextSlot(reg, 1024);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000272
273 // Emit wide load / store lookup slots.
274 builder.LoadLookupSlot(wide_name, TypeofMode::NOT_INSIDE_TYPEOF)
275 .LoadLookupSlot(wide_name, TypeofMode::INSIDE_TYPEOF)
276 .StoreLookupSlot(wide_name, LanguageMode::SLOPPY)
277 .StoreLookupSlot(wide_name, LanguageMode::STRICT);
278
279 // CreateClosureWide
280 Handle<SharedFunctionInfo> shared_info2 = factory->NewSharedFunctionInfo(
281 factory->NewStringFromStaticChars("function_b"), MaybeHandle<Code>(),
282 false);
283 builder.CreateClosure(shared_info2, NOT_TENURED);
284
285 // Emit wide variant of literal creation operations.
286 builder.CreateRegExpLiteral(factory->NewStringFromStaticChars("wide_literal"),
287 0, 0)
288 .CreateArrayLiteral(factory->NewFixedArray(2), 0, 0)
289 .CreateObjectLiteral(factory->NewFixedArray(2), 0, 0);
290
291 // Longer jumps requiring ConstantWide operand
Ben Murdoch097c5b22016-05-18 11:27:45 +0100292 builder.Jump(&start).JumpIfNull(&start).JumpIfUndefined(&start).JumpIfNotHole(
293 &start);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000294 // Perform an operation that returns boolean value to
295 // generate JumpIfTrue/False
Ben Murdoch097c5b22016-05-18 11:27:45 +0100296 builder.CompareOperation(Token::Value::EQ, reg)
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000297 .JumpIfTrue(&start)
Ben Murdoch097c5b22016-05-18 11:27:45 +0100298 .CompareOperation(Token::Value::EQ, reg)
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000299 .JumpIfFalse(&start);
300 // Perform an operation that returns a non-boolean operation to
301 // generate JumpIfToBooleanTrue/False.
Ben Murdoch097c5b22016-05-18 11:27:45 +0100302 builder.BinaryOperation(Token::Value::ADD, reg)
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000303 .JumpIfTrue(&start)
Ben Murdoch097c5b22016-05-18 11:27:45 +0100304 .BinaryOperation(Token::Value::ADD, reg)
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000305 .JumpIfFalse(&start);
306
Ben Murdochc5610432016-08-08 18:44:38 +0100307 // Emit generator operations
308 builder.SuspendGenerator(reg)
309 .ResumeGenerator(reg);
310
Ben Murdochda12d292016-06-02 14:46:10 +0100311 // Intrinsics handled by the interpreter.
312 builder.CallRuntime(Runtime::kInlineIsArray, reg, 1)
313 .CallRuntime(Runtime::kInlineIsArray, wide, 1);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100314
Ben Murdochda12d292016-06-02 14:46:10 +0100315 builder.Debugger();
316 for (size_t i = 0; i < arraysize(end); i++) {
317 builder.Bind(&end[i]);
318 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000319 builder.Return();
320
321 // Generate BytecodeArray.
322 Handle<BytecodeArray> the_array = builder.ToBytecodeArray();
323 CHECK_EQ(the_array->frame_size(),
Ben Murdochda12d292016-06-02 14:46:10 +0100324 builder.fixed_and_temporary_register_count() * kPointerSize);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000325
326 // Build scorecard of bytecodes encountered in the BytecodeArray.
327 std::vector<int> scorecard(Bytecodes::ToByte(Bytecode::kLast) + 1);
Ben Murdochda12d292016-06-02 14:46:10 +0100328
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000329 Bytecode final_bytecode = Bytecode::kLdaZero;
330 int i = 0;
331 while (i < the_array->length()) {
332 uint8_t code = the_array->get(i);
333 scorecard[code] += 1;
334 final_bytecode = Bytecodes::FromByte(code);
Ben Murdochda12d292016-06-02 14:46:10 +0100335 OperandScale operand_scale = OperandScale::kSingle;
336 int prefix_offset = 0;
337 if (Bytecodes::IsPrefixScalingBytecode(final_bytecode)) {
338 operand_scale = Bytecodes::PrefixBytecodeToOperandScale(final_bytecode);
339 prefix_offset = 1;
340 code = the_array->get(i + 1);
341 final_bytecode = Bytecodes::FromByte(code);
342 }
343 i += prefix_offset + Bytecodes::Size(final_bytecode, operand_scale);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000344 }
345
Ben Murdochda12d292016-06-02 14:46:10 +0100346 // Insert entry for illegal bytecode as this is never willingly emitted.
347 scorecard[Bytecodes::ToByte(Bytecode::kIllegal)] = 1;
348
Ben Murdochc5610432016-08-08 18:44:38 +0100349 // Insert entry for nop bytecode as this often gets optimized out.
350 scorecard[Bytecodes::ToByte(Bytecode::kNop)] = 1;
351
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000352 // Check return occurs at the end and only once in the BytecodeArray.
353 CHECK_EQ(final_bytecode, Bytecode::kReturn);
354 CHECK_EQ(scorecard[Bytecodes::ToByte(final_bytecode)], 1);
355
Ben Murdoch097c5b22016-05-18 11:27:45 +0100356#define CHECK_BYTECODE_PRESENT(Name, ...) \
357 /* Check Bytecode is marked in scorecard, unless it's a debug break */ \
358 if (!Bytecodes::IsDebugBreak(Bytecode::k##Name)) { \
359 CHECK_GE(scorecard[Bytecodes::ToByte(Bytecode::k##Name)], 1); \
360 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000361 BYTECODE_LIST(CHECK_BYTECODE_PRESENT)
362#undef CHECK_BYTECODE_PRESENT
363}
364
365
366TEST_F(BytecodeArrayBuilderTest, FrameSizesLookGood) {
367 for (int locals = 0; locals < 5; locals++) {
368 for (int contexts = 0; contexts < 4; contexts++) {
369 for (int temps = 0; temps < 3; temps++) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100370 BytecodeArrayBuilder builder(isolate(), zone(), 0, contexts, locals);
371 BytecodeRegisterAllocator temporaries(
372 zone(), builder.temporary_register_allocator());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000373 for (int i = 0; i < temps; i++) {
374 builder.StoreAccumulatorInRegister(temporaries.NewRegister());
375 }
376 builder.Return();
377
378 Handle<BytecodeArray> the_array = builder.ToBytecodeArray();
379 int total_registers = locals + contexts + temps;
380 CHECK_EQ(the_array->frame_size(), total_registers * kPointerSize);
381 }
382 }
383 }
384}
385
386
387TEST_F(BytecodeArrayBuilderTest, RegisterValues) {
388 int index = 1;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000389
390 Register the_register(index);
391 CHECK_EQ(the_register.index(), index);
392
393 int actual_operand = the_register.ToOperand();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000394 int actual_index = Register::FromOperand(actual_operand).index();
395 CHECK_EQ(actual_index, index);
396}
397
398
399TEST_F(BytecodeArrayBuilderTest, Parameters) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100400 BytecodeArrayBuilder builder(isolate(), zone(), 10, 0, 0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000401 Register param0(builder.Parameter(0));
402 Register param9(builder.Parameter(9));
403 CHECK_EQ(param9.index() - param0.index(), 9);
404}
405
406
407TEST_F(BytecodeArrayBuilderTest, RegisterType) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100408 BytecodeArrayBuilder builder(isolate(), zone(), 10, 0, 3);
409 BytecodeRegisterAllocator register_allocator(
410 zone(), builder.temporary_register_allocator());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000411 Register temp0 = register_allocator.NewRegister();
412 Register param0(builder.Parameter(0));
413 Register param9(builder.Parameter(9));
414 Register temp1 = register_allocator.NewRegister();
415 Register reg0(0);
416 Register reg1(1);
417 Register reg2(2);
418 Register temp2 = register_allocator.NewRegister();
419 CHECK_EQ(builder.RegisterIsParameterOrLocal(temp0), false);
420 CHECK_EQ(builder.RegisterIsParameterOrLocal(temp1), false);
421 CHECK_EQ(builder.RegisterIsParameterOrLocal(temp2), false);
422 CHECK_EQ(builder.RegisterIsParameterOrLocal(param0), true);
423 CHECK_EQ(builder.RegisterIsParameterOrLocal(param9), true);
424 CHECK_EQ(builder.RegisterIsParameterOrLocal(reg0), true);
425 CHECK_EQ(builder.RegisterIsParameterOrLocal(reg1), true);
426 CHECK_EQ(builder.RegisterIsParameterOrLocal(reg2), true);
427}
428
429
430TEST_F(BytecodeArrayBuilderTest, Constants) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100431 BytecodeArrayBuilder builder(isolate(), zone(), 0, 0, 0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000432 Factory* factory = isolate()->factory();
433 Handle<HeapObject> heap_num_1 = factory->NewHeapNumber(3.14);
434 Handle<HeapObject> heap_num_2 = factory->NewHeapNumber(5.2);
435 Handle<Object> large_smi(Smi::FromInt(0x12345678), isolate());
436 Handle<HeapObject> heap_num_2_copy(*heap_num_2);
437 builder.LoadLiteral(heap_num_1)
438 .LoadLiteral(heap_num_2)
439 .LoadLiteral(large_smi)
440 .LoadLiteral(heap_num_1)
441 .LoadLiteral(heap_num_1)
Ben Murdoch097c5b22016-05-18 11:27:45 +0100442 .LoadLiteral(heap_num_2_copy)
443 .Return();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000444
445 Handle<BytecodeArray> array = builder.ToBytecodeArray();
446 // Should only have one entry for each identical constant.
447 CHECK_EQ(array->constant_pool()->length(), 3);
448}
449
450
451TEST_F(BytecodeArrayBuilderTest, ForwardJumps) {
452 static const int kFarJumpDistance = 256;
453
Ben Murdoch097c5b22016-05-18 11:27:45 +0100454 BytecodeArrayBuilder builder(isolate(), zone(), 0, 0, 1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000455 Register reg(0);
456 BytecodeLabel far0, far1, far2, far3, far4;
457 BytecodeLabel near0, near1, near2, near3, near4;
458
459 builder.Jump(&near0)
Ben Murdoch097c5b22016-05-18 11:27:45 +0100460 .CompareOperation(Token::Value::EQ, reg)
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000461 .JumpIfTrue(&near1)
Ben Murdoch097c5b22016-05-18 11:27:45 +0100462 .CompareOperation(Token::Value::EQ, reg)
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000463 .JumpIfFalse(&near2)
Ben Murdoch097c5b22016-05-18 11:27:45 +0100464 .BinaryOperation(Token::Value::ADD, reg)
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000465 .JumpIfTrue(&near3)
Ben Murdoch097c5b22016-05-18 11:27:45 +0100466 .BinaryOperation(Token::Value::ADD, reg)
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000467 .JumpIfFalse(&near4)
468 .Bind(&near0)
469 .Bind(&near1)
470 .Bind(&near2)
471 .Bind(&near3)
472 .Bind(&near4)
473 .Jump(&far0)
Ben Murdoch097c5b22016-05-18 11:27:45 +0100474 .CompareOperation(Token::Value::EQ, reg)
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000475 .JumpIfTrue(&far1)
Ben Murdoch097c5b22016-05-18 11:27:45 +0100476 .CompareOperation(Token::Value::EQ, reg)
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000477 .JumpIfFalse(&far2)
Ben Murdoch097c5b22016-05-18 11:27:45 +0100478 .BinaryOperation(Token::Value::ADD, reg)
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000479 .JumpIfTrue(&far3)
Ben Murdoch097c5b22016-05-18 11:27:45 +0100480 .BinaryOperation(Token::Value::ADD, reg)
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000481 .JumpIfFalse(&far4);
482 for (int i = 0; i < kFarJumpDistance - 18; i++) {
Ben Murdochc5610432016-08-08 18:44:38 +0100483 builder.Debugger();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000484 }
485 builder.Bind(&far0).Bind(&far1).Bind(&far2).Bind(&far3).Bind(&far4);
486 builder.Return();
487
488 Handle<BytecodeArray> array = builder.ToBytecodeArray();
489 DCHECK_EQ(array->length(), 36 + kFarJumpDistance - 18 + 1);
490
491 BytecodeArrayIterator iterator(array);
492 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJump);
493 CHECK_EQ(iterator.GetImmediateOperand(0), 18);
494 iterator.Advance();
495
496 // Ignore compare operation.
497 iterator.Advance();
498
499 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfTrue);
500 CHECK_EQ(iterator.GetImmediateOperand(0), 14);
501 iterator.Advance();
502
503 // Ignore compare operation.
504 iterator.Advance();
505
506 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfFalse);
507 CHECK_EQ(iterator.GetImmediateOperand(0), 10);
508 iterator.Advance();
509
510 // Ignore add operation.
511 iterator.Advance();
512
513 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfToBooleanTrue);
514 CHECK_EQ(iterator.GetImmediateOperand(0), 6);
515 iterator.Advance();
516
517 // Ignore add operation.
518 iterator.Advance();
519
520 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfToBooleanFalse);
521 CHECK_EQ(iterator.GetImmediateOperand(0), 2);
522 iterator.Advance();
523
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000524 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpConstant);
525 CHECK_EQ(*iterator.GetConstantForIndexOperand(0),
526 Smi::FromInt(kFarJumpDistance));
527 iterator.Advance();
528
529 // Ignore compare operation.
530 iterator.Advance();
531
532 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfTrueConstant);
533 CHECK_EQ(*iterator.GetConstantForIndexOperand(0),
534 Smi::FromInt(kFarJumpDistance - 4));
535 iterator.Advance();
536
537 // Ignore compare operation.
538 iterator.Advance();
539
540 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfFalseConstant);
541 CHECK_EQ(*iterator.GetConstantForIndexOperand(0),
542 Smi::FromInt(kFarJumpDistance - 8));
543 iterator.Advance();
544
545 // Ignore add operation.
546 iterator.Advance();
547
548 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfToBooleanTrueConstant);
549 CHECK_EQ(*iterator.GetConstantForIndexOperand(0),
550 Smi::FromInt(kFarJumpDistance - 12));
551 iterator.Advance();
552
553 // Ignore add operation.
554 iterator.Advance();
555
556 CHECK_EQ(iterator.current_bytecode(),
557 Bytecode::kJumpIfToBooleanFalseConstant);
558 CHECK_EQ(*iterator.GetConstantForIndexOperand(0),
559 Smi::FromInt(kFarJumpDistance - 16));
560 iterator.Advance();
561}
562
563
564TEST_F(BytecodeArrayBuilderTest, BackwardJumps) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100565 BytecodeArrayBuilder builder(isolate(), zone(), 0, 0, 1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000566 Register reg(0);
567
568 BytecodeLabel label0, label1, label2, label3, label4;
569 builder.Bind(&label0)
570 .Jump(&label0)
571 .Bind(&label1)
Ben Murdoch097c5b22016-05-18 11:27:45 +0100572 .CompareOperation(Token::Value::EQ, reg)
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000573 .JumpIfTrue(&label1)
574 .Bind(&label2)
Ben Murdoch097c5b22016-05-18 11:27:45 +0100575 .CompareOperation(Token::Value::EQ, reg)
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000576 .JumpIfFalse(&label2)
577 .Bind(&label3)
Ben Murdoch097c5b22016-05-18 11:27:45 +0100578 .BinaryOperation(Token::Value::ADD, reg)
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000579 .JumpIfTrue(&label3)
580 .Bind(&label4)
Ben Murdoch097c5b22016-05-18 11:27:45 +0100581 .BinaryOperation(Token::Value::ADD, reg)
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000582 .JumpIfFalse(&label4);
583 for (int i = 0; i < 63; i++) {
584 builder.Jump(&label4);
585 }
Ben Murdochda12d292016-06-02 14:46:10 +0100586
587 // Add padding to force wide backwards jumps.
588 for (int i = 0; i < 256; i++) {
Ben Murdochc5610432016-08-08 18:44:38 +0100589 builder.Debugger();
Ben Murdochda12d292016-06-02 14:46:10 +0100590 }
591
Ben Murdoch097c5b22016-05-18 11:27:45 +0100592 builder.BinaryOperation(Token::Value::ADD, reg).JumpIfFalse(&label4);
593 builder.BinaryOperation(Token::Value::ADD, reg).JumpIfTrue(&label3);
594 builder.CompareOperation(Token::Value::EQ, reg).JumpIfFalse(&label2);
595 builder.CompareOperation(Token::Value::EQ, reg).JumpIfTrue(&label1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000596 builder.Jump(&label0);
597 builder.Return();
598
599 Handle<BytecodeArray> array = builder.ToBytecodeArray();
600 BytecodeArrayIterator iterator(array);
601 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJump);
602 CHECK_EQ(iterator.GetImmediateOperand(0), 0);
603 iterator.Advance();
604 // Ignore compare operation.
605 iterator.Advance();
606 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfTrue);
Ben Murdochda12d292016-06-02 14:46:10 +0100607 CHECK_EQ(iterator.current_operand_scale(), OperandScale::kSingle);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000608 CHECK_EQ(iterator.GetImmediateOperand(0), -2);
609 iterator.Advance();
610 // Ignore compare operation.
611 iterator.Advance();
612 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfFalse);
Ben Murdochda12d292016-06-02 14:46:10 +0100613 CHECK_EQ(iterator.current_operand_scale(), OperandScale::kSingle);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000614 CHECK_EQ(iterator.GetImmediateOperand(0), -2);
615 iterator.Advance();
616 // Ignore binary operation.
617 iterator.Advance();
618 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfToBooleanTrue);
Ben Murdochda12d292016-06-02 14:46:10 +0100619 CHECK_EQ(iterator.current_operand_scale(), OperandScale::kSingle);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000620 CHECK_EQ(iterator.GetImmediateOperand(0), -2);
621 iterator.Advance();
622 // Ignore binary operation.
623 iterator.Advance();
624 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfToBooleanFalse);
Ben Murdochda12d292016-06-02 14:46:10 +0100625 CHECK_EQ(iterator.current_operand_scale(), OperandScale::kSingle);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000626 CHECK_EQ(iterator.GetImmediateOperand(0), -2);
627 iterator.Advance();
628 for (int i = 0; i < 63; i++) {
629 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJump);
Ben Murdochda12d292016-06-02 14:46:10 +0100630 CHECK_EQ(iterator.current_operand_scale(), OperandScale::kSingle);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000631 CHECK_EQ(iterator.GetImmediateOperand(0), -i * 2 - 4);
632 iterator.Advance();
633 }
Ben Murdochda12d292016-06-02 14:46:10 +0100634 // Check padding to force wide backwards jumps.
635 for (int i = 0; i < 256; i++) {
Ben Murdochc5610432016-08-08 18:44:38 +0100636 CHECK_EQ(iterator.current_bytecode(), Bytecode::kDebugger);
Ben Murdochda12d292016-06-02 14:46:10 +0100637 iterator.Advance();
638 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000639 // Ignore binary operation.
640 iterator.Advance();
Ben Murdochda12d292016-06-02 14:46:10 +0100641 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfToBooleanFalse);
642 CHECK_EQ(iterator.current_operand_scale(), OperandScale::kDouble);
643 CHECK_EQ(iterator.GetImmediateOperand(0), -389);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000644 iterator.Advance();
645 // Ignore binary operation.
646 iterator.Advance();
Ben Murdochda12d292016-06-02 14:46:10 +0100647 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfToBooleanTrue);
648 CHECK_EQ(iterator.current_operand_scale(), OperandScale::kDouble);
649 CHECK_EQ(iterator.GetImmediateOperand(0), -399);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000650 iterator.Advance();
651 // Ignore compare operation.
652 iterator.Advance();
Ben Murdochda12d292016-06-02 14:46:10 +0100653 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfFalse);
654 CHECK_EQ(iterator.current_operand_scale(), OperandScale::kDouble);
655 CHECK_EQ(iterator.GetImmediateOperand(0), -409);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000656 iterator.Advance();
657 // Ignore compare operation.
658 iterator.Advance();
Ben Murdochda12d292016-06-02 14:46:10 +0100659 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpIfTrue);
660 CHECK_EQ(iterator.current_operand_scale(), OperandScale::kDouble);
661 CHECK_EQ(iterator.GetImmediateOperand(0), -419);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000662 iterator.Advance();
Ben Murdochda12d292016-06-02 14:46:10 +0100663 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJump);
664 CHECK_EQ(iterator.current_operand_scale(), OperandScale::kDouble);
665 CHECK_EQ(iterator.GetImmediateOperand(0), -425);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000666 iterator.Advance();
667 CHECK_EQ(iterator.current_bytecode(), Bytecode::kReturn);
668 iterator.Advance();
669 CHECK(iterator.done());
670}
671
672
673TEST_F(BytecodeArrayBuilderTest, LabelReuse) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100674 BytecodeArrayBuilder builder(isolate(), zone(), 0, 0, 0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000675
676 // Labels can only have 1 forward reference, but
677 // can be referred to mulitple times once bound.
678 BytecodeLabel label;
679
680 builder.Jump(&label).Bind(&label).Jump(&label).Jump(&label).Return();
681
682 Handle<BytecodeArray> array = builder.ToBytecodeArray();
683 BytecodeArrayIterator iterator(array);
684 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJump);
685 CHECK_EQ(iterator.GetImmediateOperand(0), 2);
686 iterator.Advance();
687 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJump);
688 CHECK_EQ(iterator.GetImmediateOperand(0), 0);
689 iterator.Advance();
690 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJump);
691 CHECK_EQ(iterator.GetImmediateOperand(0), -2);
692 iterator.Advance();
693 CHECK_EQ(iterator.current_bytecode(), Bytecode::kReturn);
694 iterator.Advance();
695 CHECK(iterator.done());
696}
697
698
699TEST_F(BytecodeArrayBuilderTest, LabelAddressReuse) {
700 static const int kRepeats = 3;
701
Ben Murdoch097c5b22016-05-18 11:27:45 +0100702 BytecodeArrayBuilder builder(isolate(), zone(), 0, 0, 0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000703 for (int i = 0; i < kRepeats; i++) {
704 BytecodeLabel label;
705 builder.Jump(&label).Bind(&label).Jump(&label).Jump(&label);
706 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000707 builder.Return();
708
709 Handle<BytecodeArray> array = builder.ToBytecodeArray();
710 BytecodeArrayIterator iterator(array);
711 for (int i = 0; i < kRepeats; i++) {
712 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJump);
713 CHECK_EQ(iterator.GetImmediateOperand(0), 2);
714 iterator.Advance();
715 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJump);
716 CHECK_EQ(iterator.GetImmediateOperand(0), 0);
717 iterator.Advance();
718 CHECK_EQ(iterator.current_bytecode(), Bytecode::kJump);
719 CHECK_EQ(iterator.GetImmediateOperand(0), -2);
720 iterator.Advance();
721 }
722 CHECK_EQ(iterator.current_bytecode(), Bytecode::kReturn);
723 iterator.Advance();
724 CHECK(iterator.done());
725}
726
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000727} // namespace interpreter
728} // namespace internal
729} // namespace v8