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_INTERPRETER_H_
6 #define V8_INTERPRETER_INTERPRETER_H_
7 
8 #include <memory>
9 
10 // Clients of this interface shouldn't depend on lots of interpreter internals.
11 // Do not include anything from src/interpreter other than
12 // src/interpreter/bytecodes.h here!
13 #include "src/base/macros.h"
14 #include "src/builtins/builtins.h"
15 #include "src/interpreter/bytecodes.h"
16 #include "src/parsing/token.h"
17 #include "src/runtime/runtime.h"
18 
19 namespace v8 {
20 namespace internal {
21 
22 class Isolate;
23 class Callable;
24 class CompilationInfo;
25 class CompilationJob;
26 
27 namespace compiler {
28 class Node;
29 }  // namespace compiler
30 
31 namespace interpreter {
32 
33 class InterpreterAssembler;
34 
35 class Interpreter {
36  public:
37   explicit Interpreter(Isolate* isolate);
~Interpreter()38   virtual ~Interpreter() {}
39 
40   // Initializes the interpreter dispatch table.
41   void Initialize();
42 
43   // Returns the interrupt budget which should be used for the profiler counter.
44   static int InterruptBudget();
45 
46   // Creates a compilation job which will generate bytecode for |info|.
47   static CompilationJob* NewCompilationJob(CompilationInfo* info);
48 
49   // Return bytecode handler for |bytecode|.
50   Code* GetBytecodeHandler(Bytecode bytecode, OperandScale operand_scale);
51 
52   // GC support.
53   void IterateDispatchTable(ObjectVisitor* v);
54 
55   // Disassembler support (only useful with ENABLE_DISASSEMBLER defined).
56   void TraceCodegen(Handle<Code> code);
57   const char* LookupNameOfBytecodeHandler(Code* code);
58 
59   V8_EXPORT_PRIVATE Local<v8::Object> GetDispatchCountersObject();
60 
dispatch_table_address()61   Address dispatch_table_address() {
62     return reinterpret_cast<Address>(&dispatch_table_[0]);
63   }
64 
bytecode_dispatch_counters_table()65   Address bytecode_dispatch_counters_table() {
66     return reinterpret_cast<Address>(bytecode_dispatch_counters_table_.get());
67   }
68 
69   // TODO(ignition): Tune code size multiplier.
70   static const int kCodeSizeMultiplier = 32;
71 
72  private:
73 // Bytecode handler generator functions.
74 #define DECLARE_BYTECODE_HANDLER_GENERATOR(Name, ...) \
75   void Do##Name(InterpreterAssembler* assembler);
76   BYTECODE_LIST(DECLARE_BYTECODE_HANDLER_GENERATOR)
77 #undef DECLARE_BYTECODE_HANDLER_GENERATOR
78 
79   typedef void (Interpreter::*BytecodeGeneratorFunc)(InterpreterAssembler*);
80 
81   // Generates handler for given |bytecode| and |operand_scale| using
82   // |generator| and installs it into the dispatch table.
83   void InstallBytecodeHandler(Zone* zone, Bytecode bytecode,
84                               OperandScale operand_scale,
85                               BytecodeGeneratorFunc generator);
86 
87   // Generates code to perform the binary operation via |Generator|.
88   template <class Generator>
89   void DoBinaryOpWithFeedback(InterpreterAssembler* assembler);
90 
91   // Generates code to perform the comparison via |Generator| while gathering
92   // type feedback.
93   void DoCompareOpWithFeedback(Token::Value compare_op,
94                                InterpreterAssembler* assembler);
95 
96   // Generates code to perform the bitwise binary operation corresponding to
97   // |bitwise_op| while gathering type feedback.
98   void DoBitwiseBinaryOp(Token::Value bitwise_op,
99                          InterpreterAssembler* assembler);
100 
101   // Generates code to perform the binary operation via |Generator| using
102   // an immediate value rather the accumulator as the rhs operand.
103   template <class Generator>
104   void DoBinaryOpWithImmediate(InterpreterAssembler* assembler);
105 
106   // Generates code to perform the unary operation via |Generator| while
107   // gatering type feedback.
108   template <class Generator>
109   void DoUnaryOpWithFeedback(InterpreterAssembler* assembler);
110 
111   // Generates code to perform the comparison operation associated with
112   // |compare_op|.
113   void DoCompareOp(Token::Value compare_op, InterpreterAssembler* assembler);
114 
115   // Generates code to perform a global store via |ic|.
116   void DoStaGlobal(Callable ic, InterpreterAssembler* assembler);
117 
118   // Generates code to perform a named property store via |ic|.
119   void DoStoreIC(Callable ic, InterpreterAssembler* assembler);
120 
121   // Generates code to perform a keyed property store via |ic|.
122   void DoKeyedStoreIC(Callable ic, InterpreterAssembler* assembler);
123 
124   // Generates code to perform a JS call that collects type feedback.
125   void DoJSCall(InterpreterAssembler* assembler, TailCallMode tail_call_mode);
126 
127   // Generates code to perform delete via function_id.
128   void DoDelete(Runtime::FunctionId function_id,
129                 InterpreterAssembler* assembler);
130 
131   // Generates code to perform a lookup slot load via |function_id|.
132   void DoLdaLookupSlot(Runtime::FunctionId function_id,
133                        InterpreterAssembler* assembler);
134 
135   // Generates code to perform a lookup slot load via |function_id| that can
136   // fast path to a context slot load.
137   void DoLdaLookupContextSlot(Runtime::FunctionId function_id,
138                               InterpreterAssembler* assembler);
139 
140   // Generates code to perform a lookup slot load via |function_id| that can
141   // fast path to a global load.
142   void DoLdaLookupGlobalSlot(Runtime::FunctionId function_id,
143                              InterpreterAssembler* assembler);
144 
145   // Generates code to perform a lookup slot store depending on
146   // |language_mode|.
147   void DoStaLookupSlot(LanguageMode language_mode,
148                        InterpreterAssembler* assembler);
149 
150   // Generates code to load a global.
151   void BuildLoadGlobal(int slot_operand_index, int name_operand_index,
152                        TypeofMode typeof_mode, InterpreterAssembler* assembler);
153 
154   // Generates code to prepare the result for ForInPrepare. Cache data
155   // are placed into the consecutive series of registers starting at
156   // |output_register|.
157   void BuildForInPrepareResult(compiler::Node* output_register,
158                                compiler::Node* cache_type,
159                                compiler::Node* cache_array,
160                                compiler::Node* cache_length,
161                                InterpreterAssembler* assembler);
162 
163   // Generates code to perform the unary operation via |callable|.
164   compiler::Node* BuildUnaryOp(Callable callable,
165                                InterpreterAssembler* assembler);
166 
167   uintptr_t GetDispatchCounter(Bytecode from, Bytecode to) const;
168 
169   // Get dispatch table index of bytecode.
170   static size_t GetDispatchTableIndex(Bytecode bytecode,
171                                       OperandScale operand_scale);
172 
173   bool IsDispatchTableInitialized();
174   bool ShouldInitializeDispatchTable();
175 
176   static const int kNumberOfWideVariants = 3;
177   static const int kDispatchTableSize = kNumberOfWideVariants * (kMaxUInt8 + 1);
178   static const int kNumberOfBytecodes = static_cast<int>(Bytecode::kLast) + 1;
179 
180   Isolate* isolate_;
181   Address dispatch_table_[kDispatchTableSize];
182   std::unique_ptr<uintptr_t[]> bytecode_dispatch_counters_table_;
183 
184   DISALLOW_COPY_AND_ASSIGN(Interpreter);
185 };
186 
187 }  // namespace interpreter
188 }  // namespace internal
189 }  // namespace v8
190 
191 #endif  // V8_INTERPRETER_INTERPRETER_H_
192