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