blob: fe693371845c3f56c12d10e37a37debe1552aad3 [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"
Ben Murdoch097c5b22016-05-18 11:27:45 +01009#include "src/interpreter/bytecode-register-allocator.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000010#include "src/interpreter/bytecodes.h"
11#include "src/interpreter/constant-array-builder.h"
Ben Murdoch097c5b22016-05-18 11:27:45 +010012#include "src/interpreter/handler-table-builder.h"
13#include "src/interpreter/register-translator.h"
14#include "src/interpreter/source-position-table.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015#include "src/zone-containers.h"
16
17namespace v8 {
18namespace internal {
19
20class Isolate;
21
22namespace interpreter {
23
24class BytecodeLabel;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000025class Register;
26
Ben Murdoch097c5b22016-05-18 11:27:45 +010027class BytecodeArrayBuilder final : public ZoneObject, private RegisterMover {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000028 public:
Ben Murdoch097c5b22016-05-18 11:27:45 +010029 BytecodeArrayBuilder(Isolate* isolate, Zone* zone, int parameter_count,
30 int context_count, int locals_count);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000031 ~BytecodeArrayBuilder();
32
33 Handle<BytecodeArray> ToBytecodeArray();
34
Ben Murdoch097c5b22016-05-18 11:27:45 +010035 // Get the number of parameters expected by function.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000036 int parameter_count() const {
37 DCHECK_GE(parameter_count_, 0);
38 return parameter_count_;
39 }
40
Ben Murdoch097c5b22016-05-18 11:27:45 +010041 // Get the number of locals required for bytecode array.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000042 int locals_count() const {
43 DCHECK_GE(local_register_count_, 0);
44 return local_register_count_;
45 }
46
Ben Murdoch097c5b22016-05-18 11:27:45 +010047 // Get number of contexts required for bytecode array.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000048 int context_count() const {
49 DCHECK_GE(context_register_count_, 0);
50 return context_register_count_;
51 }
52
53 Register first_context_register() const;
54 Register last_context_register() const;
55
56 // Returns the number of fixed (non-temporary) registers.
57 int fixed_register_count() const { return context_count() + locals_count(); }
58
Ben Murdoch097c5b22016-05-18 11:27:45 +010059 // Returns the number of fixed and temporary registers.
60 int fixed_and_temporary_register_count() const {
61 return fixed_register_count() + temporary_register_count();
62 }
63
64 int temporary_register_count() const {
65 return temporary_register_allocator()->allocation_count();
66 }
67
68 // Returns the number of registers used for translating wide
69 // register operands into byte sized register operands.
70 int translation_register_count() const {
71 return RegisterTranslator::RegisterCountAdjustment(
72 fixed_and_temporary_register_count(), parameter_count());
73 }
74
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000075 Register Parameter(int parameter_index) const;
76
77 // Return true if the register |reg| represents a parameter or a
78 // local.
79 bool RegisterIsParameterOrLocal(Register reg) const;
80
Ben Murdoch097c5b22016-05-18 11:27:45 +010081 // Returns true if the register |reg| is a live temporary register.
82 bool TemporaryRegisterIsLive(Register reg) const;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000083
84 // Constant loads to accumulator.
85 BytecodeArrayBuilder& LoadLiteral(v8::internal::Smi* value);
86 BytecodeArrayBuilder& LoadLiteral(Handle<Object> object);
87 BytecodeArrayBuilder& LoadUndefined();
88 BytecodeArrayBuilder& LoadNull();
89 BytecodeArrayBuilder& LoadTheHole();
90 BytecodeArrayBuilder& LoadTrue();
91 BytecodeArrayBuilder& LoadFalse();
92 BytecodeArrayBuilder& LoadBooleanConstant(bool value);
93
94 // Global loads to the accumulator and stores from the accumulator.
95 BytecodeArrayBuilder& LoadGlobal(const Handle<String> name, int feedback_slot,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000096 TypeofMode typeof_mode);
97 BytecodeArrayBuilder& StoreGlobal(const Handle<String> name,
98 int feedback_slot,
99 LanguageMode language_mode);
100
101 // Load the object at |slot_index| in |context| into the accumulator.
102 BytecodeArrayBuilder& LoadContextSlot(Register context, int slot_index);
103
104 // Stores the object in the accumulator into |slot_index| of |context|.
105 BytecodeArrayBuilder& StoreContextSlot(Register context, int slot_index);
106
107 // Register-accumulator transfers.
108 BytecodeArrayBuilder& LoadAccumulatorWithRegister(Register reg);
109 BytecodeArrayBuilder& StoreAccumulatorInRegister(Register reg);
110
111 // Register-register transfer.
112 BytecodeArrayBuilder& MoveRegister(Register from, Register to);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000113
114 // Named load property.
115 BytecodeArrayBuilder& LoadNamedProperty(Register object,
Ben Murdoch097c5b22016-05-18 11:27:45 +0100116 const Handle<Name> name,
117 int feedback_slot);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000118 // Keyed load property. The key should be in the accumulator.
Ben Murdoch097c5b22016-05-18 11:27:45 +0100119 BytecodeArrayBuilder& LoadKeyedProperty(Register object, int feedback_slot);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000120
121 // Store properties. The value to be stored should be in the accumulator.
122 BytecodeArrayBuilder& StoreNamedProperty(Register object,
Ben Murdoch097c5b22016-05-18 11:27:45 +0100123 const Handle<Name> name,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000124 int feedback_slot,
125 LanguageMode language_mode);
126 BytecodeArrayBuilder& StoreKeyedProperty(Register object, Register key,
127 int feedback_slot,
128 LanguageMode language_mode);
129
130 // Lookup the variable with |name|.
131 BytecodeArrayBuilder& LoadLookupSlot(const Handle<String> name,
132 TypeofMode typeof_mode);
133
134 // Store value in the accumulator into the variable with |name|.
135 BytecodeArrayBuilder& StoreLookupSlot(const Handle<String> name,
136 LanguageMode language_mode);
137
138 // Create a new closure for the SharedFunctionInfo.
139 BytecodeArrayBuilder& CreateClosure(Handle<SharedFunctionInfo> shared_info,
140 PretenureFlag tenured);
141
142 // Create a new arguments object in the accumulator.
143 BytecodeArrayBuilder& CreateArguments(CreateArgumentsType type);
144
145 // Literals creation. Constant elements should be in the accumulator.
146 BytecodeArrayBuilder& CreateRegExpLiteral(Handle<String> pattern,
147 int literal_index, int flags);
148 BytecodeArrayBuilder& CreateArrayLiteral(Handle<FixedArray> constant_elements,
149 int literal_index, int flags);
150 BytecodeArrayBuilder& CreateObjectLiteral(
151 Handle<FixedArray> constant_properties, int literal_index, int flags);
152
153 // Push the context in accumulator as the new context, and store in register
154 // |context|.
155 BytecodeArrayBuilder& PushContext(Register context);
156
157 // Pop the current context and replace with |context|.
158 BytecodeArrayBuilder& PopContext(Register context);
159
160 // Call a JS function. The JSFunction or Callable to be called should be in
Ben Murdoch097c5b22016-05-18 11:27:45 +0100161 // |callable|, the receiver should be in |receiver_args| and all subsequent
162 // arguments should be in registers <receiver_args + 1> to
163 // <receiver_args + receiver_arg_count - 1>.
164 BytecodeArrayBuilder& Call(
165 Register callable, Register receiver_args, size_t receiver_arg_count,
166 int feedback_slot, TailCallMode tail_call_mode = TailCallMode::kDisallow);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000167
Ben Murdoch097c5b22016-05-18 11:27:45 +0100168 BytecodeArrayBuilder& TailCall(Register callable, Register receiver_args,
169 size_t receiver_arg_count, int feedback_slot) {
170 return Call(callable, receiver_args, receiver_arg_count, feedback_slot,
171 TailCallMode::kAllow);
172 }
173
174 // Call the new operator. The accumulator holds the |new_target|.
175 // The |constructor| is in a register followed by |arg_count|
176 // consecutive arguments starting at |first_arg| for the constuctor
177 // invocation.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000178 BytecodeArrayBuilder& New(Register constructor, Register first_arg,
179 size_t arg_count);
180
181 // Call the runtime function with |function_id|. The first argument should be
182 // in |first_arg| and all subsequent arguments should be in registers
Ben Murdoch097c5b22016-05-18 11:27:45 +0100183 // <first_arg + 1> to <first_arg + arg_count - 1>.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000184 BytecodeArrayBuilder& CallRuntime(Runtime::FunctionId function_id,
185 Register first_arg, size_t arg_count);
186
187 // Call the runtime function with |function_id| that returns a pair of values.
188 // The first argument should be in |first_arg| and all subsequent arguments
Ben Murdoch097c5b22016-05-18 11:27:45 +0100189 // should be in registers <first_arg + 1> to <first_arg + arg_count - 1>. The
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000190 // return values will be returned in <first_return> and <first_return + 1>.
191 BytecodeArrayBuilder& CallRuntimeForPair(Runtime::FunctionId function_id,
192 Register first_arg, size_t arg_count,
193 Register first_return);
194
195 // Call the JS runtime function with |context_index|. The the receiver should
Ben Murdoch097c5b22016-05-18 11:27:45 +0100196 // be in |receiver_args| and all subsequent arguments should be in registers
197 // <receiver + 1> to <receiver + receiver_args_count - 1>.
198 BytecodeArrayBuilder& CallJSRuntime(int context_index, Register receiver_args,
199 size_t receiver_args_count);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000200
201 // Operators (register holds the lhs value, accumulator holds the rhs value).
Ben Murdoch097c5b22016-05-18 11:27:45 +0100202 BytecodeArrayBuilder& BinaryOperation(Token::Value binop, Register reg);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000203
204 // Count Operators (value stored in accumulator).
Ben Murdoch097c5b22016-05-18 11:27:45 +0100205 BytecodeArrayBuilder& CountOperation(Token::Value op);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000206
207 // Unary Operators.
208 BytecodeArrayBuilder& LogicalNot();
209 BytecodeArrayBuilder& TypeOf();
210
211 // Deletes property from an object. This expects that accumulator contains
212 // the key to be deleted and the register contains a reference to the object.
213 BytecodeArrayBuilder& Delete(Register object, LanguageMode language_mode);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000214
215 // Tests.
Ben Murdoch097c5b22016-05-18 11:27:45 +0100216 BytecodeArrayBuilder& CompareOperation(Token::Value op, Register reg);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000217
218 // Casts.
219 BytecodeArrayBuilder& CastAccumulatorToBoolean();
220 BytecodeArrayBuilder& CastAccumulatorToJSObject();
221 BytecodeArrayBuilder& CastAccumulatorToName();
222 BytecodeArrayBuilder& CastAccumulatorToNumber();
223
224 // Flow Control.
225 BytecodeArrayBuilder& Bind(BytecodeLabel* label);
226 BytecodeArrayBuilder& Bind(const BytecodeLabel& target, BytecodeLabel* label);
227
228 BytecodeArrayBuilder& Jump(BytecodeLabel* label);
229 BytecodeArrayBuilder& JumpIfTrue(BytecodeLabel* label);
230 BytecodeArrayBuilder& JumpIfFalse(BytecodeLabel* label);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100231 BytecodeArrayBuilder& JumpIfNotHole(BytecodeLabel* label);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000232 BytecodeArrayBuilder& JumpIfNull(BytecodeLabel* label);
233 BytecodeArrayBuilder& JumpIfUndefined(BytecodeLabel* label);
234
Ben Murdoch097c5b22016-05-18 11:27:45 +0100235 BytecodeArrayBuilder& StackCheck();
236
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000237 BytecodeArrayBuilder& Throw();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100238 BytecodeArrayBuilder& ReThrow();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000239 BytecodeArrayBuilder& Return();
240
Ben Murdoch097c5b22016-05-18 11:27:45 +0100241 // Debugger.
242 BytecodeArrayBuilder& Debugger();
243
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000244 // Complex flow control.
Ben Murdoch097c5b22016-05-18 11:27:45 +0100245 BytecodeArrayBuilder& ForInPrepare(Register cache_info_triple);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000246 BytecodeArrayBuilder& ForInDone(Register index, Register cache_length);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100247 BytecodeArrayBuilder& ForInNext(Register receiver, Register index,
248 Register cache_type_array_pair);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000249 BytecodeArrayBuilder& ForInStep(Register index);
250
Ben Murdoch097c5b22016-05-18 11:27:45 +0100251 // Exception handling.
252 BytecodeArrayBuilder& MarkHandler(int handler_id, bool will_catch);
253 BytecodeArrayBuilder& MarkTryBegin(int handler_id, Register context);
254 BytecodeArrayBuilder& MarkTryEnd(int handler_id);
255
256 // Creates a new handler table entry and returns a {hander_id} identifying the
257 // entry, so that it can be referenced by above exception handling support.
258 int NewHandlerEntry() { return handler_table_builder()->NewHandlerEntry(); }
259
260 void SetStatementPosition(Statement* stmt);
261 void SetExpressionPosition(Expression* expr);
262
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000263 // Accessors
264 Zone* zone() const { return zone_; }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100265 TemporaryRegisterAllocator* temporary_register_allocator() {
266 return &temporary_allocator_;
267 }
268 const TemporaryRegisterAllocator* temporary_register_allocator() const {
269 return &temporary_allocator_;
270 }
271
272 void EnsureReturn(FunctionLiteral* literal);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000273
274 private:
Ben Murdoch097c5b22016-05-18 11:27:45 +0100275 class PreviousBytecodeHelper;
276 friend class BytecodeRegisterAllocator;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000277
278 static Bytecode BytecodeForBinaryOperation(Token::Value op);
279 static Bytecode BytecodeForCountOperation(Token::Value op);
280 static Bytecode BytecodeForCompareOperation(Token::Value op);
281 static Bytecode BytecodeForWideOperands(Bytecode bytecode);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000282 static Bytecode BytecodeForStoreIC(LanguageMode language_mode);
283 static Bytecode BytecodeForKeyedStoreIC(LanguageMode language_mode);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100284 static Bytecode BytecodeForLoadGlobal(TypeofMode typeof_mode);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000285 static Bytecode BytecodeForStoreGlobal(LanguageMode language_mode);
286 static Bytecode BytecodeForStoreLookupSlot(LanguageMode language_mode);
287 static Bytecode BytecodeForCreateArguments(CreateArgumentsType type);
288 static Bytecode BytecodeForDelete(LanguageMode language_mode);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100289 static Bytecode BytecodeForCall(TailCallMode tail_call_mode);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000290
291 static bool FitsInIdx8Operand(int value);
292 static bool FitsInIdx8Operand(size_t value);
293 static bool FitsInImm8Operand(int value);
294 static bool FitsInIdx16Operand(int value);
295 static bool FitsInIdx16Operand(size_t value);
296 static bool FitsInReg8Operand(Register value);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100297 static bool FitsInReg8OperandUntranslated(Register value);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000298 static bool FitsInReg16Operand(Register value);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100299 static bool FitsInReg16OperandUntranslated(Register value);
300
301 // RegisterMover interface.
302 void MoveRegisterUntranslated(Register from, Register to) override;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000303
304 static Bytecode GetJumpWithConstantOperand(Bytecode jump_smi8_operand);
305 static Bytecode GetJumpWithConstantWideOperand(Bytecode jump_smi8_operand);
306 static Bytecode GetJumpWithToBoolean(Bytecode jump_smi8_operand);
307
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000308 template <size_t N>
309 INLINE(void Output(Bytecode bytecode, uint32_t(&operands)[N]));
310 void Output(Bytecode bytecode, uint32_t operand0, uint32_t operand1,
311 uint32_t operand2, uint32_t operand3);
312 void Output(Bytecode bytecode, uint32_t operand0, uint32_t operand1,
313 uint32_t operand2);
314 void Output(Bytecode bytecode, uint32_t operand0, uint32_t operand1);
315 void Output(Bytecode bytecode, uint32_t operand0);
316 void Output(Bytecode bytecode);
317
318 BytecodeArrayBuilder& OutputJump(Bytecode jump_bytecode,
319 BytecodeLabel* label);
320 void PatchJump(const ZoneVector<uint8_t>::iterator& jump_target,
321 const ZoneVector<uint8_t>::iterator& jump_location);
322 void PatchIndirectJumpWith8BitOperand(
323 const ZoneVector<uint8_t>::iterator& jump_location, int delta);
324 void PatchIndirectJumpWith16BitOperand(
325 const ZoneVector<uint8_t>::iterator& jump_location, int delta);
326
327 void LeaveBasicBlock();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000328
329 bool OperandIsValid(Bytecode bytecode, int operand_index,
330 uint32_t operand_value) const;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100331 bool RegisterIsValid(Register reg, OperandType reg_type) const;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000332
Ben Murdoch097c5b22016-05-18 11:27:45 +0100333 bool LastBytecodeInSameBlock() const;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000334 bool NeedToBooleanCast();
335 bool IsRegisterInAccumulator(Register reg);
336
Ben Murdoch097c5b22016-05-18 11:27:45 +0100337 // Set position for implicit return.
338 void SetReturnPosition(FunctionLiteral* fun);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000339
340 // Gets a constant pool entry for the |object|.
341 size_t GetConstantPoolEntry(Handle<Object> object);
342
Ben Murdoch097c5b22016-05-18 11:27:45 +0100343 ZoneVector<uint8_t>* bytecodes() { return &bytecodes_; }
344 const ZoneVector<uint8_t>* bytecodes() const { return &bytecodes_; }
345 Isolate* isolate() const { return isolate_; }
346 ConstantArrayBuilder* constant_array_builder() {
347 return &constant_array_builder_;
348 }
349 const ConstantArrayBuilder* constant_array_builder() const {
350 return &constant_array_builder_;
351 }
352 HandlerTableBuilder* handler_table_builder() {
353 return &handler_table_builder_;
354 }
355 SourcePositionTableBuilder* source_position_table_builder() {
356 return &source_position_table_builder_;
357 }
358 RegisterTranslator* register_translator() { return &register_translator_; }
359
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000360 Isolate* isolate_;
361 Zone* zone_;
362 ZoneVector<uint8_t> bytecodes_;
363 bool bytecode_generated_;
364 ConstantArrayBuilder constant_array_builder_;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100365 HandlerTableBuilder handler_table_builder_;
366 SourcePositionTableBuilder source_position_table_builder_;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000367 size_t last_block_end_;
368 size_t last_bytecode_start_;
369 bool exit_seen_in_block_;
370 int unbound_jumps_;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000371 int parameter_count_;
372 int local_register_count_;
373 int context_register_count_;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100374 TemporaryRegisterAllocator temporary_allocator_;
375 RegisterTranslator register_translator_;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000376
377 DISALLOW_COPY_AND_ASSIGN(BytecodeArrayBuilder);
378};
379
380
381// A label representing a branch target in a bytecode array. When a
382// label is bound, it represents a known position in the bytecode
383// array. For labels that are forward references there can be at most
384// one reference whilst it is unbound.
385class BytecodeLabel final {
386 public:
387 BytecodeLabel() : bound_(false), offset_(kInvalidOffset) {}
388
389 bool is_bound() const { return bound_; }
390 size_t offset() const { return offset_; }
391
392 private:
393 static const size_t kInvalidOffset = static_cast<size_t>(-1);
394
395 void bind_to(size_t offset) {
396 DCHECK(!bound_ && offset != kInvalidOffset);
397 offset_ = offset;
398 bound_ = true;
399 }
400
401 void set_referrer(size_t offset) {
402 DCHECK(!bound_ && offset != kInvalidOffset && offset_ == kInvalidOffset);
403 offset_ = offset;
404 }
405
406 bool is_forward_target() const {
407 return offset() != kInvalidOffset && !is_bound();
408 }
409
410 // There are three states for a label:
411 // bound_ offset_
412 // UNSET false kInvalidOffset
413 // FORWARD_TARGET false Offset of referring jump
414 // BACKWARD_TARGET true Offset of label in bytecode array when bound
415 bool bound_;
416 size_t offset_;
417
418 friend class BytecodeArrayBuilder;
419};
420
421} // namespace interpreter
422} // namespace internal
423} // namespace v8
424
425#endif // V8_INTERPRETER_BYTECODE_ARRAY_BUILDER_H_