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/runtime/runtime.h" 13 #include "src/wasm/function-body-decoder.h" 14 #include "src/wasm/function-compiler.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 struct AssemblerOptions; 23 24 namespace compiler { 25 // Forward declarations for some compiler data structures. 26 class CallDescriptor; 27 class Graph; 28 class MachineGraph; 29 class Node; 30 class NodeOriginTable; 31 class Operator; 32 class SourcePositionTable; 33 class WasmDecorator; 34 enum class TrapId : uint32_t; 35 } // namespace compiler 36 37 namespace wasm { 38 struct DecodeStruct; 39 // Expose {Node} and {Graph} opaquely as {wasm::TFNode} and {wasm::TFGraph}. 40 typedef compiler::Node TFNode; 41 typedef compiler::MachineGraph TFGraph; 42 class WasmCode; 43 struct WasmFeatures; 44 } // namespace wasm 45 46 namespace compiler { 47 48 class TurbofanWasmCompilationUnit { 49 public: 50 explicit TurbofanWasmCompilationUnit(wasm::WasmCompilationUnit* wasm_unit); 51 ~TurbofanWasmCompilationUnit(); 52 53 SourcePositionTable* BuildGraphForWasmFunction(wasm::WasmFeatures* detected, 54 double* decode_ms, 55 MachineGraph* mcgraph, 56 NodeOriginTable* node_origins); 57 58 void ExecuteCompilation(wasm::WasmFeatures* detected); 59 60 wasm::WasmCode* FinishCompilation(wasm::ErrorThrower*); 61 62 private: 63 wasm::WasmCompilationUnit* const wasm_unit_; 64 bool ok_ = true; 65 wasm::WasmCode* wasm_code_ = nullptr; 66 wasm::Result<wasm::DecodeStruct*> graph_construction_result_; 67 68 DISALLOW_COPY_AND_ASSIGN(TurbofanWasmCompilationUnit); 69 }; 70 71 // Wraps a JS function, producing a code object that can be called from wasm. 72 MaybeHandle<Code> CompileWasmToJSWrapper(Isolate*, Handle<JSReceiver> target, 73 wasm::FunctionSig*, uint32_t index, 74 wasm::ModuleOrigin, 75 wasm::UseTrapHandler); 76 77 // Creates a code object calling a wasm function with the given signature, 78 // callable from JS. 79 // TODO(clemensh): Remove the {UseTrapHandler} parameter to make js-to-wasm 80 // wrappers sharable across instances. 81 V8_EXPORT_PRIVATE MaybeHandle<Code> CompileJSToWasmWrapper( 82 Isolate*, const wasm::NativeModule*, wasm::FunctionSig*, bool is_import, 83 wasm::UseTrapHandler); 84 85 // Compiles a stub that redirects a call to a wasm function to the wasm 86 // interpreter. It's ABI compatible with the compiled wasm function. 87 MaybeHandle<Code> CompileWasmInterpreterEntry(Isolate*, uint32_t func_index, 88 wasm::FunctionSig*); 89 90 // Helper function to get the offset into a fixed array for a given {index}. 91 // TODO(titzer): access-builder.h is not accessible outside compiler. Move? 92 int FixedArrayOffsetMinusTag(uint32_t index); 93 94 enum CWasmEntryParameters { 95 kCodeObject, 96 kWasmInstance, 97 kArgumentsBuffer, 98 // marker: 99 kNumParameters 100 }; 101 102 // Compiles a stub with JS linkage, taking parameters as described by 103 // {CWasmEntryParameters}. It loads the wasm parameters from the argument 104 // buffer and calls the wasm function given as first parameter. 105 MaybeHandle<Code> CompileCWasmEntry(Isolate* isolate, wasm::FunctionSig* sig); 106 107 // Values from the instance object are cached between WASM-level function calls. 108 // This struct allows the SSA environment handling this cache to be defined 109 // and manipulated in wasm-compiler.{h,cc} instead of inside the WASM decoder. 110 // (Note that currently, the globals base is immutable, so not cached here.) 111 struct WasmInstanceCacheNodes { 112 Node* mem_start; 113 Node* mem_size; 114 Node* mem_mask; 115 }; 116 117 // Abstracts details of building TurboFan graph nodes for wasm to separate 118 // the wasm decoder from the internal details of TurboFan. 119 class WasmGraphBuilder { 120 public: 121 enum EnforceBoundsCheck : bool { 122 kNeedsBoundsCheck = true, 123 kCanOmitBoundsCheck = false 124 }; 125 enum UseRetpoline : bool { kRetpoline = true, kNoRetpoline = false }; 126 127 WasmGraphBuilder(wasm::ModuleEnv* env, Zone* zone, MachineGraph* mcgraph, 128 wasm::FunctionSig* sig, 129 compiler::SourcePositionTable* spt = nullptr); 130 131 Node** Buffer(size_t count) { 132 if (count > cur_bufsize_) { 133 size_t new_size = count + cur_bufsize_ + 5; 134 cur_buffer_ = 135 reinterpret_cast<Node**>(zone_->New(new_size * sizeof(Node*))); 136 cur_bufsize_ = new_size; 137 } 138 return cur_buffer_; 139 } 140 141 //----------------------------------------------------------------------- 142 // Operations independent of {control} or {effect}. 143 //----------------------------------------------------------------------- 144 Node* Error(); 145 Node* Start(unsigned params); 146 Node* Param(unsigned index); 147 Node* Loop(Node* entry); 148 Node* Terminate(Node* effect, Node* control); 149 Node* Merge(unsigned count, Node** controls); 150 Node* Phi(wasm::ValueType type, unsigned count, Node** vals, Node* control); 151 Node* CreateOrMergeIntoPhi(MachineRepresentation rep, Node* merge, 152 Node* tnode, Node* fnode); 153 Node* CreateOrMergeIntoEffectPhi(Node* merge, Node* tnode, Node* fnode); 154 Node* EffectPhi(unsigned count, Node** effects, Node* control); 155 Node* RefNull(); 156 Node* Uint32Constant(uint32_t value); 157 Node* Int32Constant(int32_t value); 158 Node* Int64Constant(int64_t value); 159 Node* IntPtrConstant(intptr_t value); 160 Node* Float32Constant(float value); 161 Node* Float64Constant(double value); 162 Node* Binop(wasm::WasmOpcode opcode, Node* left, Node* right, 163 wasm::WasmCodePosition position = wasm::kNoCodePosition); 164 Node* Unop(wasm::WasmOpcode opcode, Node* input, 165 wasm::WasmCodePosition position = wasm::kNoCodePosition); 166 Node* GrowMemory(Node* input); 167 Node* Throw(uint32_t tag, const wasm::WasmException* exception, 168 const Vector<Node*> values); 169 Node* Rethrow(); 170 Node* ConvertExceptionTagToRuntimeId(uint32_t tag); 171 Node* GetExceptionRuntimeId(); 172 Node** GetExceptionValues(const wasm::WasmException* except_decl); 173 bool IsPhiWithMerge(Node* phi, Node* merge); 174 bool ThrowsException(Node* node, Node** if_success, Node** if_exception); 175 void AppendToMerge(Node* merge, Node* from); 176 void AppendToPhi(Node* phi, Node* from); 177 178 void StackCheck(wasm::WasmCodePosition position, Node** effect = nullptr, 179 Node** control = nullptr); 180 181 void PatchInStackCheckIfNeeded(); 182 183 //----------------------------------------------------------------------- 184 // Operations that read and/or write {control} and {effect}. 185 //----------------------------------------------------------------------- 186 Node* BranchNoHint(Node* cond, Node** true_node, Node** false_node); 187 Node* BranchExpectTrue(Node* cond, Node** true_node, Node** false_node); 188 Node* BranchExpectFalse(Node* cond, Node** true_node, Node** false_node); 189 190 Node* TrapIfTrue(wasm::TrapReason reason, Node* cond, 191 wasm::WasmCodePosition position); 192 Node* TrapIfFalse(wasm::TrapReason reason, Node* cond, 193 wasm::WasmCodePosition position); 194 Node* TrapIfEq32(wasm::TrapReason reason, Node* node, int32_t val, 195 wasm::WasmCodePosition position); 196 Node* ZeroCheck32(wasm::TrapReason reason, Node* node, 197 wasm::WasmCodePosition position); 198 Node* TrapIfEq64(wasm::TrapReason reason, Node* node, int64_t val, 199 wasm::WasmCodePosition position); 200 Node* ZeroCheck64(wasm::TrapReason reason, Node* node, 201 wasm::WasmCodePosition position); 202 203 Node* Switch(unsigned count, Node* key); 204 Node* IfValue(int32_t value, Node* sw); 205 Node* IfDefault(Node* sw); 206 Node* Return(unsigned count, Node** nodes); 207 template <typename... Nodes> 208 Node* Return(Node* fst, Nodes*... more) { 209 Node* arr[] = {fst, more...}; 210 return Return(arraysize(arr), arr); 211 } 212 Node* ReturnVoid(); 213 Node* Unreachable(wasm::WasmCodePosition position); 214 215 Node* CallDirect(uint32_t index, Node** args, Node*** rets, 216 wasm::WasmCodePosition position); 217 Node* CallIndirect(uint32_t index, Node** args, Node*** rets, 218 wasm::WasmCodePosition position); 219 220 Node* Invert(Node* node); 221 222 //----------------------------------------------------------------------- 223 // Operations that concern the linear memory. 224 //----------------------------------------------------------------------- 225 Node* CurrentMemoryPages(); 226 Node* GetGlobal(uint32_t index); 227 Node* SetGlobal(uint32_t index, Node* val); 228 Node* TraceMemoryOperation(bool is_store, MachineRepresentation, Node* index, 229 uint32_t offset, wasm::WasmCodePosition); 230 Node* LoadMem(wasm::ValueType type, MachineType memtype, Node* index, 231 uint32_t offset, uint32_t alignment, 232 wasm::WasmCodePosition position); 233 Node* StoreMem(MachineRepresentation mem_rep, Node* index, uint32_t offset, 234 uint32_t alignment, Node* val, wasm::WasmCodePosition position, 235 wasm::ValueType type); 236 static void PrintDebugName(Node* node); 237 238 void set_instance_node(Node* instance_node) { 239 this->instance_node_ = instance_node; 240 } 241 242 Node* Control() { 243 DCHECK_NOT_NULL(*control_); 244 return *control_; 245 } 246 Node* Effect() { 247 DCHECK_NOT_NULL(*effect_); 248 return *effect_; 249 } 250 Node* SetControl(Node* node) { 251 *control_ = node; 252 return node; 253 } 254 Node* SetEffect(Node* node) { 255 *effect_ = node; 256 return node; 257 } 258 259 void set_control_ptr(Node** control) { this->control_ = control; } 260 261 void set_effect_ptr(Node** effect) { this->effect_ = effect; } 262 263 void GetGlobalBaseAndOffset(MachineType mem_type, const wasm::WasmGlobal&, 264 Node** base_node, Node** offset_node); 265 266 // Utilities to manipulate sets of instance cache nodes. 267 void InitInstanceCache(WasmInstanceCacheNodes* instance_cache); 268 void PrepareInstanceCacheForLoop(WasmInstanceCacheNodes* instance_cache, 269 Node* control); 270 void NewInstanceCacheMerge(WasmInstanceCacheNodes* to, 271 WasmInstanceCacheNodes* from, Node* merge); 272 void MergeInstanceCacheInto(WasmInstanceCacheNodes* to, 273 WasmInstanceCacheNodes* from, Node* merge); 274 275 void set_instance_cache(WasmInstanceCacheNodes* instance_cache) { 276 this->instance_cache_ = instance_cache; 277 } 278 279 wasm::FunctionSig* GetFunctionSignature() { return sig_; } 280 281 void LowerInt64(); 282 283 void SimdScalarLoweringForTesting(); 284 285 void SetSourcePosition(Node* node, wasm::WasmCodePosition position); 286 287 Node* S128Zero(); 288 Node* S1x4Zero(); 289 Node* S1x8Zero(); 290 Node* S1x16Zero(); 291 292 Node* SimdOp(wasm::WasmOpcode opcode, Node* const* inputs); 293 294 Node* SimdLaneOp(wasm::WasmOpcode opcode, uint8_t lane, Node* const* inputs); 295 296 Node* SimdShiftOp(wasm::WasmOpcode opcode, uint8_t shift, 297 Node* const* inputs); 298 299 Node* Simd8x16ShuffleOp(const uint8_t shuffle[16], Node* const* inputs); 300 301 Node* AtomicOp(wasm::WasmOpcode opcode, Node* const* inputs, 302 uint32_t alignment, uint32_t offset, 303 wasm::WasmCodePosition position); 304 305 bool has_simd() const { return has_simd_; } 306 307 const wasm::WasmModule* module() { return env_ ? env_->module : nullptr; } 308 309 bool use_trap_handler() const { return env_ && env_->use_trap_handler; } 310 311 MachineGraph* mcgraph() { return mcgraph_; } 312 Graph* graph(); 313 314 void AddBytecodePositionDecorator(NodeOriginTable* node_origins, 315 wasm::Decoder* decoder); 316 317 void RemoveBytecodePositionDecorator(); 318 319 protected: 320 static const int kDefaultBufferSize = 16; 321 322 Zone* const zone_; 323 MachineGraph* const mcgraph_; 324 wasm::ModuleEnv* const env_; 325 326 Node** control_ = nullptr; 327 Node** effect_ = nullptr; 328 WasmInstanceCacheNodes* instance_cache_ = nullptr; 329 330 SetOncePointer<Node> instance_node_; 331 SetOncePointer<Node> globals_start_; 332 SetOncePointer<Node> imported_mutable_globals_; 333 SetOncePointer<Node> stack_check_code_node_; 334 SetOncePointer<const Operator> stack_check_call_operator_; 335 336 Node** cur_buffer_; 337 size_t cur_bufsize_; 338 Node* def_buffer_[kDefaultBufferSize]; 339 bool has_simd_ = false; 340 bool needs_stack_check_ = false; 341 const bool untrusted_code_mitigations_ = true; 342 343 wasm::FunctionSig* const sig_; 344 345 compiler::WasmDecorator* decorator_ = nullptr; 346 347 compiler::SourcePositionTable* const source_position_table_ = nullptr; 348 349 Node* NoContextConstant(); 350 351 Node* MemBuffer(uint32_t offset); 352 // BoundsCheckMem receives a uint32 {index} node and returns a ptrsize index. 353 Node* BoundsCheckMem(uint8_t access_size, Node* index, uint32_t offset, 354 wasm::WasmCodePosition, EnforceBoundsCheck); 355 Node* CheckBoundsAndAlignment(uint8_t access_size, Node* index, 356 uint32_t offset, wasm::WasmCodePosition); 357 Node* Uint32ToUintptr(Node*); 358 const Operator* GetSafeLoadOperator(int offset, wasm::ValueType type); 359 const Operator* GetSafeStoreOperator(int offset, wasm::ValueType type); 360 Node* BuildChangeEndiannessStore(Node* node, MachineRepresentation rep, 361 wasm::ValueType wasmtype = wasm::kWasmStmt); 362 Node* BuildChangeEndiannessLoad(Node* node, MachineType type, 363 wasm::ValueType wasmtype = wasm::kWasmStmt); 364 365 Node* MaskShiftCount32(Node* node); 366 Node* MaskShiftCount64(Node* node); 367 368 template <typename... Args> 369 Node* BuildCCall(MachineSignature* sig, Node* function, Args... args); 370 Node* BuildWasmCall(wasm::FunctionSig* sig, Node** args, Node*** rets, 371 wasm::WasmCodePosition position, Node* instance_node, 372 UseRetpoline use_retpoline); 373 Node* BuildImportWasmCall(wasm::FunctionSig* sig, Node** args, Node*** rets, 374 wasm::WasmCodePosition position, int func_index); 375 Node* BuildImportWasmCall(wasm::FunctionSig* sig, Node** args, Node*** rets, 376 wasm::WasmCodePosition position, Node* func_index); 377 378 Node* BuildF32CopySign(Node* left, Node* right); 379 Node* BuildF64CopySign(Node* left, Node* right); 380 381 Node* BuildIntConvertFloat(Node* input, wasm::WasmCodePosition position, 382 wasm::WasmOpcode); 383 Node* BuildI32Ctz(Node* input); 384 Node* BuildI32Popcnt(Node* input); 385 Node* BuildI64Ctz(Node* input); 386 Node* BuildI64Popcnt(Node* input); 387 Node* BuildBitCountingCall(Node* input, ExternalReference ref, 388 MachineRepresentation input_type); 389 390 Node* BuildCFuncInstruction(ExternalReference ref, MachineType type, 391 Node* input0, Node* input1 = nullptr); 392 Node* BuildF32Trunc(Node* input); 393 Node* BuildF32Floor(Node* input); 394 Node* BuildF32Ceil(Node* input); 395 Node* BuildF32NearestInt(Node* input); 396 Node* BuildF64Trunc(Node* input); 397 Node* BuildF64Floor(Node* input); 398 Node* BuildF64Ceil(Node* input); 399 Node* BuildF64NearestInt(Node* input); 400 Node* BuildI32Rol(Node* left, Node* right); 401 Node* BuildI64Rol(Node* left, Node* right); 402 403 Node* BuildF64Acos(Node* input); 404 Node* BuildF64Asin(Node* input); 405 Node* BuildF64Pow(Node* left, Node* right); 406 Node* BuildF64Mod(Node* left, Node* right); 407 408 Node* BuildIntToFloatConversionInstruction( 409 Node* input, ExternalReference ref, 410 MachineRepresentation parameter_representation, 411 const MachineType result_type); 412 Node* BuildF32SConvertI64(Node* input); 413 Node* BuildF32UConvertI64(Node* input); 414 Node* BuildF64SConvertI64(Node* input); 415 Node* BuildF64UConvertI64(Node* input); 416 417 Node* BuildCcallConvertFloat(Node* input, wasm::WasmCodePosition position, 418 wasm::WasmOpcode opcode); 419 420 Node* BuildI32DivS(Node* left, Node* right, wasm::WasmCodePosition position); 421 Node* BuildI32RemS(Node* left, Node* right, wasm::WasmCodePosition position); 422 Node* BuildI32DivU(Node* left, Node* right, wasm::WasmCodePosition position); 423 Node* BuildI32RemU(Node* left, Node* right, wasm::WasmCodePosition position); 424 425 Node* BuildI64DivS(Node* left, Node* right, wasm::WasmCodePosition position); 426 Node* BuildI64RemS(Node* left, Node* right, wasm::WasmCodePosition position); 427 Node* BuildI64DivU(Node* left, Node* right, wasm::WasmCodePosition position); 428 Node* BuildI64RemU(Node* left, Node* right, wasm::WasmCodePosition position); 429 Node* BuildDiv64Call(Node* left, Node* right, ExternalReference ref, 430 MachineType result_type, wasm::TrapReason trap_zero, 431 wasm::WasmCodePosition position); 432 433 Node* BuildChangeInt32ToIntPtr(Node* value); 434 Node* BuildChangeInt32ToSmi(Node* value); 435 Node* BuildChangeUint31ToSmi(Node* value); 436 Node* BuildSmiShiftBitsConstant(); 437 Node* BuildChangeSmiToInt32(Node* value); 438 439 Node* BuildLoadInstanceFromExportedFunction(Node* closure); 440 441 // Asm.js specific functionality. 442 Node* BuildI32AsmjsSConvertF32(Node* input); 443 Node* BuildI32AsmjsSConvertF64(Node* input); 444 Node* BuildI32AsmjsUConvertF32(Node* input); 445 Node* BuildI32AsmjsUConvertF64(Node* input); 446 Node* BuildI32AsmjsDivS(Node* left, Node* right); 447 Node* BuildI32AsmjsRemS(Node* left, Node* right); 448 Node* BuildI32AsmjsDivU(Node* left, Node* right); 449 Node* BuildI32AsmjsRemU(Node* left, Node* right); 450 Node* BuildAsmjsLoadMem(MachineType type, Node* index); 451 Node* BuildAsmjsStoreMem(MachineType type, Node* index, Node* val); 452 453 uint32_t GetExceptionEncodedSize(const wasm::WasmException* exception) const; 454 void BuildEncodeException32BitValue(uint32_t* index, Node* value); 455 Node* BuildDecodeException32BitValue(Node* const* values, uint32_t* index); 456 457 Node** Realloc(Node* const* buffer, size_t old_count, size_t new_count) { 458 Node** buf = Buffer(new_count); 459 if (buf != buffer) memcpy(buf, buffer, old_count * sizeof(Node*)); 460 return buf; 461 } 462 463 void SetNeedsStackCheck() { needs_stack_check_ = true; } 464 465 //----------------------------------------------------------------------- 466 // Operations involving the CEntry, a dependency we want to remove 467 // to get off the GC heap. 468 //----------------------------------------------------------------------- 469 Node* BuildCallToRuntime(Runtime::FunctionId f, Node** parameters, 470 int parameter_count); 471 472 Node* BuildCallToRuntimeWithContext(Runtime::FunctionId f, Node* js_context, 473 Node** parameters, int parameter_count); 474 Node* BuildCallToRuntimeWithContextFromJS(Runtime::FunctionId f, 475 Node* js_context, 476 Node* const* parameters, 477 int parameter_count); 478 TrapId GetTrapIdForTrap(wasm::TrapReason reason); 479 }; 480 481 V8_EXPORT_PRIVATE CallDescriptor* GetWasmCallDescriptor( 482 Zone* zone, wasm::FunctionSig* signature, 483 WasmGraphBuilder::UseRetpoline use_retpoline = 484 WasmGraphBuilder::kNoRetpoline); 485 486 V8_EXPORT_PRIVATE CallDescriptor* GetI32WasmCallDescriptor( 487 Zone* zone, CallDescriptor* call_descriptor); 488 489 V8_EXPORT_PRIVATE CallDescriptor* GetI32WasmCallDescriptorForSimd( 490 Zone* zone, CallDescriptor* call_descriptor); 491 492 AssemblerOptions WasmAssemblerOptions(); 493 494 } // namespace compiler 495 } // namespace internal 496 } // namespace v8 497 498 #endif // V8_COMPILER_WASM_COMPILER_H_ 499