• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 Local(int index) const;
75   Register Parameter(int parameter_index) const;
76 
77   // Constant loads to accumulator.
78   BytecodeArrayBuilder& LoadConstantPoolEntry(size_t entry);
79   BytecodeArrayBuilder& LoadLiteral(v8::internal::Smi* value);
80   BytecodeArrayBuilder& LoadLiteral(const AstRawString* raw_string);
81   BytecodeArrayBuilder& LoadLiteral(const Scope* scope);
82   BytecodeArrayBuilder& LoadLiteral(const AstValue* ast_value);
83   BytecodeArrayBuilder& LoadUndefined();
84   BytecodeArrayBuilder& LoadNull();
85   BytecodeArrayBuilder& LoadTheHole();
86   BytecodeArrayBuilder& LoadTrue();
87   BytecodeArrayBuilder& LoadFalse();
88 
89   // Global loads to the accumulator and stores from the accumulator.
90   BytecodeArrayBuilder& LoadGlobal(const AstRawString* name, int feedback_slot,
91                                    TypeofMode typeof_mode);
92   BytecodeArrayBuilder& StoreGlobal(const AstRawString* name, int feedback_slot,
93                                     LanguageMode language_mode);
94 
95   // Load the object at |slot_index| at |depth| in the context chain starting
96   // with |context| into the accumulator.
97   enum ContextSlotMutability { kImmutableSlot, kMutableSlot };
98   BytecodeArrayBuilder& LoadContextSlot(Register context, int slot_index,
99                                         int depth,
100                                         ContextSlotMutability immutable);
101 
102   // Stores the object in the accumulator into |slot_index| at |depth| in the
103   // context chain starting with |context|.
104   BytecodeArrayBuilder& StoreContextSlot(Register context, int slot_index,
105                                          int depth);
106 
107   // Load from a module variable into the accumulator. |depth| is the depth of
108   // the current context relative to the module context.
109   BytecodeArrayBuilder& LoadModuleVariable(int cell_index, int depth);
110 
111   // Store from the accumulator into a module variable. |depth| is the depth of
112   // the current context relative to the module context.
113   BytecodeArrayBuilder& StoreModuleVariable(int cell_index, int depth);
114 
115   // Register-accumulator transfers.
116   BytecodeArrayBuilder& LoadAccumulatorWithRegister(Register reg);
117   BytecodeArrayBuilder& StoreAccumulatorInRegister(Register reg);
118 
119   // Register-register transfer.
120   BytecodeArrayBuilder& MoveRegister(Register from, Register to);
121 
122   // Named load property.
123   BytecodeArrayBuilder& LoadNamedProperty(Register object,
124                                           const AstRawString* name,
125                                           int feedback_slot);
126   // Keyed load property. The key should be in the accumulator.
127   BytecodeArrayBuilder& LoadKeyedProperty(Register object, int feedback_slot);
128   // Named load property of the @@iterator symbol.
129   BytecodeArrayBuilder& LoadIteratorProperty(Register object,
130                                              int feedback_slot);
131   // Named load property of the @@asyncIterator symbol.
132   BytecodeArrayBuilder& LoadAsyncIteratorProperty(Register object,
133                                                   int feedback_slot);
134 
135   // Store properties. Flag for NeedsSetFunctionName() should
136   // be in the accumulator.
137   BytecodeArrayBuilder& StoreDataPropertyInLiteral(
138       Register object, Register name, DataPropertyInLiteralFlags flags,
139       int feedback_slot);
140 
141   // Store a property named by a property name. The value to be stored should be
142   // in the accumulator.
143   BytecodeArrayBuilder& StoreNamedProperty(Register object,
144                                            const AstRawString* name,
145                                            int feedback_slot,
146                                            LanguageMode language_mode);
147   // Store a property named by a constant from the constant pool. The value to
148   // be stored should be in the accumulator.
149   BytecodeArrayBuilder& StoreNamedProperty(Register object,
150                                            size_t constant_pool_entry,
151                                            int feedback_slot,
152                                            LanguageMode language_mode);
153   // Store an own property named by a constant from the constant pool. The
154   // value to be stored should be in the accumulator.
155   BytecodeArrayBuilder& StoreNamedOwnProperty(Register object,
156                                               const AstRawString* name,
157                                               int feedback_slot);
158   // Store a property keyed by a value in a register. The value to be stored
159   // should be in the accumulator.
160   BytecodeArrayBuilder& StoreKeyedProperty(Register object, Register key,
161                                            int feedback_slot,
162                                            LanguageMode language_mode);
163   // Store the home object property. The value to be stored should be in the
164   // accumulator.
165   BytecodeArrayBuilder& StoreHomeObjectProperty(Register object,
166                                                 int feedback_slot,
167                                                 LanguageMode language_mode);
168 
169   // Lookup the variable with |name|.
170   BytecodeArrayBuilder& LoadLookupSlot(const AstRawString* name,
171                                        TypeofMode typeof_mode);
172 
173   // Lookup the variable with |name|, which is known to be at |slot_index| at
174   // |depth| in the context chain if not shadowed by a context extension
175   // somewhere in that context chain.
176   BytecodeArrayBuilder& LoadLookupContextSlot(const AstRawString* name,
177                                               TypeofMode typeof_mode,
178                                               int slot_index, int depth);
179 
180   // Lookup the variable with |name|, which has its feedback in |feedback_slot|
181   // and is known to be global if not shadowed by a context extension somewhere
182   // up to |depth| in that context chain.
183   BytecodeArrayBuilder& LoadLookupGlobalSlot(const AstRawString* name,
184                                              TypeofMode typeof_mode,
185                                              int feedback_slot, int depth);
186 
187   // Store value in the accumulator into the variable with |name|.
188   BytecodeArrayBuilder& StoreLookupSlot(const AstRawString* name,
189                                         LanguageMode language_mode);
190 
191   // Create a new closure for a SharedFunctionInfo which will be inserted at
192   // constant pool index |shared_function_info_entry|.
193   BytecodeArrayBuilder& CreateClosure(size_t shared_function_info_entry,
194                                       int slot, int flags);
195 
196   // Create a new local context for a |scope| and a closure which should be
197   // in the accumulator.
198   BytecodeArrayBuilder& CreateBlockContext(const Scope* scope);
199 
200   // Create a new context for a catch block with |exception|, |name|,
201   // |scope|, and the closure in the accumulator.
202   BytecodeArrayBuilder& CreateCatchContext(Register exception,
203                                            const AstRawString* name,
204                                            const Scope* scope);
205 
206   // Create a new context with size |slots|.
207   BytecodeArrayBuilder& CreateFunctionContext(int slots);
208 
209   // Create a new eval context with size |slots|.
210   BytecodeArrayBuilder& CreateEvalContext(int slots);
211 
212   // Creates a new context with the given |scope| for a with-statement
213   // with the |object| in a register and the closure in the accumulator.
214   BytecodeArrayBuilder& CreateWithContext(Register object, const Scope* scope);
215 
216   // Create a new arguments object in the accumulator.
217   BytecodeArrayBuilder& CreateArguments(CreateArgumentsType type);
218 
219   // Literals creation.  Constant elements should be in the accumulator.
220   BytecodeArrayBuilder& CreateRegExpLiteral(const AstRawString* pattern,
221                                             int literal_index, int flags);
222   BytecodeArrayBuilder& CreateArrayLiteral(size_t constant_elements_entry,
223                                            int literal_index, int flags);
224   BytecodeArrayBuilder& CreateObjectLiteral(size_t constant_properties_entry,
225                                             int literal_index, int flags,
226                                             Register output);
227 
228   // Push the context in accumulator as the new context, and store in register
229   // |context|.
230   BytecodeArrayBuilder& PushContext(Register context);
231 
232   // Pop the current context and replace with |context|.
233   BytecodeArrayBuilder& PopContext(Register context);
234 
235   // Call a JS function. The JSFunction or Callable to be called should be in
236   // |callable|. The arguments should be in |args|, with the receiver in
237   // |args[0]|. The call type of the expression is in |call_type|. Type feedback
238   // is recorded in the |feedback_slot| in the type feedback vector.
239   BytecodeArrayBuilder& Call(
240       Register callable, RegisterList args, int feedback_slot,
241       Call::CallType call_type,
242       TailCallMode tail_call_mode = TailCallMode::kDisallow);
243 
244   // Call a JS function. The JSFunction or Callable to be called should be in
245   // |callable|, the receiver in |args[0]| and the arguments in |args[1]|
246   // onwards. The final argument must be a spread.
247   BytecodeArrayBuilder& CallWithSpread(Register callable, RegisterList args);
248 
249   // Call the Construct operator. The accumulator holds the |new_target|.
250   // The |constructor| is in a register and arguments are in |args|.
251   BytecodeArrayBuilder& Construct(Register constructor, RegisterList args,
252                                   int feedback_slot);
253 
254   // Call the Construct operator for use with a spread. The accumulator holds
255   // the |new_target|. The |constructor| is in a register and arguments are in
256   // |args|. The final argument must be a spread.
257   BytecodeArrayBuilder& ConstructWithSpread(Register constructor,
258                                             RegisterList args);
259 
260   // Call the runtime function with |function_id| and arguments |args|.
261   BytecodeArrayBuilder& CallRuntime(Runtime::FunctionId function_id,
262                                     RegisterList args);
263   // Call the runtime function with |function_id| with single argument |arg|.
264   BytecodeArrayBuilder& CallRuntime(Runtime::FunctionId function_id,
265                                     Register arg);
266   // Call the runtime function with |function_id| with no arguments.
267   BytecodeArrayBuilder& CallRuntime(Runtime::FunctionId function_id);
268 
269   // Call the runtime function with |function_id| and arguments |args|, that
270   // returns a pair of values. The return values will be returned in
271   // |return_pair|.
272   BytecodeArrayBuilder& CallRuntimeForPair(Runtime::FunctionId function_id,
273                                            RegisterList args,
274                                            RegisterList return_pair);
275   // Call the runtime function with |function_id| with single argument |arg|
276   // that returns a pair of values. The return values will be returned in
277   // |return_pair|.
278   BytecodeArrayBuilder& CallRuntimeForPair(Runtime::FunctionId function_id,
279                                            Register arg,
280                                            RegisterList return_pair);
281 
282   // Call the JS runtime function with |context_index| and arguments |args|.
283   BytecodeArrayBuilder& CallJSRuntime(int context_index, RegisterList args);
284 
285   // Operators (register holds the lhs value, accumulator holds the rhs value).
286   // Type feedback will be recorded in the |feedback_slot|
287   BytecodeArrayBuilder& BinaryOperation(Token::Value binop, Register reg,
288                                         int feedback_slot);
289 
290   // Count Operators (value stored in accumulator).
291   // Type feedback will be recorded in the |feedback_slot|
292   BytecodeArrayBuilder& CountOperation(Token::Value op, int feedback_slot);
293 
294   // Unary Operators.
295   BytecodeArrayBuilder& LogicalNot();
296   BytecodeArrayBuilder& TypeOf();
297 
298   // Expects a heap object in the accumulator. Returns its super constructor in
299   // the register |out| if it passes the IsConstructor test. Otherwise, it
300   // throws a TypeError exception.
301   BytecodeArrayBuilder& GetSuperConstructor(Register out);
302 
303   // Deletes property from an object. This expects that accumulator contains
304   // the key to be deleted and the register contains a reference to the object.
305   BytecodeArrayBuilder& Delete(Register object, LanguageMode language_mode);
306 
307   // Tests.
308   BytecodeArrayBuilder& CompareOperation(Token::Value op, Register reg,
309                                          int feedback_slot = kNoFeedbackSlot);
310 
311   // Converts accumulator and stores result in register |out|.
312   BytecodeArrayBuilder& ConvertAccumulatorToObject(Register out);
313   BytecodeArrayBuilder& ConvertAccumulatorToName(Register out);
314   BytecodeArrayBuilder& ConvertAccumulatorToNumber(Register out);
315 
316   // Flow Control.
317   BytecodeArrayBuilder& Bind(BytecodeLabel* label);
318   BytecodeArrayBuilder& Bind(const BytecodeLabel& target, BytecodeLabel* label);
319 
320   BytecodeArrayBuilder& Jump(BytecodeLabel* label);
321   BytecodeArrayBuilder& JumpIfTrue(BytecodeLabel* label);
322   BytecodeArrayBuilder& JumpIfFalse(BytecodeLabel* label);
323   BytecodeArrayBuilder& JumpIfNotHole(BytecodeLabel* label);
324   BytecodeArrayBuilder& JumpIfJSReceiver(BytecodeLabel* label);
325   BytecodeArrayBuilder& JumpIfNull(BytecodeLabel* label);
326   BytecodeArrayBuilder& JumpIfUndefined(BytecodeLabel* label);
327   BytecodeArrayBuilder& JumpLoop(BytecodeLabel* label, int loop_depth);
328 
329   BytecodeArrayBuilder& StackCheck(int position);
330 
331   // Sets the pending message to the value in the accumulator, and returns the
332   // previous pending message in the accumulator.
333   BytecodeArrayBuilder& SetPendingMessage();
334 
335   BytecodeArrayBuilder& Throw();
336   BytecodeArrayBuilder& ReThrow();
337   BytecodeArrayBuilder& Return();
338 
339   // Debugger.
340   BytecodeArrayBuilder& Debugger();
341 
342   // Complex flow control.
343   BytecodeArrayBuilder& ForInPrepare(Register receiver,
344                                      RegisterList cache_info_triple);
345   BytecodeArrayBuilder& ForInContinue(Register index, Register cache_length);
346   BytecodeArrayBuilder& ForInNext(Register receiver, Register index,
347                                   RegisterList cache_type_array_pair,
348                                   int feedback_slot);
349   BytecodeArrayBuilder& ForInStep(Register index);
350 
351   // Generators.
352   BytecodeArrayBuilder& SuspendGenerator(Register generator);
353   BytecodeArrayBuilder& ResumeGenerator(Register generator);
354 
355   // Exception handling.
356   BytecodeArrayBuilder& MarkHandler(int handler_id,
357                                     HandlerTable::CatchPrediction will_catch);
358   BytecodeArrayBuilder& MarkTryBegin(int handler_id, Register context);
359   BytecodeArrayBuilder& MarkTryEnd(int handler_id);
360 
361   // Creates a new handler table entry and returns a {hander_id} identifying the
362   // entry, so that it can be referenced by above exception handling support.
363   int NewHandlerEntry() { return handler_table_builder()->NewHandlerEntry(); }
364 
365   // Gets a constant pool entry.
366   size_t GetConstantPoolEntry(const AstRawString* raw_string);
367   size_t GetConstantPoolEntry(const AstValue* heap_number);
368   size_t GetConstantPoolEntry(const Scope* scope);
369 #define ENTRY_GETTER(NAME, ...) size_t NAME##ConstantPoolEntry();
370   SINGLETON_CONSTANT_ENTRY_TYPES(ENTRY_GETTER)
371 #undef ENTRY_GETTER
372 
373   // Allocates a slot in the constant pool which can later be set.
374   size_t AllocateDeferredConstantPoolEntry();
375   // Sets the deferred value into an allocated constant pool entry.
376   void SetDeferredConstantPoolEntry(size_t entry, Handle<Object> object);
377 
378   void InitializeReturnPosition(FunctionLiteral* literal);
379 
380   void SetStatementPosition(Statement* stmt) {
381     if (stmt->position() == kNoSourcePosition) return;
382     latest_source_info_.MakeStatementPosition(stmt->position());
383   }
384 
385   void SetExpressionPosition(Expression* expr) {
386     if (expr->position() == kNoSourcePosition) return;
387     if (!latest_source_info_.is_statement()) {
388       // Ensure the current expression position is overwritten with the
389       // latest value.
390       latest_source_info_.MakeExpressionPosition(expr->position());
391     }
392   }
393 
394   void SetExpressionAsStatementPosition(Expression* expr) {
395     if (expr->position() == kNoSourcePosition) return;
396     latest_source_info_.MakeStatementPosition(expr->position());
397   }
398 
399   bool RequiresImplicitReturn() const { return !return_seen_in_block_; }
400 
401   // Returns the raw operand value for the given register or register list.
402   uint32_t GetInputRegisterOperand(Register reg);
403   uint32_t GetOutputRegisterOperand(Register reg);
404   uint32_t GetInputRegisterListOperand(RegisterList reg_list);
405   uint32_t GetOutputRegisterListOperand(RegisterList reg_list);
406 
407   // Accessors
408   BytecodeRegisterAllocator* register_allocator() {
409     return &register_allocator_;
410   }
411   const BytecodeRegisterAllocator* register_allocator() const {
412     return &register_allocator_;
413   }
414   Zone* zone() const { return zone_; }
415 
416  private:
417   friend class BytecodeRegisterAllocator;
418   template <Bytecode bytecode, AccumulatorUse accumulator_use,
419             OperandType... operand_types>
420   friend class BytecodeNodeBuilder;
421 
422   const FeedbackVectorSpec* feedback_vector_spec() const {
423     return literal_->feedback_vector_spec();
424   }
425 
426   // Returns the current source position for the given |bytecode|.
427   INLINE(BytecodeSourceInfo CurrentSourcePosition(Bytecode bytecode));
428 
429 #define DECLARE_BYTECODE_OUTPUT(Name, ...)         \
430   template <typename... Operands>                  \
431   INLINE(void Output##Name(Operands... operands)); \
432   template <typename... Operands>                  \
433   INLINE(void Output##Name(BytecodeLabel* label, Operands... operands));
434   BYTECODE_LIST(DECLARE_BYTECODE_OUTPUT)
435 #undef DECLARE_OPERAND_TYPE_INFO
436 
437   bool RegisterIsValid(Register reg) const;
438   bool RegisterListIsValid(RegisterList reg_list) const;
439 
440   // Set position for return.
441   void SetReturnPosition();
442 
443   // Not implemented as the illegal bytecode is used inside internally
444   // to indicate a bytecode field is not valid or an error has occured
445   // during bytecode generation.
446   BytecodeArrayBuilder& Illegal();
447 
448   template <Bytecode bytecode, AccumulatorUse accumulator_use>
449   void PrepareToOutputBytecode();
450 
451   void LeaveBasicBlock() { return_seen_in_block_ = false; }
452 
453   BytecodeArrayWriter* bytecode_array_writer() {
454     return &bytecode_array_writer_;
455   }
456   BytecodePipelineStage* pipeline() { return pipeline_; }
457   ConstantArrayBuilder* constant_array_builder() {
458     return &constant_array_builder_;
459   }
460   const ConstantArrayBuilder* constant_array_builder() const {
461     return &constant_array_builder_;
462   }
463   HandlerTableBuilder* handler_table_builder() {
464     return &handler_table_builder_;
465   }
466 
467   Zone* zone_;
468   FunctionLiteral* literal_;
469   bool bytecode_generated_;
470   ConstantArrayBuilder constant_array_builder_;
471   HandlerTableBuilder handler_table_builder_;
472   bool return_seen_in_block_;
473   int parameter_count_;
474   int local_register_count_;
475   int context_register_count_;
476   int return_position_;
477   BytecodeRegisterAllocator register_allocator_;
478   BytecodeArrayWriter bytecode_array_writer_;
479   BytecodePipelineStage* pipeline_;
480   BytecodeRegisterOptimizer* register_optimizer_;
481   BytecodeSourceInfo latest_source_info_;
482 
483   static int const kNoFeedbackSlot = 0;
484 
485   DISALLOW_COPY_AND_ASSIGN(BytecodeArrayBuilder);
486 };
487 
488 }  // namespace interpreter
489 }  // namespace internal
490 }  // namespace v8
491 
492 #endif  // V8_INTERPRETER_BYTECODE_ARRAY_BUILDER_H_
493