blob: 7c23dc3f22caa035e19de98ad7759aef7d6bf15d [file] [log] [blame]
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001// Copyright 2015 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef V8_INTERPRETER_BYTECODE_ARRAY_BUILDER_H_
6#define V8_INTERPRETER_BYTECODE_ARRAY_BUILDER_H_
7
8#include "src/ast/ast.h"
9#include "src/interpreter/bytecodes.h"
10#include "src/interpreter/constant-array-builder.h"
11#include "src/zone-containers.h"
12
13namespace v8 {
14namespace internal {
15
16class Isolate;
17
18namespace interpreter {
19
20class BytecodeLabel;
21class ConstantArrayBuilder;
22class Register;
23
24// TODO(rmcilroy): Unify this with CreateArgumentsParameters::Type in Turbofan
25// when rest parameters implementation has settled down.
26enum class CreateArgumentsType { kMappedArguments, kUnmappedArguments };
27
28class BytecodeArrayBuilder final {
29 public:
30 BytecodeArrayBuilder(Isolate* isolate, Zone* zone);
31 ~BytecodeArrayBuilder();
32
33 Handle<BytecodeArray> ToBytecodeArray();
34
35 // Set the number of parameters expected by function.
36 void set_parameter_count(int number_of_params);
37 int parameter_count() const {
38 DCHECK_GE(parameter_count_, 0);
39 return parameter_count_;
40 }
41
42 // Set the number of locals required for bytecode array.
43 void set_locals_count(int number_of_locals);
44 int locals_count() const {
45 DCHECK_GE(local_register_count_, 0);
46 return local_register_count_;
47 }
48
49 // Set number of contexts required for bytecode array.
50 void set_context_count(int number_of_contexts);
51 int context_count() const {
52 DCHECK_GE(context_register_count_, 0);
53 return context_register_count_;
54 }
55
56 Register first_context_register() const;
57 Register last_context_register() const;
58
59 // Returns the number of fixed (non-temporary) registers.
60 int fixed_register_count() const { return context_count() + locals_count(); }
61
62 Register Parameter(int parameter_index) const;
63
64 // Return true if the register |reg| represents a parameter or a
65 // local.
66 bool RegisterIsParameterOrLocal(Register reg) const;
67
68 // Return true if the register |reg| represents a temporary register.
69 bool RegisterIsTemporary(Register reg) const;
70
71 // Constant loads to accumulator.
72 BytecodeArrayBuilder& LoadLiteral(v8::internal::Smi* value);
73 BytecodeArrayBuilder& LoadLiteral(Handle<Object> object);
74 BytecodeArrayBuilder& LoadUndefined();
75 BytecodeArrayBuilder& LoadNull();
76 BytecodeArrayBuilder& LoadTheHole();
77 BytecodeArrayBuilder& LoadTrue();
78 BytecodeArrayBuilder& LoadFalse();
79 BytecodeArrayBuilder& LoadBooleanConstant(bool value);
80
81 // Global loads to the accumulator and stores from the accumulator.
82 BytecodeArrayBuilder& LoadGlobal(const Handle<String> name, int feedback_slot,
83 LanguageMode language_mode,
84 TypeofMode typeof_mode);
85 BytecodeArrayBuilder& StoreGlobal(const Handle<String> name,
86 int feedback_slot,
87 LanguageMode language_mode);
88
89 // Load the object at |slot_index| in |context| into the accumulator.
90 BytecodeArrayBuilder& LoadContextSlot(Register context, int slot_index);
91
92 // Stores the object in the accumulator into |slot_index| of |context|.
93 BytecodeArrayBuilder& StoreContextSlot(Register context, int slot_index);
94
95 // Register-accumulator transfers.
96 BytecodeArrayBuilder& LoadAccumulatorWithRegister(Register reg);
97 BytecodeArrayBuilder& StoreAccumulatorInRegister(Register reg);
98
99 // Register-register transfer.
100 BytecodeArrayBuilder& MoveRegister(Register from, Register to);
101 BytecodeArrayBuilder& ExchangeRegisters(Register reg0, Register reg1);
102
103 // Named load property.
104 BytecodeArrayBuilder& LoadNamedProperty(Register object,
105 const Handle<String> name,
106 int feedback_slot,
107 LanguageMode language_mode);
108 // Keyed load property. The key should be in the accumulator.
109 BytecodeArrayBuilder& LoadKeyedProperty(Register object, int feedback_slot,
110 LanguageMode language_mode);
111
112 // Store properties. The value to be stored should be in the accumulator.
113 BytecodeArrayBuilder& StoreNamedProperty(Register object,
114 const Handle<String> name,
115 int feedback_slot,
116 LanguageMode language_mode);
117 BytecodeArrayBuilder& StoreKeyedProperty(Register object, Register key,
118 int feedback_slot,
119 LanguageMode language_mode);
120
121 // Lookup the variable with |name|.
122 BytecodeArrayBuilder& LoadLookupSlot(const Handle<String> name,
123 TypeofMode typeof_mode);
124
125 // Store value in the accumulator into the variable with |name|.
126 BytecodeArrayBuilder& StoreLookupSlot(const Handle<String> name,
127 LanguageMode language_mode);
128
129 // Create a new closure for the SharedFunctionInfo.
130 BytecodeArrayBuilder& CreateClosure(Handle<SharedFunctionInfo> shared_info,
131 PretenureFlag tenured);
132
133 // Create a new arguments object in the accumulator.
134 BytecodeArrayBuilder& CreateArguments(CreateArgumentsType type);
135
136 // Literals creation. Constant elements should be in the accumulator.
137 BytecodeArrayBuilder& CreateRegExpLiteral(Handle<String> pattern,
138 int literal_index, int flags);
139 BytecodeArrayBuilder& CreateArrayLiteral(Handle<FixedArray> constant_elements,
140 int literal_index, int flags);
141 BytecodeArrayBuilder& CreateObjectLiteral(
142 Handle<FixedArray> constant_properties, int literal_index, int flags);
143
144 // Push the context in accumulator as the new context, and store in register
145 // |context|.
146 BytecodeArrayBuilder& PushContext(Register context);
147
148 // Pop the current context and replace with |context|.
149 BytecodeArrayBuilder& PopContext(Register context);
150
151 // Call a JS function. The JSFunction or Callable to be called should be in
152 // |callable|, the receiver should be in |receiver| and all subsequent
153 // arguments should be in registers <receiver + 1> to
154 // <receiver + 1 + arg_count>.
155 BytecodeArrayBuilder& Call(Register callable, Register receiver,
156 size_t arg_count, int feedback_slot);
157
158 // Call the new operator. The |constructor| register is followed by
159 // |arg_count| consecutive registers containing arguments to be
160 // applied to the constructor.
161 BytecodeArrayBuilder& New(Register constructor, Register first_arg,
162 size_t arg_count);
163
164 // Call the runtime function with |function_id|. The first argument should be
165 // in |first_arg| and all subsequent arguments should be in registers
166 // <first_arg + 1> to <first_arg + 1 + arg_count>.
167 BytecodeArrayBuilder& CallRuntime(Runtime::FunctionId function_id,
168 Register first_arg, size_t arg_count);
169
170 // Call the runtime function with |function_id| that returns a pair of values.
171 // The first argument should be in |first_arg| and all subsequent arguments
172 // should be in registers <first_arg + 1> to <first_arg + 1 + arg_count>. The
173 // return values will be returned in <first_return> and <first_return + 1>.
174 BytecodeArrayBuilder& CallRuntimeForPair(Runtime::FunctionId function_id,
175 Register first_arg, size_t arg_count,
176 Register first_return);
177
178 // Call the JS runtime function with |context_index|. The the receiver should
179 // be in |receiver| and all subsequent arguments should be in registers
180 // <receiver + 1> to <receiver + 1 + arg_count>.
181 BytecodeArrayBuilder& CallJSRuntime(int context_index, Register receiver,
182 size_t arg_count);
183
184 // Operators (register holds the lhs value, accumulator holds the rhs value).
185 BytecodeArrayBuilder& BinaryOperation(Token::Value binop, Register reg,
186 Strength strength);
187
188 // Count Operators (value stored in accumulator).
189 BytecodeArrayBuilder& CountOperation(Token::Value op, Strength strength);
190
191 // Unary Operators.
192 BytecodeArrayBuilder& LogicalNot();
193 BytecodeArrayBuilder& TypeOf();
194
195 // Deletes property from an object. This expects that accumulator contains
196 // the key to be deleted and the register contains a reference to the object.
197 BytecodeArrayBuilder& Delete(Register object, LanguageMode language_mode);
198 BytecodeArrayBuilder& DeleteLookupSlot();
199
200 // Tests.
201 BytecodeArrayBuilder& CompareOperation(Token::Value op, Register reg,
202 Strength strength);
203
204 // Casts.
205 BytecodeArrayBuilder& CastAccumulatorToBoolean();
206 BytecodeArrayBuilder& CastAccumulatorToJSObject();
207 BytecodeArrayBuilder& CastAccumulatorToName();
208 BytecodeArrayBuilder& CastAccumulatorToNumber();
209
210 // Flow Control.
211 BytecodeArrayBuilder& Bind(BytecodeLabel* label);
212 BytecodeArrayBuilder& Bind(const BytecodeLabel& target, BytecodeLabel* label);
213
214 BytecodeArrayBuilder& Jump(BytecodeLabel* label);
215 BytecodeArrayBuilder& JumpIfTrue(BytecodeLabel* label);
216 BytecodeArrayBuilder& JumpIfFalse(BytecodeLabel* label);
217 BytecodeArrayBuilder& JumpIfNull(BytecodeLabel* label);
218 BytecodeArrayBuilder& JumpIfUndefined(BytecodeLabel* label);
219
220 BytecodeArrayBuilder& Throw();
221 BytecodeArrayBuilder& Return();
222
223 // Complex flow control.
224 BytecodeArrayBuilder& ForInPrepare(Register cache_type, Register cache_array,
225 Register cache_length);
226 BytecodeArrayBuilder& ForInDone(Register index, Register cache_length);
227 BytecodeArrayBuilder& ForInNext(Register receiver, Register cache_type,
228 Register cache_array, Register index);
229 BytecodeArrayBuilder& ForInStep(Register index);
230
231 // Accessors
232 Zone* zone() const { return zone_; }
233
234 private:
235 ZoneVector<uint8_t>* bytecodes() { return &bytecodes_; }
236 const ZoneVector<uint8_t>* bytecodes() const { return &bytecodes_; }
237 Isolate* isolate() const { return isolate_; }
238 ConstantArrayBuilder* constant_array_builder() {
239 return &constant_array_builder_;
240 }
241 const ConstantArrayBuilder* constant_array_builder() const {
242 return &constant_array_builder_;
243 }
244
245 static Bytecode BytecodeForBinaryOperation(Token::Value op);
246 static Bytecode BytecodeForCountOperation(Token::Value op);
247 static Bytecode BytecodeForCompareOperation(Token::Value op);
248 static Bytecode BytecodeForWideOperands(Bytecode bytecode);
249 static Bytecode BytecodeForLoadIC(LanguageMode language_mode);
250 static Bytecode BytecodeForKeyedLoadIC(LanguageMode language_mode);
251 static Bytecode BytecodeForStoreIC(LanguageMode language_mode);
252 static Bytecode BytecodeForKeyedStoreIC(LanguageMode language_mode);
253 static Bytecode BytecodeForLoadGlobal(LanguageMode language_mode,
254 TypeofMode typeof_mode);
255 static Bytecode BytecodeForStoreGlobal(LanguageMode language_mode);
256 static Bytecode BytecodeForStoreLookupSlot(LanguageMode language_mode);
257 static Bytecode BytecodeForCreateArguments(CreateArgumentsType type);
258 static Bytecode BytecodeForDelete(LanguageMode language_mode);
259
260 static bool FitsInIdx8Operand(int value);
261 static bool FitsInIdx8Operand(size_t value);
262 static bool FitsInImm8Operand(int value);
263 static bool FitsInIdx16Operand(int value);
264 static bool FitsInIdx16Operand(size_t value);
265 static bool FitsInReg8Operand(Register value);
266 static bool FitsInReg16Operand(Register value);
267
268 static Bytecode GetJumpWithConstantOperand(Bytecode jump_smi8_operand);
269 static Bytecode GetJumpWithConstantWideOperand(Bytecode jump_smi8_operand);
270 static Bytecode GetJumpWithToBoolean(Bytecode jump_smi8_operand);
271
272 Register MapRegister(Register reg);
273 Register MapRegisters(Register reg, Register args_base, int args_length = 1);
274
275 template <size_t N>
276 INLINE(void Output(Bytecode bytecode, uint32_t(&operands)[N]));
277 void Output(Bytecode bytecode, uint32_t operand0, uint32_t operand1,
278 uint32_t operand2, uint32_t operand3);
279 void Output(Bytecode bytecode, uint32_t operand0, uint32_t operand1,
280 uint32_t operand2);
281 void Output(Bytecode bytecode, uint32_t operand0, uint32_t operand1);
282 void Output(Bytecode bytecode, uint32_t operand0);
283 void Output(Bytecode bytecode);
284
285 BytecodeArrayBuilder& OutputJump(Bytecode jump_bytecode,
286 BytecodeLabel* label);
287 void PatchJump(const ZoneVector<uint8_t>::iterator& jump_target,
288 const ZoneVector<uint8_t>::iterator& jump_location);
289 void PatchIndirectJumpWith8BitOperand(
290 const ZoneVector<uint8_t>::iterator& jump_location, int delta);
291 void PatchIndirectJumpWith16BitOperand(
292 const ZoneVector<uint8_t>::iterator& jump_location, int delta);
293
294 void LeaveBasicBlock();
295 void EnsureReturn();
296
297 bool OperandIsValid(Bytecode bytecode, int operand_index,
298 uint32_t operand_value) const;
299 bool LastBytecodeInSameBlock() const;
300
301 bool NeedToBooleanCast();
302 bool IsRegisterInAccumulator(Register reg);
303
304 bool RegisterIsValid(Register reg) const;
305
306 // Temporary register management.
307 int BorrowTemporaryRegister();
308 int BorrowTemporaryRegisterNotInRange(int start_index, int end_index);
309 void ReturnTemporaryRegister(int reg_index);
310 int PrepareForConsecutiveTemporaryRegisters(size_t count);
311 void BorrowConsecutiveTemporaryRegister(int reg_index);
312 bool TemporaryRegisterIsLive(Register reg) const;
313
314 Register first_temporary_register() const;
315 Register last_temporary_register() const;
316
317 // Gets a constant pool entry for the |object|.
318 size_t GetConstantPoolEntry(Handle<Object> object);
319
320 Isolate* isolate_;
321 Zone* zone_;
322 ZoneVector<uint8_t> bytecodes_;
323 bool bytecode_generated_;
324 ConstantArrayBuilder constant_array_builder_;
325 size_t last_block_end_;
326 size_t last_bytecode_start_;
327 bool exit_seen_in_block_;
328 int unbound_jumps_;
329
330 int parameter_count_;
331 int local_register_count_;
332 int context_register_count_;
333 int temporary_register_count_;
334 ZoneSet<int> free_temporaries_;
335
336 class PreviousBytecodeHelper;
337 friend class BytecodeRegisterAllocator;
338
339 DISALLOW_COPY_AND_ASSIGN(BytecodeArrayBuilder);
340};
341
342
343// A label representing a branch target in a bytecode array. When a
344// label is bound, it represents a known position in the bytecode
345// array. For labels that are forward references there can be at most
346// one reference whilst it is unbound.
347class BytecodeLabel final {
348 public:
349 BytecodeLabel() : bound_(false), offset_(kInvalidOffset) {}
350
351 bool is_bound() const { return bound_; }
352 size_t offset() const { return offset_; }
353
354 private:
355 static const size_t kInvalidOffset = static_cast<size_t>(-1);
356
357 void bind_to(size_t offset) {
358 DCHECK(!bound_ && offset != kInvalidOffset);
359 offset_ = offset;
360 bound_ = true;
361 }
362
363 void set_referrer(size_t offset) {
364 DCHECK(!bound_ && offset != kInvalidOffset && offset_ == kInvalidOffset);
365 offset_ = offset;
366 }
367
368 bool is_forward_target() const {
369 return offset() != kInvalidOffset && !is_bound();
370 }
371
372 // There are three states for a label:
373 // bound_ offset_
374 // UNSET false kInvalidOffset
375 // FORWARD_TARGET false Offset of referring jump
376 // BACKWARD_TARGET true Offset of label in bytecode array when bound
377 bool bound_;
378 size_t offset_;
379
380 friend class BytecodeArrayBuilder;
381};
382
383} // namespace interpreter
384} // namespace internal
385} // namespace v8
386
387#endif // V8_INTERPRETER_BYTECODE_ARRAY_BUILDER_H_