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