Home | History | Annotate | Download | only in compiler
      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_WASM_COMPILER_H_
      6 #define V8_COMPILER_WASM_COMPILER_H_
      7 
      8 #include <memory>
      9 
     10 // Clients of this interface shouldn't depend on lots of compiler internals.
     11 // Do not include anything from src/compiler here!
     12 #include "src/compilation-info.h"
     13 #include "src/compiler.h"
     14 #include "src/trap-handler/trap-handler.h"
     15 #include "src/wasm/wasm-module.h"
     16 #include "src/wasm/wasm-opcodes.h"
     17 #include "src/wasm/wasm-result.h"
     18 #include "src/zone/zone.h"
     19 
     20 namespace v8 {
     21 namespace internal {
     22 
     23 namespace compiler {
     24 // Forward declarations for some compiler data structures.
     25 class Node;
     26 class JSGraph;
     27 class Graph;
     28 class Operator;
     29 class SourcePositionTable;
     30 }  // namespace compiler
     31 
     32 namespace wasm {
     33 // Forward declarations for some WASM data structures.
     34 struct ModuleBytesEnv;
     35 struct ModuleEnv;
     36 struct WasmFunction;
     37 struct WasmModule;
     38 class ErrorThrower;
     39 struct DecodeStruct;
     40 
     41 // Expose {Node} and {Graph} opaquely as {wasm::TFNode} and {wasm::TFGraph}.
     42 typedef compiler::Node TFNode;
     43 typedef compiler::JSGraph TFGraph;
     44 }  // namespace wasm
     45 
     46 namespace compiler {
     47 class WasmCompilationUnit final {
     48  public:
     49   WasmCompilationUnit(wasm::ErrorThrower* thrower, Isolate* isolate,
     50                       wasm::ModuleBytesEnv* module_env,
     51                       const wasm::WasmFunction* function, uint32_t index);
     52 
     53   Zone* graph_zone() { return graph_zone_.get(); }
     54   int index() const { return index_; }
     55 
     56   void ExecuteCompilation();
     57   Handle<Code> FinishCompilation();
     58 
     59   static Handle<Code> CompileWasmFunction(wasm::ErrorThrower* thrower,
     60                                           Isolate* isolate,
     61                                           wasm::ModuleBytesEnv* module_env,
     62                                           const wasm::WasmFunction* function) {
     63     WasmCompilationUnit unit(thrower, isolate, module_env, function,
     64                              function->func_index);
     65     unit.ExecuteCompilation();
     66     return unit.FinishCompilation();
     67   }
     68 
     69  private:
     70   SourcePositionTable* BuildGraphForWasmFunction(double* decode_ms);
     71   char* GetTaggedFunctionName(const wasm::WasmFunction* function);
     72 
     73   wasm::ErrorThrower* thrower_;
     74   Isolate* isolate_;
     75   wasm::ModuleBytesEnv* module_env_;
     76   const wasm::WasmFunction* function_;
     77   // Function name is tagged with uint32 func_index - wasm#<func_index>
     78   char function_name_[16];
     79   // The graph zone is deallocated at the end of ExecuteCompilation.
     80   std::unique_ptr<Zone> graph_zone_;
     81   JSGraph* jsgraph_;
     82   Zone compilation_zone_;
     83   CompilationInfo info_;
     84   std::unique_ptr<CompilationJob> job_;
     85   uint32_t index_;
     86   wasm::Result<wasm::DecodeStruct*> graph_construction_result_;
     87   bool ok_;
     88   ZoneVector<trap_handler::ProtectedInstructionData>
     89       protected_instructions_;  // Instructions that are protected by the signal
     90                                 // handler.
     91 
     92   DISALLOW_COPY_AND_ASSIGN(WasmCompilationUnit);
     93 };
     94 
     95 // Wraps a JS function, producing a code object that can be called from WASM.
     96 Handle<Code> CompileWasmToJSWrapper(Isolate* isolate, Handle<JSReceiver> target,
     97                                     wasm::FunctionSig* sig, uint32_t index,
     98                                     Handle<String> module_name,
     99                                     MaybeHandle<String> import_name,
    100                                     wasm::ModuleOrigin origin);
    101 
    102 // Wraps a given wasm code object, producing a code object.
    103 Handle<Code> CompileJSToWasmWrapper(Isolate* isolate,
    104                                     const wasm::WasmModule* module,
    105                                     Handle<Code> wasm_code, uint32_t index);
    106 
    107 // Compiles a stub that redirects a call to a wasm function to the wasm
    108 // interpreter. It's ABI compatible with the compiled wasm function.
    109 Handle<Code> CompileWasmInterpreterEntry(Isolate* isolate, uint32_t func_index,
    110                                          wasm::FunctionSig* sig,
    111                                          Handle<WasmInstanceObject> instance);
    112 
    113 // Abstracts details of building TurboFan graph nodes for WASM to separate
    114 // the WASM decoder from the internal details of TurboFan.
    115 class WasmTrapHelper;
    116 typedef ZoneVector<Node*> NodeVector;
    117 class WasmGraphBuilder {
    118  public:
    119   WasmGraphBuilder(
    120       wasm::ModuleEnv* module_env, Zone* z, JSGraph* g, wasm::FunctionSig* sig,
    121       compiler::SourcePositionTable* source_position_table = nullptr);
    122 
    123   Node** Buffer(size_t count) {
    124     if (count > cur_bufsize_) {
    125       size_t new_size = count + cur_bufsize_ + 5;
    126       cur_buffer_ =
    127           reinterpret_cast<Node**>(zone_->New(new_size * sizeof(Node*)));
    128       cur_bufsize_ = new_size;
    129     }
    130     return cur_buffer_;
    131   }
    132 
    133   //-----------------------------------------------------------------------
    134   // Operations independent of {control} or {effect}.
    135   //-----------------------------------------------------------------------
    136   Node* Error();
    137   Node* Start(unsigned params);
    138   Node* Param(unsigned index);
    139   Node* Loop(Node* entry);
    140   Node* Terminate(Node* effect, Node* control);
    141   Node* Merge(unsigned count, Node** controls);
    142   Node* Phi(wasm::ValueType type, unsigned count, Node** vals, Node* control);
    143   Node* EffectPhi(unsigned count, Node** effects, Node* control);
    144   Node* NumberConstant(int32_t value);
    145   Node* Uint32Constant(uint32_t value);
    146   Node* Int32Constant(int32_t value);
    147   Node* Int64Constant(int64_t value);
    148   Node* Float32Constant(float value);
    149   Node* Float64Constant(double value);
    150   Node* HeapConstant(Handle<HeapObject> value);
    151   Node* Binop(wasm::WasmOpcode opcode, Node* left, Node* right,
    152               wasm::WasmCodePosition position = wasm::kNoCodePosition);
    153   Node* Unop(wasm::WasmOpcode opcode, Node* input,
    154              wasm::WasmCodePosition position = wasm::kNoCodePosition);
    155   Node* GrowMemory(Node* input);
    156   Node* Throw(Node* input);
    157   Node* Catch(Node* input, wasm::WasmCodePosition position);
    158   unsigned InputCount(Node* node);
    159   bool IsPhiWithMerge(Node* phi, Node* merge);
    160   bool ThrowsException(Node* node, Node** if_success, Node** if_exception);
    161   void AppendToMerge(Node* merge, Node* from);
    162   void AppendToPhi(Node* phi, Node* from);
    163 
    164   void StackCheck(wasm::WasmCodePosition position, Node** effect = nullptr,
    165                   Node** control = nullptr);
    166 
    167   //-----------------------------------------------------------------------
    168   // Operations that read and/or write {control} and {effect}.
    169   //-----------------------------------------------------------------------
    170   Node* BranchNoHint(Node* cond, Node** true_node, Node** false_node);
    171   Node* BranchExpectTrue(Node* cond, Node** true_node, Node** false_node);
    172   Node* BranchExpectFalse(Node* cond, Node** true_node, Node** false_node);
    173 
    174   Node* Switch(unsigned count, Node* key);
    175   Node* IfValue(int32_t value, Node* sw);
    176   Node* IfDefault(Node* sw);
    177   Node* Return(unsigned count, Node** nodes);
    178   template <typename... Nodes>
    179   Node* Return(Node* fst, Nodes*... more) {
    180     Node* arr[] = {fst, more...};
    181     return Return(arraysize(arr), arr);
    182   }
    183   Node* ReturnVoid();
    184   Node* Unreachable(wasm::WasmCodePosition position);
    185 
    186   Node* CallDirect(uint32_t index, Node** args, Node*** rets,
    187                    wasm::WasmCodePosition position);
    188   Node* CallIndirect(uint32_t index, Node** args, Node*** rets,
    189                      wasm::WasmCodePosition position);
    190 
    191   void BuildJSToWasmWrapper(Handle<Code> wasm_code, wasm::FunctionSig* sig);
    192   void BuildWasmToJSWrapper(Handle<JSReceiver> target, wasm::FunctionSig* sig);
    193   void BuildWasmInterpreterEntry(uint32_t func_index, wasm::FunctionSig* sig,
    194                                  Handle<WasmInstanceObject> instance);
    195 
    196   Node* ToJS(Node* node, wasm::ValueType type);
    197   Node* FromJS(Node* node, Node* context, wasm::ValueType type);
    198   Node* Invert(Node* node);
    199   void EnsureFunctionTableNodes();
    200 
    201   //-----------------------------------------------------------------------
    202   // Operations that concern the linear memory.
    203   //-----------------------------------------------------------------------
    204   Node* CurrentMemoryPages();
    205   Node* GetGlobal(uint32_t index);
    206   Node* SetGlobal(uint32_t index, Node* val);
    207   Node* LoadMem(wasm::ValueType type, MachineType memtype, Node* index,
    208                 uint32_t offset, uint32_t alignment,
    209                 wasm::WasmCodePosition position);
    210   Node* StoreMem(MachineType type, Node* index, uint32_t offset,
    211                  uint32_t alignment, Node* val,
    212                  wasm::WasmCodePosition position);
    213 
    214   static void PrintDebugName(Node* node);
    215 
    216   Node* Control() { return *control_; }
    217   Node* Effect() { return *effect_; }
    218 
    219   void set_control_ptr(Node** control) { this->control_ = control; }
    220 
    221   void set_effect_ptr(Node** effect) { this->effect_ = effect; }
    222 
    223   wasm::FunctionSig* GetFunctionSignature() { return sig_; }
    224 
    225   void Int64LoweringForTesting();
    226 
    227   void SimdScalarLoweringForTesting();
    228 
    229   void SetSourcePosition(Node* node, wasm::WasmCodePosition position);
    230 
    231   Node* CreateS128Value(int32_t value);
    232 
    233   Node* SimdOp(wasm::WasmOpcode opcode, const NodeVector& inputs);
    234 
    235   Node* SimdLaneOp(wasm::WasmOpcode opcode, uint8_t lane,
    236                    const NodeVector& inputs);
    237 
    238   Node* SimdShiftOp(wasm::WasmOpcode opcode, uint8_t shift,
    239                     const NodeVector& inputs);
    240 
    241   Node* SimdSwizzleOp(wasm::WasmOpcode opcode, uint32_t swizzle,
    242                       const NodeVector& inputs);
    243 
    244   bool has_simd() const { return has_simd_; }
    245 
    246   wasm::ModuleEnv* module_env() const { return module_; }
    247 
    248  private:
    249   static const int kDefaultBufferSize = 16;
    250   friend class WasmTrapHelper;
    251 
    252   Zone* zone_;
    253   JSGraph* jsgraph_;
    254   wasm::ModuleEnv* module_ = nullptr;
    255   Node* mem_buffer_ = nullptr;
    256   Node* mem_size_ = nullptr;
    257   NodeVector signature_tables_;
    258   NodeVector function_tables_;
    259   NodeVector function_table_sizes_;
    260   Node** control_ = nullptr;
    261   Node** effect_ = nullptr;
    262   Node** cur_buffer_;
    263   size_t cur_bufsize_;
    264   Node* def_buffer_[kDefaultBufferSize];
    265   bool has_simd_ = false;
    266 
    267   WasmTrapHelper* trap_;
    268   wasm::FunctionSig* sig_;
    269   SetOncePointer<const Operator> allocate_heap_number_operator_;
    270 
    271   compiler::SourcePositionTable* source_position_table_ = nullptr;
    272 
    273   // Internal helper methods.
    274   JSGraph* jsgraph() { return jsgraph_; }
    275   Graph* graph();
    276 
    277   Node* String(const char* string);
    278   Node* MemSize(uint32_t offset);
    279   Node* MemBuffer(uint32_t offset);
    280   void BoundsCheckMem(MachineType memtype, Node* index, uint32_t offset,
    281                       wasm::WasmCodePosition position);
    282 
    283   Node* BuildChangeEndianness(Node* node, MachineType type,
    284                               wasm::ValueType wasmtype = wasm::kWasmStmt);
    285 
    286   Node* MaskShiftCount32(Node* node);
    287   Node* MaskShiftCount64(Node* node);
    288 
    289   Node* BuildCCall(MachineSignature* sig, Node** args);
    290   Node* BuildWasmCall(wasm::FunctionSig* sig, Node** args, Node*** rets,
    291                       wasm::WasmCodePosition position);
    292 
    293   Node* BuildF32CopySign(Node* left, Node* right);
    294   Node* BuildF64CopySign(Node* left, Node* right);
    295   Node* BuildI32SConvertF32(Node* input, wasm::WasmCodePosition position);
    296   Node* BuildI32SConvertF64(Node* input, wasm::WasmCodePosition position);
    297   Node* BuildI32UConvertF32(Node* input, wasm::WasmCodePosition position);
    298   Node* BuildI32UConvertF64(Node* input, wasm::WasmCodePosition position);
    299   Node* BuildI32Ctz(Node* input);
    300   Node* BuildI32Popcnt(Node* input);
    301   Node* BuildI64Ctz(Node* input);
    302   Node* BuildI64Popcnt(Node* input);
    303   Node* BuildBitCountingCall(Node* input, ExternalReference ref,
    304                              MachineRepresentation input_type);
    305 
    306   Node* BuildCFuncInstruction(ExternalReference ref, MachineType type,
    307                               Node* input0, Node* input1 = nullptr);
    308   Node* BuildF32Trunc(Node* input);
    309   Node* BuildF32Floor(Node* input);
    310   Node* BuildF32Ceil(Node* input);
    311   Node* BuildF32NearestInt(Node* input);
    312   Node* BuildF64Trunc(Node* input);
    313   Node* BuildF64Floor(Node* input);
    314   Node* BuildF64Ceil(Node* input);
    315   Node* BuildF64NearestInt(Node* input);
    316   Node* BuildI32Rol(Node* left, Node* right);
    317   Node* BuildI64Rol(Node* left, Node* right);
    318 
    319   Node* BuildF64Acos(Node* input);
    320   Node* BuildF64Asin(Node* input);
    321   Node* BuildF64Pow(Node* left, Node* right);
    322   Node* BuildF64Mod(Node* left, Node* right);
    323 
    324   Node* BuildIntToFloatConversionInstruction(
    325       Node* input, ExternalReference ref,
    326       MachineRepresentation parameter_representation,
    327       const MachineType result_type);
    328   Node* BuildF32SConvertI64(Node* input);
    329   Node* BuildF32UConvertI64(Node* input);
    330   Node* BuildF64SConvertI64(Node* input);
    331   Node* BuildF64UConvertI64(Node* input);
    332 
    333   Node* BuildFloatToIntConversionInstruction(
    334       Node* input, ExternalReference ref,
    335       MachineRepresentation parameter_representation,
    336       const MachineType result_type, wasm::WasmCodePosition position);
    337   Node* BuildI64SConvertF32(Node* input, wasm::WasmCodePosition position);
    338   Node* BuildI64UConvertF32(Node* input, wasm::WasmCodePosition position);
    339   Node* BuildI64SConvertF64(Node* input, wasm::WasmCodePosition position);
    340   Node* BuildI64UConvertF64(Node* input, wasm::WasmCodePosition position);
    341 
    342   Node* BuildI32DivS(Node* left, Node* right, wasm::WasmCodePosition position);
    343   Node* BuildI32RemS(Node* left, Node* right, wasm::WasmCodePosition position);
    344   Node* BuildI32DivU(Node* left, Node* right, wasm::WasmCodePosition position);
    345   Node* BuildI32RemU(Node* left, Node* right, wasm::WasmCodePosition position);
    346 
    347   Node* BuildI64DivS(Node* left, Node* right, wasm::WasmCodePosition position);
    348   Node* BuildI64RemS(Node* left, Node* right, wasm::WasmCodePosition position);
    349   Node* BuildI64DivU(Node* left, Node* right, wasm::WasmCodePosition position);
    350   Node* BuildI64RemU(Node* left, Node* right, wasm::WasmCodePosition position);
    351   Node* BuildDiv64Call(Node* left, Node* right, ExternalReference ref,
    352                        MachineType result_type, int trap_zero,
    353                        wasm::WasmCodePosition position);
    354 
    355   Node* BuildJavaScriptToNumber(Node* node, Node* context);
    356 
    357   Node* BuildChangeInt32ToTagged(Node* value);
    358   Node* BuildChangeFloat64ToTagged(Node* value);
    359   Node* BuildChangeTaggedToFloat64(Node* value);
    360 
    361   Node* BuildChangeInt32ToSmi(Node* value);
    362   Node* BuildChangeSmiToInt32(Node* value);
    363   Node* BuildChangeUint32ToSmi(Node* value);
    364   Node* BuildChangeSmiToFloat64(Node* value);
    365   Node* BuildTestNotSmi(Node* value);
    366   Node* BuildSmiShiftBitsConstant();
    367 
    368   Node* BuildAllocateHeapNumberWithValue(Node* value, Node* control);
    369   Node* BuildLoadHeapNumberValue(Node* value, Node* control);
    370   Node* BuildHeapNumberValueIndexConstant();
    371 
    372   // Asm.js specific functionality.
    373   Node* BuildI32AsmjsSConvertF32(Node* input);
    374   Node* BuildI32AsmjsSConvertF64(Node* input);
    375   Node* BuildI32AsmjsUConvertF32(Node* input);
    376   Node* BuildI32AsmjsUConvertF64(Node* input);
    377   Node* BuildI32AsmjsDivS(Node* left, Node* right);
    378   Node* BuildI32AsmjsRemS(Node* left, Node* right);
    379   Node* BuildI32AsmjsDivU(Node* left, Node* right);
    380   Node* BuildI32AsmjsRemU(Node* left, Node* right);
    381   Node* BuildAsmjsLoadMem(MachineType type, Node* index);
    382   Node* BuildAsmjsStoreMem(MachineType type, Node* index, Node* val);
    383 
    384   Node** Realloc(Node** buffer, size_t old_count, size_t new_count) {
    385     Node** buf = Buffer(new_count);
    386     if (buf != buffer) memcpy(buf, buffer, old_count * sizeof(Node*));
    387     return buf;
    388   }
    389 
    390   int AddParameterNodes(Node** args, int pos, int param_count,
    391                         wasm::FunctionSig* sig);
    392 };
    393 }  // namespace compiler
    394 }  // namespace internal
    395 }  // namespace v8
    396 
    397 #endif  // V8_COMPILER_WASM_COMPILER_H_
    398