1 // 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/base/compiler-specific.h"
10 #include "src/globals.h"
11 #include "src/interpreter/bytecode-array-writer.h"
12 #include "src/interpreter/bytecode-register-allocator.h"
13 #include "src/interpreter/bytecode-register.h"
14 #include "src/interpreter/bytecodes.h"
15 #include "src/interpreter/constant-array-builder.h"
16 #include "src/interpreter/handler-table-builder.h"
17 #include "src/zone/zone-containers.h"
18 
19 namespace v8 {
20 namespace internal {
21 
22 class Isolate;
23 
24 namespace interpreter {
25 
26 class BytecodeLabel;
27 class BytecodeNode;
28 class BytecodePipelineStage;
29 class BytecodeRegisterOptimizer;
30 class Register;
31 
32 class V8_EXPORT_PRIVATE BytecodeArrayBuilder final
NON_EXPORTED_BASE(ZoneObject)33     : public NON_EXPORTED_BASE(ZoneObject) {
34  public:
35   BytecodeArrayBuilder(
36       Isolate* isolate, Zone* zone, int parameter_count, int context_count,
37       int locals_count, FunctionLiteral* literal = nullptr,
38       SourcePositionTableBuilder::RecordingMode source_position_mode =
39           SourcePositionTableBuilder::RECORD_SOURCE_POSITIONS);
40 
41   Handle<BytecodeArray> ToBytecodeArray(Isolate* isolate);
42 
43   // Get the number of parameters expected by function.
44   int parameter_count() const {
45     DCHECK_GE(parameter_count_, 0);
46     return parameter_count_;
47   }
48 
49   // Get the number of locals required for bytecode array.
50   int locals_count() const {
51     DCHECK_GE(local_register_count_, 0);
52     return local_register_count_;
53   }
54 
55   // Get number of contexts required for bytecode array.
56   int context_count() const {
57     DCHECK_GE(context_register_count_, 0);
58     return context_register_count_;
59   }
60 
61   Register first_context_register() const;
62   Register last_context_register() const;
63 
64   // Returns the number of fixed (non-temporary) registers.
65   int fixed_register_count() const { return context_count() + locals_count(); }
66 
67   // Returns the number of fixed and temporary registers.
68   int total_register_count() const {
69     DCHECK_LE(fixed_register_count(),
70               register_allocator()->maximum_register_count());
71     return register_allocator()->maximum_register_count();
72   }
73 
74   Register Parameter(int parameter_index) const;
75 
76   // Constant loads to accumulator.
77   BytecodeArrayBuilder& LoadConstantPoolEntry(size_t entry);
78   BytecodeArrayBuilder& LoadLiteral(v8::internal::Smi* value);
79   BytecodeArrayBuilder& LoadLiteral(Handle<Object> object);
80   BytecodeArrayBuilder& LoadUndefined();
81   BytecodeArrayBuilder& LoadNull();
82   BytecodeArrayBuilder& LoadTheHole();
83   BytecodeArrayBuilder& LoadTrue();
84   BytecodeArrayBuilder& LoadFalse();
85 
86   // Global loads to the accumulator and stores from the accumulator.
87   BytecodeArrayBuilder& LoadGlobal(int feedback_slot, TypeofMode typeof_mode);
88   BytecodeArrayBuilder& StoreGlobal(const Handle<String> name,
89                                     int feedback_slot,
90                                     LanguageMode language_mode);
91 
92   // Load the object at |slot_index| at |depth| in the context chain starting
93   // with |context| into the accumulator.
94   BytecodeArrayBuilder& LoadContextSlot(Register context, int slot_index,
95                                         int depth);
96 
97   // Stores the object in the accumulator into |slot_index| at |depth| in the
98   // context chain starting with |context|.
99   BytecodeArrayBuilder& StoreContextSlot(Register context, int slot_index,
100                                          int depth);
101 
102   // Load from a module variable into the accumulator. |depth| is the depth of
103   // the current context relative to the module context.
104   BytecodeArrayBuilder& LoadModuleVariable(int cell_index, int depth);
105 
106   // Store from the accumulator into a module variable. |depth| is the depth of
107   // the current context relative to the module context.
108   BytecodeArrayBuilder& StoreModuleVariable(int cell_index, int depth);
109 
110   // Register-accumulator transfers.
111   BytecodeArrayBuilder& LoadAccumulatorWithRegister(Register reg);
112   BytecodeArrayBuilder& StoreAccumulatorInRegister(Register reg);
113 
114   // Register-register transfer.
115   BytecodeArrayBuilder& MoveRegister(Register from, Register to);
116 
117   // Named load property.
118   BytecodeArrayBuilder& LoadNamedProperty(Register object,
119                                           const Handle<Name> name,
120                                           int feedback_slot);
121   // Keyed load property. The key should be in the accumulator.
122   BytecodeArrayBuilder& LoadKeyedProperty(Register object, int feedback_slot);
123 
124   // Store properties. The value to be stored should be in the accumulator.
125   BytecodeArrayBuilder& StoreNamedProperty(Register object,
126                                            const Handle<Name> name,
127                                            int feedback_slot,
128                                            LanguageMode language_mode);
129   BytecodeArrayBuilder& StoreKeyedProperty(Register object, Register key,
130                                            int feedback_slot,
131                                            LanguageMode language_mode);
132 
133   // Lookup the variable with |name|.
134   BytecodeArrayBuilder& LoadLookupSlot(const Handle<String> name,
135                                        TypeofMode typeof_mode);
136 
137   // Lookup the variable with |name|, which is known to be at |slot_index| at
138   // |depth| in the context chain if not shadowed by a context extension
139   // somewhere in that context chain.
140   BytecodeArrayBuilder& LoadLookupContextSlot(const Handle<String> name,
141                                               TypeofMode typeof_mode,
142                                               int slot_index, int depth);
143 
144   // Lookup the variable with |name|, which has its feedback in |feedback_slot|
145   // and is known to be global if not shadowed by a context extension somewhere
146   // up to |depth| in that context chain.
147   BytecodeArrayBuilder& LoadLookupGlobalSlot(const Handle<String> name,
148                                              TypeofMode typeof_mode,
149                                              int feedback_slot, int depth);
150 
151   // Store value in the accumulator into the variable with |name|.
152   BytecodeArrayBuilder& StoreLookupSlot(const Handle<String> name,
153                                         LanguageMode language_mode);
154 
155   // Create a new closure for a SharedFunctionInfo which will be inserted at
156   // constant pool index |entry|.
157   BytecodeArrayBuilder& CreateClosure(size_t entry, int flags);
158 
159   // Create a new local context for a |scope_info| and a closure which should be
160   // in the accumulator.
161   BytecodeArrayBuilder& CreateBlockContext(Handle<ScopeInfo> scope_info);
162 
163   // Create a new context for a catch block with |exception|, |name|,
164   // |scope_info|, and the closure in the accumulator.
165   BytecodeArrayBuilder& CreateCatchContext(Register exception,
166                                            Handle<String> name,
167                                            Handle<ScopeInfo> scope_info);
168 
169   // Create a new context with size |slots|.
170   BytecodeArrayBuilder& CreateFunctionContext(int slots);
171 
172   // Creates a new context with the given |scope_info| for a with-statement
173   // with the |object| in a register and the closure in the accumulator.
174   BytecodeArrayBuilder& CreateWithContext(Register object,
175                                           Handle<ScopeInfo> scope_info);
176 
177   // Create a new arguments object in the accumulator.
178   BytecodeArrayBuilder& CreateArguments(CreateArgumentsType type);
179 
180   // Literals creation.  Constant elements should be in the accumulator.
181   BytecodeArrayBuilder& CreateRegExpLiteral(Handle<String> pattern,
182                                             int literal_index, int flags);
183   BytecodeArrayBuilder& CreateArrayLiteral(Handle<FixedArray> constant_elements,
184                                            int literal_index, int flags);
185   BytecodeArrayBuilder& CreateObjectLiteral(
186       Handle<FixedArray> constant_properties, int literal_index, int flags,
187       Register output);
188 
189   // Push the context in accumulator as the new context, and store in register
190   // |context|.
191   BytecodeArrayBuilder& PushContext(Register context);
192 
193   // Pop the current context and replace with |context|.
194   BytecodeArrayBuilder& PopContext(Register context);
195 
196   // Call a JS function. The JSFunction or Callable to be called should be in
197   // |callable|. The arguments should be in |args|, with the receiver in
198   // |args[0]|. The call type of the expression is in |call_type|. Type feedback
199   // is recorded in the |feedback_slot| in the type feedback vector.
200   BytecodeArrayBuilder& Call(
201       Register callable, RegisterList args, int feedback_slot,
202       Call::CallType call_type,
203       TailCallMode tail_call_mode = TailCallMode::kDisallow);
204 
205   // Call the new operator. The accumulator holds the |new_target|.
206   // The |constructor| is in a register and arguments are in |args|.
207   BytecodeArrayBuilder& New(Register constructor, RegisterList args,
208                             int feedback_slot);
209 
210   // Call the runtime function with |function_id| and arguments |args|.
211   BytecodeArrayBuilder& CallRuntime(Runtime::FunctionId function_id,
212                                     RegisterList args);
213   // Call the runtime function with |function_id| with single argument |arg|.
214   BytecodeArrayBuilder& CallRuntime(Runtime::FunctionId function_id,
215                                     Register arg);
216   // Call the runtime function with |function_id| with no arguments.
217   BytecodeArrayBuilder& CallRuntime(Runtime::FunctionId function_id);
218 
219   // Call the runtime function with |function_id| and arguments |args|, that
220   // returns a pair of values. The return values will be returned in
221   // |return_pair|.
222   BytecodeArrayBuilder& CallRuntimeForPair(Runtime::FunctionId function_id,
223                                            RegisterList args,
224                                            RegisterList return_pair);
225   // Call the runtime function with |function_id| with single argument |arg|
226   // that returns a pair of values. The return values will be returned in
227   // |return_pair|.
228   BytecodeArrayBuilder& CallRuntimeForPair(Runtime::FunctionId function_id,
229                                            Register arg,
230                                            RegisterList return_pair);
231 
232   // Call the JS runtime function with |context_index| and arguments |args|.
233   BytecodeArrayBuilder& CallJSRuntime(int context_index, RegisterList args);
234 
235   // Operators (register holds the lhs value, accumulator holds the rhs value).
236   // Type feedback will be recorded in the |feedback_slot|
237   BytecodeArrayBuilder& BinaryOperation(Token::Value binop, Register reg,
238                                         int feedback_slot);
239 
240   // Count Operators (value stored in accumulator).
241   // Type feedback will be recorded in the |feedback_slot|
242   BytecodeArrayBuilder& CountOperation(Token::Value op, int feedback_slot);
243 
244   // Unary Operators.
245   BytecodeArrayBuilder& LogicalNot();
246   BytecodeArrayBuilder& TypeOf();
247 
248   // Deletes property from an object. This expects that accumulator contains
249   // the key to be deleted and the register contains a reference to the object.
250   BytecodeArrayBuilder& Delete(Register object, LanguageMode language_mode);
251 
252   // Tests.
253   BytecodeArrayBuilder& CompareOperation(Token::Value op, Register reg,
254                                          int feedback_slot = kNoFeedbackSlot);
255 
256   // Converts accumulator and stores result in register |out|.
257   BytecodeArrayBuilder& ConvertAccumulatorToObject(Register out);
258   BytecodeArrayBuilder& ConvertAccumulatorToName(Register out);
259   BytecodeArrayBuilder& ConvertAccumulatorToNumber(Register out);
260 
261   // Flow Control.
262   BytecodeArrayBuilder& Bind(BytecodeLabel* label);
263   BytecodeArrayBuilder& Bind(const BytecodeLabel& target, BytecodeLabel* label);
264 
265   BytecodeArrayBuilder& Jump(BytecodeLabel* label);
266   BytecodeArrayBuilder& JumpIfTrue(BytecodeLabel* label);
267   BytecodeArrayBuilder& JumpIfFalse(BytecodeLabel* label);
268   BytecodeArrayBuilder& JumpIfNotHole(BytecodeLabel* label);
269   BytecodeArrayBuilder& JumpIfNull(BytecodeLabel* label);
270   BytecodeArrayBuilder& JumpIfUndefined(BytecodeLabel* label);
271   BytecodeArrayBuilder& JumpLoop(BytecodeLabel* label, int loop_depth);
272 
273   BytecodeArrayBuilder& StackCheck(int position);
274 
275   BytecodeArrayBuilder& Throw();
276   BytecodeArrayBuilder& ReThrow();
277   BytecodeArrayBuilder& Return();
278 
279   // Debugger.
280   BytecodeArrayBuilder& Debugger();
281 
282   // Complex flow control.
283   BytecodeArrayBuilder& ForInPrepare(Register receiver,
284                                      RegisterList cache_info_triple);
285   BytecodeArrayBuilder& ForInContinue(Register index, Register cache_length);
286   BytecodeArrayBuilder& ForInNext(Register receiver, Register index,
287                                   RegisterList cache_type_array_pair,
288                                   int feedback_slot);
289   BytecodeArrayBuilder& ForInStep(Register index);
290 
291   // Generators.
292   BytecodeArrayBuilder& SuspendGenerator(Register generator);
293   BytecodeArrayBuilder& ResumeGenerator(Register generator);
294 
295   // Exception handling.
296   BytecodeArrayBuilder& MarkHandler(int handler_id,
297                                     HandlerTable::CatchPrediction will_catch);
298   BytecodeArrayBuilder& MarkTryBegin(int handler_id, Register context);
299   BytecodeArrayBuilder& MarkTryEnd(int handler_id);
300 
301   // Creates a new handler table entry and returns a {hander_id} identifying the
302   // entry, so that it can be referenced by above exception handling support.
303   int NewHandlerEntry() { return handler_table_builder()->NewHandlerEntry(); }
304 
305   // Allocates a slot in the constant pool which can later be inserted.
306   size_t AllocateConstantPoolEntry();
307   // Inserts a entry into an allocated constant pool entry.
308   void InsertConstantPoolEntryAt(size_t entry, Handle<Object> object);
309 
310   void InitializeReturnPosition(FunctionLiteral* literal);
311 
312   void SetStatementPosition(Statement* stmt) {
313     if (stmt->position() == kNoSourcePosition) return;
314     latest_source_info_.MakeStatementPosition(stmt->position());
315   }
316 
317   void SetExpressionPosition(Expression* expr) {
318     if (expr->position() == kNoSourcePosition) return;
319     if (!latest_source_info_.is_statement()) {
320       // Ensure the current expression position is overwritten with the
321       // latest value.
322       latest_source_info_.MakeExpressionPosition(expr->position());
323     }
324   }
325 
326   void SetExpressionAsStatementPosition(Expression* expr) {
327     if (expr->position() == kNoSourcePosition) return;
328     latest_source_info_.MakeStatementPosition(expr->position());
329   }
330 
331   bool RequiresImplicitReturn() const { return !return_seen_in_block_; }
332 
333   // Returns the raw operand value for the given register or register list.
334   uint32_t GetInputRegisterOperand(Register reg);
335   uint32_t GetOutputRegisterOperand(Register reg);
336   uint32_t GetInputRegisterListOperand(RegisterList reg_list);
337   uint32_t GetOutputRegisterListOperand(RegisterList reg_list);
338 
339   // Accessors
340   BytecodeRegisterAllocator* register_allocator() {
341     return &register_allocator_;
342   }
343   const BytecodeRegisterAllocator* register_allocator() const {
344     return &register_allocator_;
345   }
346   Zone* zone() const { return zone_; }
347 
348  private:
349   friend class BytecodeRegisterAllocator;
350   template <OperandType... operand_types>
351   friend class BytecodeNodeBuilder;
352 
353   // Returns the current source position for the given |bytecode|.
354   INLINE(BytecodeSourceInfo CurrentSourcePosition(Bytecode bytecode));
355 
356 #define DECLARE_BYTECODE_OUTPUT(Name, ...)         \
357   template <typename... Operands>                  \
358   INLINE(void Output##Name(Operands... operands)); \
359   template <typename... Operands>                  \
360   INLINE(void Output##Name(BytecodeLabel* label, Operands... operands));
361   BYTECODE_LIST(DECLARE_BYTECODE_OUTPUT)
362 #undef DECLARE_OPERAND_TYPE_INFO
363 
364   bool RegisterIsValid(Register reg) const;
365   bool RegisterListIsValid(RegisterList reg_list) const;
366 
367   // Set position for return.
368   void SetReturnPosition();
369 
370   // Gets a constant pool entry for the |object|.
371   size_t GetConstantPoolEntry(Handle<Object> object);
372 
373   // Not implemented as the illegal bytecode is used inside internally
374   // to indicate a bytecode field is not valid or an error has occured
375   // during bytecode generation.
376   BytecodeArrayBuilder& Illegal();
377 
378   void PrepareToOutputBytecode(Bytecode bytecode);
379 
380   void LeaveBasicBlock() { return_seen_in_block_ = false; }
381 
382   BytecodeArrayWriter* bytecode_array_writer() {
383     return &bytecode_array_writer_;
384   }
385   BytecodePipelineStage* pipeline() { return pipeline_; }
386   ConstantArrayBuilder* constant_array_builder() {
387     return &constant_array_builder_;
388   }
389   const ConstantArrayBuilder* constant_array_builder() const {
390     return &constant_array_builder_;
391   }
392   HandlerTableBuilder* handler_table_builder() {
393     return &handler_table_builder_;
394   }
395 
396   Zone* zone_;
397   bool bytecode_generated_;
398   ConstantArrayBuilder constant_array_builder_;
399   HandlerTableBuilder handler_table_builder_;
400   bool return_seen_in_block_;
401   int parameter_count_;
402   int local_register_count_;
403   int context_register_count_;
404   int return_position_;
405   BytecodeRegisterAllocator register_allocator_;
406   BytecodeArrayWriter bytecode_array_writer_;
407   BytecodePipelineStage* pipeline_;
408   BytecodeRegisterOptimizer* register_optimizer_;
409   BytecodeSourceInfo latest_source_info_;
410 
411   static int const kNoFeedbackSlot = 0;
412 
413   DISALLOW_COPY_AND_ASSIGN(BytecodeArrayBuilder);
414 };
415 
416 }  // namespace interpreter
417 }  // namespace internal
418 }  // namespace v8
419 
420 #endif  // V8_INTERPRETER_BYTECODE_ARRAY_BUILDER_H_
421