• 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_COMPILER_CODE_ASSEMBLER_H_
6 #define V8_COMPILER_CODE_ASSEMBLER_H_
7 
8 #include <map>
9 #include <memory>
10 
11 // Clients of this interface shouldn't depend on lots of compiler internals.
12 // Do not include anything from src/compiler here!
13 #include "src/allocation.h"
14 #include "src/builtins/builtins.h"
15 #include "src/code-factory.h"
16 #include "src/globals.h"
17 #include "src/heap/heap.h"
18 #include "src/machine-type.h"
19 #include "src/runtime/runtime.h"
20 #include "src/zone/zone-containers.h"
21 
22 namespace v8 {
23 namespace internal {
24 
25 class Callable;
26 class CallInterfaceDescriptor;
27 class Isolate;
28 class Factory;
29 class Zone;
30 
31 namespace compiler {
32 
33 class CallDescriptor;
34 class CodeAssemblerLabel;
35 class CodeAssemblerVariable;
36 class CodeAssemblerState;
37 class Node;
38 class RawMachineAssembler;
39 class RawMachineLabel;
40 
41 typedef ZoneList<CodeAssemblerVariable*> CodeAssemblerVariableList;
42 
43 typedef std::function<void()> CodeAssemblerCallback;
44 
45 #define CODE_ASSEMBLER_COMPARE_BINARY_OP_LIST(V) \
46   V(Float32Equal)                                \
47   V(Float32LessThan)                             \
48   V(Float32LessThanOrEqual)                      \
49   V(Float32GreaterThan)                          \
50   V(Float32GreaterThanOrEqual)                   \
51   V(Float64Equal)                                \
52   V(Float64LessThan)                             \
53   V(Float64LessThanOrEqual)                      \
54   V(Float64GreaterThan)                          \
55   V(Float64GreaterThanOrEqual)                   \
56   V(Int32GreaterThan)                            \
57   V(Int32GreaterThanOrEqual)                     \
58   V(Int32LessThan)                               \
59   V(Int32LessThanOrEqual)                        \
60   V(IntPtrLessThan)                              \
61   V(IntPtrLessThanOrEqual)                       \
62   V(IntPtrGreaterThan)                           \
63   V(IntPtrGreaterThanOrEqual)                    \
64   V(IntPtrEqual)                                 \
65   V(Uint32LessThan)                              \
66   V(Uint32LessThanOrEqual)                       \
67   V(Uint32GreaterThanOrEqual)                    \
68   V(UintPtrLessThan)                             \
69   V(UintPtrLessThanOrEqual)                      \
70   V(UintPtrGreaterThan)                          \
71   V(UintPtrGreaterThanOrEqual)                   \
72   V(WordEqual)                                   \
73   V(WordNotEqual)                                \
74   V(Word32Equal)                                 \
75   V(Word32NotEqual)                              \
76   V(Word64Equal)                                 \
77   V(Word64NotEqual)
78 
79 #define CODE_ASSEMBLER_BINARY_OP_LIST(V)   \
80   CODE_ASSEMBLER_COMPARE_BINARY_OP_LIST(V) \
81   V(Float64Add)                            \
82   V(Float64Sub)                            \
83   V(Float64Mul)                            \
84   V(Float64Div)                            \
85   V(Float64Mod)                            \
86   V(Float64Atan2)                          \
87   V(Float64Pow)                            \
88   V(Float64InsertLowWord32)                \
89   V(Float64InsertHighWord32)               \
90   V(IntPtrAddWithOverflow)                 \
91   V(IntPtrSubWithOverflow)                 \
92   V(IntPtrMul)                             \
93   V(Int32Add)                              \
94   V(Int32AddWithOverflow)                  \
95   V(Int32Sub)                              \
96   V(Int32Mul)                              \
97   V(Int32MulWithOverflow)                  \
98   V(Int32Div)                              \
99   V(Int32Mod)                              \
100   V(WordOr)                                \
101   V(WordAnd)                               \
102   V(WordXor)                               \
103   V(WordShl)                               \
104   V(WordShr)                               \
105   V(WordSar)                               \
106   V(WordRor)                               \
107   V(Word32Or)                              \
108   V(Word32And)                             \
109   V(Word32Xor)                             \
110   V(Word32Shl)                             \
111   V(Word32Shr)                             \
112   V(Word32Sar)                             \
113   V(Word32Ror)                             \
114   V(Word64Or)                              \
115   V(Word64And)                             \
116   V(Word64Xor)                             \
117   V(Word64Shr)                             \
118   V(Word64Sar)                             \
119   V(Word64Ror)
120 
121 #define CODE_ASSEMBLER_UNARY_OP_LIST(V) \
122   V(Float64Abs)                         \
123   V(Float64Acos)                        \
124   V(Float64Acosh)                       \
125   V(Float64Asin)                        \
126   V(Float64Asinh)                       \
127   V(Float64Atan)                        \
128   V(Float64Atanh)                       \
129   V(Float64Cos)                         \
130   V(Float64Cosh)                        \
131   V(Float64Exp)                         \
132   V(Float64Expm1)                       \
133   V(Float64Log)                         \
134   V(Float64Log1p)                       \
135   V(Float64Log2)                        \
136   V(Float64Log10)                       \
137   V(Float64Cbrt)                        \
138   V(Float64Neg)                         \
139   V(Float64Sin)                         \
140   V(Float64Sinh)                        \
141   V(Float64Sqrt)                        \
142   V(Float64Tan)                         \
143   V(Float64Tanh)                        \
144   V(Float64ExtractLowWord32)            \
145   V(Float64ExtractHighWord32)           \
146   V(BitcastTaggedToWord)                \
147   V(BitcastWordToTagged)                \
148   V(BitcastWordToTaggedSigned)          \
149   V(TruncateFloat64ToFloat32)           \
150   V(TruncateFloat64ToWord32)            \
151   V(TruncateInt64ToInt32)               \
152   V(ChangeFloat32ToFloat64)             \
153   V(ChangeFloat64ToUint32)              \
154   V(ChangeInt32ToFloat64)               \
155   V(ChangeInt32ToInt64)                 \
156   V(ChangeUint32ToFloat64)              \
157   V(ChangeUint32ToUint64)               \
158   V(RoundFloat64ToInt32)                \
159   V(RoundInt32ToFloat32)                \
160   V(Float64SilenceNaN)                  \
161   V(Float64RoundDown)                   \
162   V(Float64RoundUp)                     \
163   V(Float64RoundTiesEven)               \
164   V(Float64RoundTruncate)               \
165   V(Word32Clz)                          \
166   V(Word32Not)                          \
167   V(Word32BinaryNot)
168 
169 // A "public" interface used by components outside of compiler directory to
170 // create code objects with TurboFan's backend. This class is mostly a thin shim
171 // around the RawMachineAssembler, and its primary job is to ensure that the
172 // innards of the RawMachineAssembler and other compiler implementation details
173 // don't leak outside of the the compiler directory..
174 //
175 // V8 components that need to generate low-level code using this interface
176 // should include this header--and this header only--from the compiler directory
177 // (this is actually enforced). Since all interesting data structures are
178 // forward declared, it's not possible for clients to peek inside the compiler
179 // internals.
180 //
181 // In addition to providing isolation between TurboFan and code generation
182 // clients, CodeAssembler also provides an abstraction for creating variables
183 // and enhanced Label functionality to merge variable values along paths where
184 // they have differing values, including loops.
185 //
186 // The CodeAssembler itself is stateless (and instances are expected to be
187 // temporary-scoped and short-lived); all its state is encapsulated into
188 // a CodeAssemblerState instance.
189 class V8_EXPORT_PRIVATE CodeAssembler {
190  public:
CodeAssembler(CodeAssemblerState * state)191   explicit CodeAssembler(CodeAssemblerState* state) : state_(state) {}
192   ~CodeAssembler();
193 
194   static Handle<Code> GenerateCode(CodeAssemblerState* state);
195 
196   bool Is64() const;
197   bool IsFloat64RoundUpSupported() const;
198   bool IsFloat64RoundDownSupported() const;
199   bool IsFloat64RoundTiesEvenSupported() const;
200   bool IsFloat64RoundTruncateSupported() const;
201 
202   // Shortened aliases for use in CodeAssembler subclasses.
203   typedef CodeAssemblerLabel Label;
204   typedef CodeAssemblerVariable Variable;
205   typedef CodeAssemblerVariableList VariableList;
206 
207   // ===========================================================================
208   // Base Assembler
209   // ===========================================================================
210 
211   // Constants.
212   Node* Int32Constant(int32_t value);
213   Node* Int64Constant(int64_t value);
214   Node* IntPtrConstant(intptr_t value);
215   Node* NumberConstant(double value);
216   Node* SmiConstant(Smi* value);
217   Node* SmiConstant(int value);
218   Node* HeapConstant(Handle<HeapObject> object);
219   Node* CStringConstant(const char* str);
220   Node* BooleanConstant(bool value);
221   Node* ExternalConstant(ExternalReference address);
222   Node* Float64Constant(double value);
223   Node* NaNConstant();
224 
225   bool ToInt32Constant(Node* node, int32_t& out_value);
226   bool ToInt64Constant(Node* node, int64_t& out_value);
227   bool ToSmiConstant(Node* node, Smi*& out_value);
228   bool ToIntPtrConstant(Node* node, intptr_t& out_value);
229 
230   Node* Parameter(int value);
231   Node* GetJSContextParameter();
232   void Return(Node* value);
233   void Return(Node* value1, Node* value2);
234   void Return(Node* value1, Node* value2, Node* value3);
235   void PopAndReturn(Node* pop, Node* value);
236 
237   void DebugBreak();
238   void Unreachable();
239   void Comment(const char* format, ...);
240 
241   void Bind(Label* label);
242   void Goto(Label* label);
243   void GotoIf(Node* condition, Label* true_label);
244   void GotoIfNot(Node* condition, Label* false_label);
245   void Branch(Node* condition, Label* true_label, Label* false_label);
246 
247   void Switch(Node* index, Label* default_label, const int32_t* case_values,
248               Label** case_labels, size_t case_count);
249 
250   // Access to the frame pointer
251   Node* LoadFramePointer();
252   Node* LoadParentFramePointer();
253 
254   // Access to the stack pointer
255   Node* LoadStackPointer();
256 
257   // Load raw memory location.
258   Node* Load(MachineType rep, Node* base);
259   Node* Load(MachineType rep, Node* base, Node* offset);
260   Node* AtomicLoad(MachineType rep, Node* base, Node* offset);
261 
262   // Load a value from the root array.
263   Node* LoadRoot(Heap::RootListIndex root_index);
264 
265   // Store value to raw memory location.
266   Node* Store(Node* base, Node* value);
267   Node* Store(Node* base, Node* offset, Node* value);
268   Node* StoreWithMapWriteBarrier(Node* base, Node* offset, Node* value);
269   Node* StoreNoWriteBarrier(MachineRepresentation rep, Node* base, Node* value);
270   Node* StoreNoWriteBarrier(MachineRepresentation rep, Node* base, Node* offset,
271                             Node* value);
272   Node* AtomicStore(MachineRepresentation rep, Node* base, Node* offset,
273                     Node* value);
274 
275   // Store a value to the root array.
276   Node* StoreRoot(Heap::RootListIndex root_index, Node* value);
277 
278 // Basic arithmetic operations.
279 #define DECLARE_CODE_ASSEMBLER_BINARY_OP(name) Node* name(Node* a, Node* b);
280   CODE_ASSEMBLER_BINARY_OP_LIST(DECLARE_CODE_ASSEMBLER_BINARY_OP)
281 #undef DECLARE_CODE_ASSEMBLER_BINARY_OP
282 
283   Node* IntPtrAdd(Node* left, Node* right);
284   Node* IntPtrSub(Node* left, Node* right);
285 
286   Node* WordShl(Node* value, int shift);
287   Node* WordShr(Node* value, int shift);
288   Node* Word32Shr(Node* value, int shift);
289 
290 // Unary
291 #define DECLARE_CODE_ASSEMBLER_UNARY_OP(name) Node* name(Node* a);
292   CODE_ASSEMBLER_UNARY_OP_LIST(DECLARE_CODE_ASSEMBLER_UNARY_OP)
293 #undef DECLARE_CODE_ASSEMBLER_UNARY_OP
294 
295   // Changes an intptr_t to a double, e.g. for storing an element index
296   // outside Smi range in a HeapNumber. Lossless on 32-bit,
297   // rounds on 64-bit (which doesn't affect valid element indices).
298   Node* RoundIntPtrToFloat64(Node* value);
299   // No-op on 32-bit, otherwise zero extend.
300   Node* ChangeUint32ToWord(Node* value);
301   // No-op on 32-bit, otherwise sign extend.
302   Node* ChangeInt32ToIntPtr(Node* value);
303 
304   // No-op that guarantees that the value is kept alive till this point even
305   // if GC happens.
306   Node* Retain(Node* value);
307 
308   // Projections
309   Node* Projection(int index, Node* value);
310 
311   // Calls
312   template <class... TArgs>
313   Node* CallRuntime(Runtime::FunctionId function, Node* context, TArgs... args);
314 
315   template <class... TArgs>
316   Node* TailCallRuntime(Runtime::FunctionId function, Node* context,
317                         TArgs... args);
318 
319   template <class... TArgs>
CallStub(Callable const & callable,Node * context,TArgs...args)320   Node* CallStub(Callable const& callable, Node* context, TArgs... args) {
321     Node* target = HeapConstant(callable.code());
322     return CallStub(callable.descriptor(), target, context, args...);
323   }
324 
325   template <class... TArgs>
CallStub(const CallInterfaceDescriptor & descriptor,Node * target,Node * context,TArgs...args)326   Node* CallStub(const CallInterfaceDescriptor& descriptor, Node* target,
327                  Node* context, TArgs... args) {
328     return CallStubR(descriptor, 1, target, context, args...);
329   }
330 
331   template <class... TArgs>
332   Node* CallStubR(const CallInterfaceDescriptor& descriptor, size_t result_size,
333                   Node* target, Node* context, TArgs... args);
334 
335   Node* CallStubN(const CallInterfaceDescriptor& descriptor, size_t result_size,
336                   int input_count, Node* const* inputs);
337 
338   template <class... TArgs>
TailCallStub(Callable const & callable,Node * context,TArgs...args)339   Node* TailCallStub(Callable const& callable, Node* context, TArgs... args) {
340     Node* target = HeapConstant(callable.code());
341     return TailCallStub(callable.descriptor(), target, context, args...);
342   }
343 
344   template <class... TArgs>
345   Node* TailCallStub(const CallInterfaceDescriptor& descriptor, Node* target,
346                      Node* context, TArgs... args);
347 
348   template <class... TArgs>
349   Node* TailCallBytecodeDispatch(const CallInterfaceDescriptor& descriptor,
350                                  Node* target, TArgs... args);
351 
352   template <class... TArgs>
CallJS(Callable const & callable,Node * context,Node * function,Node * receiver,TArgs...args)353   Node* CallJS(Callable const& callable, Node* context, Node* function,
354                Node* receiver, TArgs... args) {
355     int argc = static_cast<int>(sizeof...(args));
356     Node* arity = Int32Constant(argc);
357     return CallStub(callable, context, function, arity, receiver, args...);
358   }
359 
360   template <class... TArgs>
ConstructJS(Callable const & callable,Node * context,Node * new_target,TArgs...args)361   Node* ConstructJS(Callable const& callable, Node* context, Node* new_target,
362                     TArgs... args) {
363     int argc = static_cast<int>(sizeof...(args));
364     Node* arity = Int32Constant(argc);
365     Node* receiver = LoadRoot(Heap::kUndefinedValueRootIndex);
366 
367     // Construct(target, new_target, arity, receiver, arguments...)
368     return CallStub(callable, context, new_target, new_target, arity, receiver,
369                     args...);
370   }
371 
372   Node* CallCFunctionN(Signature<MachineType>* signature, int input_count,
373                        Node* const* inputs);
374 
375   // Call to a C function with two arguments.
376   Node* CallCFunction2(MachineType return_type, MachineType arg0_type,
377                        MachineType arg1_type, Node* function, Node* arg0,
378                        Node* arg1);
379 
380   // Call to a C function with three arguments.
381   Node* CallCFunction3(MachineType return_type, MachineType arg0_type,
382                        MachineType arg1_type, MachineType arg2_type,
383                        Node* function, Node* arg0, Node* arg1, Node* arg2);
384 
385   // Exception handling support.
386   void GotoIfException(Node* node, Label* if_exception,
387                        Variable* exception_var = nullptr);
388 
389   // Helpers which delegate to RawMachineAssembler.
390   Factory* factory() const;
391   Isolate* isolate() const;
392   Zone* zone() const;
393 
state()394   CodeAssemblerState* state() { return state_; }
395 
396   void BreakOnNode(int node_id);
397 
398  protected:
399   void RegisterCallGenerationCallbacks(
400       const CodeAssemblerCallback& call_prologue,
401       const CodeAssemblerCallback& call_epilogue);
402   void UnregisterCallGenerationCallbacks();
403 
404  private:
405   RawMachineAssembler* raw_assembler() const;
406 
407   // Calls respective callback registered in the state.
408   void CallPrologue();
409   void CallEpilogue();
410 
411   CodeAssemblerState* state_;
412 
413   DISALLOW_COPY_AND_ASSIGN(CodeAssembler);
414 };
415 
416 class CodeAssemblerVariable {
417  public:
418   explicit CodeAssemblerVariable(CodeAssembler* assembler,
419                                  MachineRepresentation rep);
420   CodeAssemblerVariable(CodeAssembler* assembler, MachineRepresentation rep,
421                         Node* initial_value);
422   ~CodeAssemblerVariable();
423   void Bind(Node* value);
424   Node* value() const;
425   MachineRepresentation rep() const;
426   bool IsBound() const;
427 
428  private:
429   friend class CodeAssemblerLabel;
430   friend class CodeAssemblerState;
431   class Impl;
432   Impl* impl_;
433   CodeAssemblerState* state_;
434 };
435 
436 class CodeAssemblerLabel {
437  public:
438   enum Type { kDeferred, kNonDeferred };
439 
440   explicit CodeAssemblerLabel(
441       CodeAssembler* assembler,
442       CodeAssemblerLabel::Type type = CodeAssemblerLabel::kNonDeferred)
443       : CodeAssemblerLabel(assembler, 0, nullptr, type) {}
444   CodeAssemblerLabel(
445       CodeAssembler* assembler,
446       const CodeAssemblerVariableList& merged_variables,
447       CodeAssemblerLabel::Type type = CodeAssemblerLabel::kNonDeferred)
448       : CodeAssemblerLabel(assembler, merged_variables.length(),
449                            &(merged_variables[0]), type) {}
450   CodeAssemblerLabel(
451       CodeAssembler* assembler, size_t count, CodeAssemblerVariable** vars,
452       CodeAssemblerLabel::Type type = CodeAssemblerLabel::kNonDeferred);
453   CodeAssemblerLabel(
454       CodeAssembler* assembler, CodeAssemblerVariable* merged_variable,
455       CodeAssemblerLabel::Type type = CodeAssemblerLabel::kNonDeferred)
456       : CodeAssemblerLabel(assembler, 1, &merged_variable, type) {}
457   ~CodeAssemblerLabel();
458 
459  private:
460   friend class CodeAssembler;
461 
462   void Bind();
463   void MergeVariables();
464 
465   bool bound_;
466   size_t merge_count_;
467   CodeAssemblerState* state_;
468   RawMachineLabel* label_;
469   // Map of variables that need to be merged to their phi nodes (or placeholders
470   // for those phis).
471   std::map<CodeAssemblerVariable::Impl*, Node*> variable_phis_;
472   // Map of variables to the list of value nodes that have been added from each
473   // merge path in their order of merging.
474   std::map<CodeAssemblerVariable::Impl*, std::vector<Node*>> variable_merges_;
475 };
476 
477 class V8_EXPORT_PRIVATE CodeAssemblerState {
478  public:
479   // Create with CallStub linkage.
480   // |result_size| specifies the number of results returned by the stub.
481   // TODO(rmcilroy): move result_size to the CallInterfaceDescriptor.
482   CodeAssemblerState(Isolate* isolate, Zone* zone,
483                      const CallInterfaceDescriptor& descriptor,
484                      Code::Flags flags, const char* name,
485                      size_t result_size = 1);
486 
487   // Create with JSCall linkage.
488   CodeAssemblerState(Isolate* isolate, Zone* zone, int parameter_count,
489                      Code::Flags flags, const char* name);
490 
491   ~CodeAssemblerState();
492 
name()493   const char* name() const { return name_; }
494   int parameter_count() const;
495 
496  private:
497   friend class CodeAssembler;
498   friend class CodeAssemblerLabel;
499   friend class CodeAssemblerVariable;
500 
501   CodeAssemblerState(Isolate* isolate, Zone* zone,
502                      CallDescriptor* call_descriptor, Code::Flags flags,
503                      const char* name);
504 
505   std::unique_ptr<RawMachineAssembler> raw_assembler_;
506   Code::Flags flags_;
507   const char* name_;
508   bool code_generated_;
509   ZoneSet<CodeAssemblerVariable::Impl*> variables_;
510   CodeAssemblerCallback call_prologue_;
511   CodeAssemblerCallback call_epilogue_;
512 
513   DISALLOW_COPY_AND_ASSIGN(CodeAssemblerState);
514 };
515 
516 }  // namespace compiler
517 }  // namespace internal
518 }  // namespace v8
519 
520 #endif  // V8_COMPILER_CODE_ASSEMBLER_H_
521