diff options
Diffstat (limited to 'deps/v8/src/compiler/wasm-compiler.cc')
-rw-r--r-- | deps/v8/src/compiler/wasm-compiler.cc | 1142 |
1 files changed, 776 insertions, 366 deletions
diff --git a/deps/v8/src/compiler/wasm-compiler.cc b/deps/v8/src/compiler/wasm-compiler.cc index fe90492e73..bc731b2bb8 100644 --- a/deps/v8/src/compiler/wasm-compiler.cc +++ b/deps/v8/src/compiler/wasm-compiler.cc @@ -34,10 +34,14 @@ #include "src/wasm/function-body-decoder.h" #include "src/wasm/wasm-limits.h" #include "src/wasm/wasm-module.h" -#include "src/wasm/wasm-objects.h" +#include "src/wasm/wasm-objects-inl.h" #include "src/wasm/wasm-opcodes.h" #include "src/wasm/wasm-text.h" +namespace v8 { +namespace internal { +namespace compiler { + // TODO(titzer): pull WASM_64 up to a common header. #if !V8_TARGET_ARCH_32_BIT || V8_TARGET_ARCH_X64 #define WASM_64 1 @@ -49,12 +53,10 @@ V8_Fatal(__FILE__, __LINE__, "Unsupported opcode #%d:%s", (opcode), \ wasm::WasmOpcodes::OpcodeName(opcode)); -namespace v8 { -namespace internal { -namespace compiler { - namespace { +constexpr uint32_t kBytesPerExceptionValuesArrayElement = 2; + void MergeControlToEnd(JSGraph* jsgraph, Node* node) { Graph* g = jsgraph->graph(); if (g->end()) { @@ -69,7 +71,8 @@ void MergeControlToEnd(JSGraph* jsgraph, Node* node) { WasmGraphBuilder::WasmGraphBuilder( ModuleEnv* env, Zone* zone, JSGraph* jsgraph, Handle<Code> centry_stub, wasm::FunctionSig* sig, - compiler::SourcePositionTable* source_position_table) + compiler::SourcePositionTable* source_position_table, + RuntimeExceptionSupport exception_support) : zone_(zone), jsgraph_(jsgraph), centry_stub_node_(jsgraph_->HeapConstant(centry_stub)), @@ -79,6 +82,7 @@ WasmGraphBuilder::WasmGraphBuilder( function_table_sizes_(zone), cur_buffer_(def_buffer_), cur_bufsize_(kDefaultBufferSize), + runtime_exception_support_(exception_support), sig_(sig), source_position_table_(source_position_table) { for (size_t i = sig->parameter_count(); i > 0 && !has_simd_; --i) { @@ -190,11 +194,15 @@ Node* WasmGraphBuilder::Int64Constant(int64_t value) { return jsgraph()->Int64Constant(value); } +Node* WasmGraphBuilder::IntPtrConstant(intptr_t value) { + return jsgraph()->IntPtrConstant(value); +} + void WasmGraphBuilder::StackCheck(wasm::WasmCodePosition position, Node** effect, Node** control) { // TODO(mtrofin): "!env_" happens when we generate a wrapper. // We should factor wrappers separately from wasm codegen. - if (FLAG_wasm_no_stack_checks || !env_ || !has_runtime_exception_support_) { + if (FLAG_wasm_no_stack_checks || !env_ || !runtime_exception_support_) { return; } if (effect == nullptr) effect = effect_; @@ -830,7 +838,7 @@ Node* WasmGraphBuilder::BranchExpectFalse(Node* cond, Node** true_node, } Builtins::Name WasmGraphBuilder::GetBuiltinIdForTrap(wasm::TrapReason reason) { - if (!has_runtime_exception_support_) { + if (runtime_exception_support_ == kNoRuntimeExceptionSupport) { // We use Builtins::builtin_count as a marker to tell the code generator // to generate a call to a testing c-function instead of a runtime // function. This code should only be called from a cctest. @@ -1098,8 +1106,8 @@ Node* WasmGraphBuilder::BuildChangeEndiannessStore(Node* node, Node* lowerByte; Node* higherByte; - DCHECK(shiftCount > 0); - DCHECK((shiftCount + 8) % 16 == 0); + DCHECK_LT(0, shiftCount); + DCHECK_EQ(0, (shiftCount + 8) % 16); if (valueSizeInBits > 32) { shiftLower = graph()->NewNode(m->Word64Shl(), value, @@ -1235,8 +1243,8 @@ Node* WasmGraphBuilder::BuildChangeEndiannessLoad(Node* node, Node* lowerByte; Node* higherByte; - DCHECK(shiftCount > 0); - DCHECK((shiftCount + 8) % 16 == 0); + DCHECK_LT(0, shiftCount); + DCHECK_EQ(0, (shiftCount + 8) % 16); if (valueSizeInBits > 32) { shiftLower = graph()->NewNode(m->Word64Shl(), value, @@ -1459,9 +1467,8 @@ Node* WasmGraphBuilder::BuildBitCountingCall(Node* input, ExternalReference ref, sig_builder.AddParam(MachineType::Pointer()); Node* function = graph()->NewNode(jsgraph()->common()->ExternalConstant(ref)); - Node* args[] = {function, stack_slot_param}; - return BuildCCall(sig_builder.Build(), args); + return BuildCCall(sig_builder.Build(), function, stack_slot_param); } Node* WasmGraphBuilder::BuildI32Ctz(Node* input) { @@ -1595,12 +1602,14 @@ Node* WasmGraphBuilder::BuildCFuncInstruction(ExternalReference ref, *control_); Node* function = graph()->NewNode(jsgraph()->common()->ExternalConstant(ref)); - Node** args = Buffer(5); - args[0] = function; - args[1] = stack_slot_param0; - int input_count = 1; - if (input1 != nullptr) { + if (input1 == nullptr) { + const int input_count = 1; + Signature<MachineType>::Builder sig_builder(jsgraph()->zone(), 0, + input_count); + sig_builder.AddParam(MachineType::Pointer()); + BuildCCall(sig_builder.Build(), function, stack_slot_param0); + } else { Node* stack_slot_param1 = graph()->NewNode( jsgraph()->machine()->StackSlot(type.representation())); const Operator* store_op1 = jsgraph()->machine()->Store( @@ -1608,17 +1617,15 @@ Node* WasmGraphBuilder::BuildCFuncInstruction(ExternalReference ref, *effect_ = graph()->NewNode(store_op1, stack_slot_param1, jsgraph()->Int32Constant(0), input1, *effect_, *control_); - args[2] = stack_slot_param1; - ++input_count; - } - Signature<MachineType>::Builder sig_builder(jsgraph()->zone(), 0, - input_count); - sig_builder.AddParam(MachineType::Pointer()); - if (input1 != nullptr) { + const int input_count = 2; + Signature<MachineType>::Builder sig_builder(jsgraph()->zone(), 0, + input_count); sig_builder.AddParam(MachineType::Pointer()); + sig_builder.AddParam(MachineType::Pointer()); + BuildCCall(sig_builder.Build(), function, stack_slot_param0, + stack_slot_param1); } - BuildCCall(sig_builder.Build(), args); const Operator* load_op = jsgraph()->machine()->Load(type); @@ -1669,8 +1676,8 @@ Node* WasmGraphBuilder::BuildIntToFloatConversionInstruction( sig_builder.AddParam(MachineType::Pointer()); sig_builder.AddParam(MachineType::Pointer()); Node* function = graph()->NewNode(jsgraph()->common()->ExternalConstant(ref)); - Node* args[] = {function, stack_slot_param, stack_slot_result}; - BuildCCall(sig_builder.Build(), args); + BuildCCall(sig_builder.Build(), function, stack_slot_param, + stack_slot_result); const Operator* load_op = jsgraph()->machine()->Load(result_type); Node* load = graph()->NewNode(load_op, stack_slot_result, jsgraph()->Int32Constant(0), @@ -1769,9 +1776,10 @@ Node* WasmGraphBuilder::BuildFloatToIntConversionInstruction( sig_builder.AddParam(MachineType::Pointer()); sig_builder.AddParam(MachineType::Pointer()); Node* function = graph()->NewNode(jsgraph()->common()->ExternalConstant(ref)); - Node* args[] = {function, stack_slot_param, stack_slot_result}; ZeroCheck32(wasm::kTrapFloatUnrepresentable, - BuildCCall(sig_builder.Build(), args), position); + BuildCCall(sig_builder.Build(), function, stack_slot_param, + stack_slot_result), + position); const Operator* load_op = jsgraph()->machine()->Load(result_type); Node* load = graph()->NewNode(load_op, stack_slot_result, jsgraph()->Int32Constant(0), @@ -1806,28 +1814,161 @@ Node* WasmGraphBuilder::GrowMemory(Node* input) { return result; } -Node* WasmGraphBuilder::Throw(Node* input) { +uint32_t WasmGraphBuilder::GetExceptionEncodedSize( + const wasm::WasmException* exception) const { + const wasm::WasmExceptionSig* sig = exception->sig; + uint32_t encoded_size = 0; + for (size_t i = 0; i < sig->parameter_count(); ++i) { + size_t byte_size = size_t(1) << ElementSizeLog2Of(sig->GetParam(i)); + DCHECK_EQ(byte_size % kBytesPerExceptionValuesArrayElement, 0); + DCHECK_LE(1, byte_size / kBytesPerExceptionValuesArrayElement); + encoded_size += byte_size / kBytesPerExceptionValuesArrayElement; + } + return encoded_size; +} + +Node* WasmGraphBuilder::Throw(uint32_t tag, + const wasm::WasmException* exception, + const Vector<Node*> values) { SetNeedsStackCheck(); - Node* parameters[] = {BuildChangeInt32ToSmi(input)}; - return BuildCallToRuntime(Runtime::kWasmThrow, parameters, - arraysize(parameters)); + uint32_t encoded_size = GetExceptionEncodedSize(exception); + Node* create_parameters[] = { + BuildChangeUint32ToSmi(ConvertExceptionTagToRuntimeId(tag)), + BuildChangeUint32ToSmi(Uint32Constant(encoded_size))}; + BuildCallToRuntime(Runtime::kWasmThrowCreate, create_parameters, + arraysize(create_parameters)); + uint32_t index = 0; + const wasm::WasmExceptionSig* sig = exception->sig; + MachineOperatorBuilder* m = jsgraph()->machine(); + for (size_t i = 0; i < sig->parameter_count(); ++i) { + Node* value = values[i]; + switch (sig->GetParam(i)) { + case wasm::kWasmF32: + value = graph()->NewNode(m->BitcastFloat32ToInt32(), value); + // Intentionally fall to next case. + case wasm::kWasmI32: + BuildEncodeException32BitValue(&index, value); + break; + case wasm::kWasmF64: + value = graph()->NewNode(m->BitcastFloat64ToInt64(), value); + // Intentionally fall to next case. + case wasm::kWasmI64: { + Node* upper32 = graph()->NewNode( + m->TruncateInt64ToInt32(), + Binop(wasm::kExprI64ShrU, value, Int64Constant(32))); + BuildEncodeException32BitValue(&index, upper32); + Node* lower32 = graph()->NewNode(m->TruncateInt64ToInt32(), value); + BuildEncodeException32BitValue(&index, lower32); + break; + } + default: + CHECK(false); + break; + } + } + DCHECK_EQ(encoded_size, index); + return BuildCallToRuntime(Runtime::kWasmThrow, nullptr, 0); +} + +void WasmGraphBuilder::BuildEncodeException32BitValue(uint32_t* index, + Node* value) { + MachineOperatorBuilder* machine = jsgraph()->machine(); + Node* upper_parameters[] = { + BuildChangeUint32ToSmi(Int32Constant(*index)), + BuildChangeUint32ToSmi( + graph()->NewNode(machine->Word32Shr(), value, Int32Constant(16))), + }; + BuildCallToRuntime(Runtime::kWasmExceptionSetElement, upper_parameters, + arraysize(upper_parameters)); + ++(*index); + Node* lower_parameters[] = { + BuildChangeUint32ToSmi(Int32Constant(*index)), + BuildChangeUint32ToSmi(graph()->NewNode(machine->Word32And(), value, + Int32Constant(0xFFFFu))), + }; + BuildCallToRuntime(Runtime::kWasmExceptionSetElement, lower_parameters, + arraysize(lower_parameters)); + ++(*index); +} + +Node* WasmGraphBuilder::BuildDecodeException32BitValue(Node* const* values, + uint32_t* index) { + MachineOperatorBuilder* machine = jsgraph()->machine(); + Node* upper = BuildChangeSmiToInt32(values[*index]); + (*index)++; + upper = graph()->NewNode(machine->Word32Shl(), upper, Int32Constant(16)); + Node* lower = BuildChangeSmiToInt32(values[*index]); + (*index)++; + Node* value = graph()->NewNode(machine->Word32Or(), upper, lower); + return value; } Node* WasmGraphBuilder::Rethrow() { SetNeedsStackCheck(); - Node* result = BuildCallToRuntime(Runtime::kWasmRethrow, nullptr, 0); + Node* result = BuildCallToRuntime(Runtime::kWasmThrow, nullptr, 0); return result; } -Node* WasmGraphBuilder::Catch(Node* input, wasm::WasmCodePosition position) { +Node* WasmGraphBuilder::ConvertExceptionTagToRuntimeId(uint32_t tag) { + // TODO(kschimpf): Handle exceptions from different modules, when they are + // linked at runtime. + return Uint32Constant(tag); +} + +Node* WasmGraphBuilder::GetExceptionRuntimeId() { SetNeedsStackCheck(); - Node* parameters[] = {input}; // caught value - Node* value = BuildCallToRuntime(Runtime::kWasmSetCaughtExceptionValue, + return BuildChangeSmiToInt32( + BuildCallToRuntime(Runtime::kWasmGetExceptionRuntimeId, nullptr, 0)); +} + +Node** WasmGraphBuilder::GetExceptionValues( + const wasm::WasmException* except_decl) { + // TODO(kschimpf): We need to move this code to the function-body-decoder.cc + // in order to build landing-pad (exception) edges in case the runtime + // call causes an exception. + + // Start by getting the encoded values from the exception. + uint32_t encoded_size = GetExceptionEncodedSize(except_decl); + Node** values = Buffer(encoded_size); + for (uint32_t i = 0; i < encoded_size; ++i) { + Node* parameters[] = {BuildChangeUint32ToSmi(Uint32Constant(i))}; + values[i] = BuildCallToRuntime(Runtime::kWasmExceptionGetElement, parameters, arraysize(parameters)); - parameters[0] = value; - value = BuildCallToRuntime(Runtime::kWasmGetExceptionTag, parameters, - arraysize(parameters)); - return BuildChangeSmiToInt32(value); + } + + // Now convert the leading entries to the corresponding parameter values. + uint32_t index = 0; + const wasm::WasmExceptionSig* sig = except_decl->sig; + for (size_t i = 0; i < sig->parameter_count(); ++i) { + Node* value = BuildDecodeException32BitValue(values, &index); + switch (wasm::ValueType type = sig->GetParam(i)) { + case wasm::kWasmF32: { + value = Unop(wasm::kExprF32ReinterpretI32, value); + break; + } + case wasm::kWasmI32: + break; + case wasm::kWasmF64: + case wasm::kWasmI64: { + Node* upper = + Binop(wasm::kExprI64Shl, Unop(wasm::kExprI64UConvertI32, value), + Int64Constant(32)); + Node* lower = Unop(wasm::kExprI64UConvertI32, + BuildDecodeException32BitValue(values, &index)); + value = Binop(wasm::kExprI64Ior, upper, lower); + if (type == wasm::kWasmF64) { + value = Unop(wasm::kExprF64ReinterpretI64, value); + } + break; + } + default: + CHECK(false); + break; + } + values[i] = value; + } + DCHECK_EQ(index, encoded_size); + return values; } Node* WasmGraphBuilder::BuildI32DivS(Node* left, Node* right, @@ -2147,9 +2288,8 @@ Node* WasmGraphBuilder::BuildDiv64Call(Node* left, Node* right, sig_builder.AddParam(MachineType::Pointer()); Node* function = graph()->NewNode(jsgraph()->common()->ExternalConstant(ref)); - Node* args[] = {function, stack_slot_dst, stack_slot_src}; - - Node* call = BuildCCall(sig_builder.Build(), args); + Node* call = + BuildCCall(sig_builder.Build(), function, stack_slot_dst, stack_slot_src); ZeroCheck32(static_cast<wasm::TrapReason>(trap_zero), call, position); TrapIfEq32(wasm::kTrapDivUnrepresentable, call, -1, position); @@ -2161,23 +2301,18 @@ Node* WasmGraphBuilder::BuildDiv64Call(Node* left, Node* right, return load; } -Node* WasmGraphBuilder::BuildCCall(MachineSignature* sig, Node** args) { - const size_t params = sig->parameter_count(); - const size_t extra = 2; // effect and control inputs. - const size_t count = 1 + params + extra; - - // Reallocate the buffer to make space for extra inputs. - args = Realloc(args, 1 + params, count); - - // Add effect and control inputs. - args[params + 1] = *effect_; - args[params + 2] = *control_; +template <typename... Args> +Node* WasmGraphBuilder::BuildCCall(MachineSignature* sig, Node* function, + Args... args) { + DCHECK_LE(sig->return_count(), 1); + DCHECK_EQ(sizeof...(args), sig->parameter_count()); + Node* const call_args[] = {function, args..., *effect_, *control_}; CallDescriptor* desc = Linkage::GetSimplifiedCDescriptor(jsgraph()->zone(), sig); const Operator* op = jsgraph()->common()->Call(desc); - Node* call = graph()->NewNode(op, static_cast<int>(count), args); + Node* call = graph()->NewNode(op, arraysize(call_args), call_args); *effect_ = call; return call; } @@ -2185,17 +2320,22 @@ Node* WasmGraphBuilder::BuildCCall(MachineSignature* sig, Node** args) { Node* WasmGraphBuilder::BuildWasmCall(wasm::FunctionSig* sig, Node** args, Node*** rets, wasm::WasmCodePosition position) { + DCHECK_NOT_NULL(wasm_context_); SetNeedsStackCheck(); const size_t params = sig->parameter_count(); - const size_t extra = 2; // effect and control inputs. + const size_t extra = 3; // wasm_context, effect, and control. const size_t count = 1 + params + extra; // Reallocate the buffer to make space for extra inputs. args = Realloc(args, 1 + params, count); + // Make room for the wasm_context parameter at index 1, just after code. + memmove(&args[2], &args[1], params * sizeof(Node*)); + args[1] = wasm_context_; + // Add effect and control inputs. - args[params + 1] = *effect_; - args[params + 2] = *control_; + args[params + 2] = *effect_; + args[params + 3] = *control_; CallDescriptor* descriptor = GetWasmCallDescriptor(jsgraph()->zone(), sig); const Operator* op = jsgraph()->common()->Call(descriptor); @@ -2441,7 +2581,7 @@ Node* WasmGraphBuilder::ToJS(Node* node, wasm::ValueType type) { } } -Node* WasmGraphBuilder::BuildJavaScriptToNumber(Node* node, Node* context) { +Node* WasmGraphBuilder::BuildJavaScriptToNumber(Node* node, Node* js_context) { Callable callable = Builtins::CallableFor(jsgraph()->isolate(), Builtins::kToNumber); CallDescriptor* desc = Linkage::GetStubCallDescriptor( @@ -2450,7 +2590,7 @@ Node* WasmGraphBuilder::BuildJavaScriptToNumber(Node* node, Node* context) { Node* stub_code = jsgraph()->HeapConstant(callable.code()); Node* result = graph()->NewNode(jsgraph()->common()->Call(desc), stub_code, - node, context, *effect_, *control_); + node, js_context, *effect_, *control_); SetSourcePosition(result, 1); @@ -2511,12 +2651,12 @@ Node* WasmGraphBuilder::BuildChangeTaggedToFloat64(Node* value) { return phi; } -Node* WasmGraphBuilder::FromJS(Node* node, Node* context, +Node* WasmGraphBuilder::FromJS(Node* node, Node* js_context, wasm::ValueType type) { DCHECK_NE(wasm::kWasmStmt, type); // Do a JavaScript ToNumber. - Node* num = BuildJavaScriptToNumber(node, context); + Node* num = BuildJavaScriptToNumber(node, js_context); // Change representation. SimplifiedOperatorBuilder simplified(jsgraph()->zone()); @@ -2590,11 +2730,12 @@ Node* WasmGraphBuilder::BuildAllocateHeapNumberWithValue(Node* value, Node* control) { MachineOperatorBuilder* machine = jsgraph()->machine(); CommonOperatorBuilder* common = jsgraph()->common(); - // The AllocateHeapNumberStub does not use the context, so we can safely pass - // in Smi zero here. - Callable callable = CodeFactory::AllocateHeapNumber(jsgraph()->isolate()); + // The AllocateHeapNumber builtin does not use the js_context, so we can + // safely pass in Smi zero here. + Callable callable = Builtins::CallableFor(jsgraph()->isolate(), + Builtins::kAllocateHeapNumber); Node* target = jsgraph()->HeapConstant(callable.code()); - Node* context = jsgraph()->NoContextConstant(); + Node* js_context = jsgraph()->NoContextConstant(); Node* effect = graph()->NewNode(common->BeginRegion(RegionObservability::kNotObservable), graph()->start()); @@ -2605,7 +2746,7 @@ Node* WasmGraphBuilder::BuildAllocateHeapNumberWithValue(Node* value, allocate_heap_number_operator_.set(common->Call(descriptor)); } Node* heap_number = graph()->NewNode(allocate_heap_number_operator_.get(), - target, context, effect, control); + target, js_context, effect, control); Node* store = graph()->NewNode(machine->Store(StoreRepresentation( MachineRepresentation::kFloat64, kNoWriteBarrier)), @@ -2624,9 +2765,11 @@ Node* WasmGraphBuilder::BuildHeapNumberValueIndexConstant() { return jsgraph()->IntPtrConstant(HeapNumber::kValueOffset - kHeapObjectTag); } -void WasmGraphBuilder::BuildJSToWasmWrapper(Handle<Code> wasm_code) { - int wasm_count = static_cast<int>(sig_->parameter_count()); - int count = wasm_count + 3; +void WasmGraphBuilder::BuildJSToWasmWrapper(Handle<Code> wasm_code, + Address wasm_context_address) { + const int wasm_count = static_cast<int>(sig_->parameter_count()); + const int count = + wasm_count + 4; // wasm_code, wasm_context, effect, and control. Node** args = Buffer(count); // Build the start and the JS parameter nodes. @@ -2634,27 +2777,33 @@ void WasmGraphBuilder::BuildJSToWasmWrapper(Handle<Code> wasm_code) { *control_ = start; *effect_ = start; - // Create the context parameter - Node* context = graph()->NewNode( + // Create the js_context parameter + Node* js_context = graph()->NewNode( jsgraph()->common()->Parameter( Linkage::GetJSCallContextParamIndex(wasm_count + 1), "%context"), graph()->start()); - // Set the ThreadInWasm flag before we do the actual call. - BuildModifyThreadInWasmFlag(true); + // Create the wasm_context node to pass as parameter. This must be a + // RelocatableIntPtrConstant because JSToWasm wrappers are compiled at module + // compile time and patched at instance build time. + DCHECK_NULL(wasm_context_); + wasm_context_ = jsgraph()->RelocatableIntPtrConstant( + reinterpret_cast<uintptr_t>(wasm_context_address), + RelocInfo::WASM_CONTEXT_REFERENCE); if (!wasm::IsJSCompatibleSignature(sig_)) { - // Throw a TypeError. Use the context of the calling javascript function - // (passed as a parameter), such that the generated code is context + // Throw a TypeError. Use the js_context of the calling javascript function + // (passed as a parameter), such that the generated code is js_context // independent. - BuildCallToRuntimeWithContext(Runtime::kWasmThrowTypeError, context, - nullptr, 0); + BuildCallToRuntimeWithContextFromJS(Runtime::kWasmThrowTypeError, + js_context, nullptr, 0); // Add a dummy call to the wasm function so that the generated wrapper // contains a reference to the wrapped wasm function. Without this reference // the wasm function could not be re-imported into another wasm module. int pos = 0; args[pos++] = HeapConstant(wasm_code); + args[pos++] = wasm_context_; args[pos++] = *effect_; args[pos++] = *control_; @@ -2669,14 +2818,18 @@ void WasmGraphBuilder::BuildJSToWasmWrapper(Handle<Code> wasm_code) { int pos = 0; args[pos++] = HeapConstant(wasm_code); + args[pos++] = wasm_context_; // Convert JS parameters to wasm numbers. for (int i = 0; i < wasm_count; ++i) { Node* param = Param(i + 1); - Node* wasm_param = FromJS(param, context, sig_->GetParam(i)); + Node* wasm_param = FromJS(param, js_context, sig_->GetParam(i)); args[pos++] = wasm_param; } + // Set the ThreadInWasm flag before we do the actual call. + BuildModifyThreadInWasmFlag(true); + args[pos++] = *effect_; args[pos++] = *control_; @@ -2699,13 +2852,42 @@ int WasmGraphBuilder::AddParameterNodes(Node** args, int pos, int param_count, wasm::FunctionSig* sig) { // Convert wasm numbers to JS values. for (int i = 0; i < param_count; ++i) { - Node* param = Param(i); + Node* param = Param(i + 1); // Start from index 1 to drop the wasm_context. args[pos++] = ToJS(param, sig->GetParam(i)); } return pos; } -void WasmGraphBuilder::BuildWasmToJSWrapper(Handle<JSReceiver> target) { +Node* WasmGraphBuilder::LoadImportDataAtOffset(int offset, Node* table) { + offset = FixedArray::OffsetOfElementAt(offset) - kHeapObjectTag; + Node* offset_node = jsgraph()->Int32Constant(offset); + Node* import_data = graph()->NewNode( + jsgraph()->machine()->Load(LoadRepresentation::TaggedPointer()), table, + offset_node, *effect_, *control_); + *effect_ = import_data; + return import_data; +} + +Node* WasmGraphBuilder::LoadNativeContext(Node* table) { + // The js_imports_table is set up so that index 0 has isolate->native_context + return LoadImportDataAtOffset(0, table); +} + +int OffsetForImportData(int index, WasmGraphBuilder::ImportDataType type) { + // The js_imports_table is set up so that index 0 has isolate->native_context + // and for every index, 3*index+1 has the JSReceiver, 3*index+2 has function's + // global proxy and 3*index+3 has function's context. + return 3 * index + type; +} + +Node* WasmGraphBuilder::LoadImportData(int index, ImportDataType type, + Node* table) { + return LoadImportDataAtOffset(OffsetForImportData(index, type), table); +} + +bool WasmGraphBuilder::BuildWasmToJSWrapper( + Handle<JSReceiver> target, Handle<FixedArray> global_js_imports_table, + int index) { DCHECK(target->IsCallable()); int wasm_count = static_cast<int>(sig_->parameter_count()); @@ -2717,17 +2899,28 @@ void WasmGraphBuilder::BuildWasmToJSWrapper(Handle<JSReceiver> target) { *effect_ = start; *control_ = start; + // We add the target function to a table and look it up during runtime. This + // ensures that if the GC kicks in, it doesn't need to patch the code for the + // JS function. + // js_imports_table is fixed array with global handle scope whose lifetime is + // tied to the instance. + // TODO(aseemgarg): explore using per-import global handle instead of a table + Node* table_ptr = jsgraph()->IntPtrConstant( + reinterpret_cast<intptr_t>(global_js_imports_table.location())); + Node* table = graph()->NewNode( + jsgraph()->machine()->Load(LoadRepresentation::TaggedPointer()), + table_ptr, jsgraph()->IntPtrConstant(0), *effect_, *control_); + *effect_ = table; + if (!wasm::IsJSCompatibleSignature(sig_)) { - // Throw a TypeError. Embedding the context is ok here, since this code is - // regenerated at instantiation time. - Node* context = - jsgraph()->HeapConstant(jsgraph()->isolate()->native_context()); - BuildCallToRuntimeWithContext(Runtime::kWasmThrowTypeError, context, + // Throw a TypeError. + Node* native_context = LoadNativeContext(table); + BuildCallToRuntimeWithContext(Runtime::kWasmThrowTypeError, native_context, nullptr, 0); // We don't need to return a value here, as the runtime call will not return // anyway (the c entry stub will trigger stack unwinding). ReturnVoid(); - return; + return false; } Node** args = Buffer(wasm_count + 7); @@ -2740,12 +2933,12 @@ void WasmGraphBuilder::BuildWasmToJSWrapper(Handle<JSReceiver> target) { Handle<JSFunction> function = Handle<JSFunction>::cast(target); if (function->shared()->internal_formal_parameter_count() == wasm_count) { int pos = 0; - args[pos++] = jsgraph()->Constant(target); // target callable. + args[pos++] = + LoadImportData(index, kFunction, table); // target callable. // Receiver. if (is_sloppy(function->shared()->language_mode()) && !function->shared()->native()) { - args[pos++] = - HeapConstant(handle(function->context()->global_proxy(), isolate)); + args[pos++] = LoadImportData(index, kGlobalProxy, table); } else { args[pos++] = jsgraph()->Constant( handle(isolate->heap()->undefined_value(), isolate)); @@ -2759,7 +2952,7 @@ void WasmGraphBuilder::BuildWasmToJSWrapper(Handle<JSReceiver> target) { args[pos++] = jsgraph()->UndefinedConstant(); // new target args[pos++] = jsgraph()->Int32Constant(wasm_count); // argument count - args[pos++] = HeapConstant(handle(function->context())); + args[pos++] = LoadImportData(index, kFunctionContext, table); args[pos++] = *effect_; args[pos++] = *control_; @@ -2768,11 +2961,12 @@ void WasmGraphBuilder::BuildWasmToJSWrapper(Handle<JSReceiver> target) { } // We cannot call the target directly, we have to use the Call builtin. + Node* native_context = nullptr; if (!call) { int pos = 0; Callable callable = CodeFactory::Call(isolate); args[pos++] = jsgraph()->HeapConstant(callable.code()); - args[pos++] = jsgraph()->Constant(target); // target callable + args[pos++] = LoadImportData(index, kFunction, table); // target callable. args[pos++] = jsgraph()->Int32Constant(wasm_count); // argument count args[pos++] = jsgraph()->Constant( handle(isolate->heap()->undefined_value(), isolate)); // receiver @@ -2789,7 +2983,8 @@ void WasmGraphBuilder::BuildWasmToJSWrapper(Handle<JSReceiver> target) { // is only needed if the target is a constructor to throw a TypeError, if // the target is a native function, or if the target is a callable JSObject, // which can only be constructed by the runtime. - args[pos++] = HeapConstant(isolate->native_context()); + native_context = LoadNativeContext(table); + args[pos++] = native_context; args[pos++] = *effect_; args[pos++] = *control_; @@ -2804,9 +2999,12 @@ void WasmGraphBuilder::BuildWasmToJSWrapper(Handle<JSReceiver> target) { // Convert the return value back. Node* val = sig_->return_count() == 0 ? jsgraph()->Int32Constant(0) - : FromJS(call, HeapConstant(isolate->native_context()), + : FromJS(call, + native_context != nullptr ? native_context + : LoadNativeContext(table), sig_->GetReturn()); Return(val); + return true; } namespace { @@ -2818,6 +3016,39 @@ bool HasInt64ParamOrReturn(wasm::FunctionSig* sig) { } } // namespace +void WasmGraphBuilder::BuildWasmToWasmWrapper(Handle<Code> target, + Address new_context_address) { + int wasm_count = static_cast<int>(sig_->parameter_count()); + int count = wasm_count + 4; // wasm_code, wasm_context, effect, and control. + Node** args = Buffer(count); + + // Build the start node. + Node* start = Start(count + 1); + *control_ = start; + *effect_ = start; + + int pos = 0; + // Add the wasm code target. + args[pos++] = jsgraph()->HeapConstant(target); + // Add the wasm_context of the other instance. + args[pos++] = jsgraph()->IntPtrConstant( + reinterpret_cast<uintptr_t>(new_context_address)); + // Add the parameters starting from index 1 since the parameter with index 0 + // is the old wasm_context. + for (int i = 0; i < wasm_count; ++i) { + args[pos++] = Param(i + 1); + } + args[pos++] = *effect_; + args[pos++] = *control_; + + // Call the wasm code. + CallDescriptor* desc = GetWasmCallDescriptor(jsgraph()->zone(), sig_); + Node* call = graph()->NewNode(jsgraph()->common()->Call(desc), count, args); + *effect_ = call; + Node* retval = sig_->return_count() == 0 ? jsgraph()->Int32Constant(0) : call; + Return(retval); +} + void WasmGraphBuilder::BuildWasmInterpreterEntry( uint32_t function_index, Handle<WasmInstanceObject> instance) { int param_count = static_cast<int>(sig_->parameter_count()); @@ -2852,9 +3083,10 @@ void WasmGraphBuilder::BuildWasmInterpreterEntry( for (int i = 0; i < param_count; ++i) { wasm::ValueType type = sig_->GetParam(i); - *effect_ = - graph()->NewNode(GetSafeStoreOperator(offset, type), arg_buffer, - Int32Constant(offset), Param(i), *effect_, *control_); + // Start from the parameter with index 1 to drop the wasm_context. + *effect_ = graph()->NewNode(GetSafeStoreOperator(offset, type), arg_buffer, + Int32Constant(offset), Param(i + 1), *effect_, + *control_); offset += 1 << ElementSizeLog2Of(type); } DCHECK_EQ(args_size_bytes, offset); @@ -2886,12 +3118,17 @@ void WasmGraphBuilder::BuildWasmInterpreterEntry( if (HasInt64ParamOrReturn(sig_)) LowerInt64(); } -void WasmGraphBuilder::BuildCWasmEntry() { +void WasmGraphBuilder::BuildCWasmEntry(Address wasm_context_address) { // Build the start and the JS parameter nodes. Node* start = Start(CWasmEntryParameters::kNumParameters + 5); *control_ = start; *effect_ = start; + // Create the wasm_context node to pass as parameter. + DCHECK_NULL(wasm_context_); + wasm_context_ = jsgraph()->IntPtrConstant( + reinterpret_cast<uintptr_t>(wasm_context_address)); + // Create parameter nodes (offset by 1 for the receiver parameter). Node* code_obj = Param(CWasmEntryParameters::kCodeObject + 1); Node* arg_buffer = Param(CWasmEntryParameters::kArgumentsBuffer + 1); @@ -2900,11 +3137,12 @@ void WasmGraphBuilder::BuildCWasmEntry() { BuildModifyThreadInWasmFlag(true); int wasm_arg_count = static_cast<int>(sig_->parameter_count()); - int arg_count = wasm_arg_count + 3; // args + code, control, effect + int arg_count = wasm_arg_count + 4; // code, wasm_context, control, effect Node** args = Buffer(arg_count); int pos = 0; args[pos++] = code_obj; + args[pos++] = wasm_context_; int offset = 0; for (wasm::ValueType type : sig_->parameters()) { @@ -2955,38 +3193,60 @@ void WasmGraphBuilder::BuildCWasmEntry() { } } -Node* WasmGraphBuilder::MemBuffer(uint32_t offset) { - DCHECK_NOT_NULL(env_); - const uintptr_t mem_start = static_cast<const uintptr_t>(env_->mem_start); - if (offset == 0) { - if (!mem_buffer_) { - mem_buffer_ = jsgraph()->RelocatableIntPtrConstant( - mem_start, RelocInfo::WASM_MEMORY_REFERENCE); - } - return mem_buffer_; - } else { - return jsgraph()->RelocatableIntPtrConstant( - static_cast<uintptr_t>(mem_start + offset), - RelocInfo::WASM_MEMORY_REFERENCE); +// This function is used by WasmFullDecoder to create a node that loads the +// mem_start variable from the WasmContext. It should not be used directly by +// the WasmGraphBuilder. The WasmGraphBuilder should directly use mem_start_, +// which will always contain the correct node (stored in the SsaEnv). +Node* WasmGraphBuilder::LoadMemStart() { + DCHECK_NOT_NULL(wasm_context_); + Node* mem_buffer = graph()->NewNode( + jsgraph()->machine()->Load(MachineType::UintPtr()), wasm_context_, + jsgraph()->Int32Constant( + static_cast<int32_t>(offsetof(WasmContext, mem_start))), + *effect_, *control_); + *effect_ = mem_buffer; + return mem_buffer; +} + +// This function is used by WasmFullDecoder to create a node that loads the +// mem_size variable from the WasmContext. It should not be used directly by +// the WasmGraphBuilder. The WasmGraphBuilder should directly use mem_size_, +// which will always contain the correct node (stored in the SsaEnv). +Node* WasmGraphBuilder::LoadMemSize() { + // Load mem_size from the memory_context location at runtime. + DCHECK_NOT_NULL(wasm_context_); + Node* mem_size = graph()->NewNode( + jsgraph()->machine()->Load(MachineType::Uint32()), wasm_context_, + jsgraph()->Int32Constant( + static_cast<int32_t>(offsetof(WasmContext, mem_size))), + *effect_, *control_); + *effect_ = mem_size; + if (jsgraph()->machine()->Is64()) { + mem_size = graph()->NewNode(jsgraph()->machine()->ChangeUint32ToUint64(), + mem_size); } + return mem_size; +} + +Node* WasmGraphBuilder::MemBuffer(uint32_t offset) { + DCHECK_NOT_NULL(*mem_start_); + if (offset == 0) return *mem_start_; + return graph()->NewNode(jsgraph()->machine()->IntAdd(), *mem_start_, + jsgraph()->IntPtrConstant(offset)); } Node* WasmGraphBuilder::CurrentMemoryPages() { // CurrentMemoryPages can not be called from asm.js. DCHECK_EQ(wasm::kWasmOrigin, env_->module->origin()); - SetNeedsStackCheck(); - Node* call = BuildCallToRuntime(Runtime::kWasmMemorySize, nullptr, 0); - Node* result = BuildChangeSmiToInt32(call); - return result; -} - -Node* WasmGraphBuilder::MemSize() { - DCHECK_NOT_NULL(env_); - if (mem_size_) return mem_size_; - uint32_t size = env_->mem_size; - mem_size_ = jsgraph()->RelocatableInt32Constant( - size, RelocInfo::WASM_MEMORY_SIZE_REFERENCE); - return mem_size_; + DCHECK_NOT_NULL(*mem_size_); + Node* mem_size = *mem_size_; + if (jsgraph()->machine()->Is64()) { + mem_size = graph()->NewNode(jsgraph()->machine()->TruncateInt64ToInt32(), + mem_size); + } + return graph()->NewNode( + jsgraph()->machine()->Word32Shr(), mem_size, + jsgraph()->Int32Constant(WhichPowerOf2(wasm::WasmModule::kPageSize))); } void WasmGraphBuilder::EnsureFunctionTableNodes() { @@ -3013,51 +3273,46 @@ void WasmGraphBuilder::EnsureFunctionTableNodes() { Node* WasmGraphBuilder::BuildModifyThreadInWasmFlag(bool new_value) { // TODO(eholk): generate code to modify the thread-local storage directly, // rather than calling the runtime. - // - // Note that the runtime functions also toggle the wasm_execution_time - // counters. Make sure this behavior is preserved if we avoid the runtime - // call. if (!trap_handler::UseTrapHandler()) { return *control_; } - const Runtime::FunctionId f = - new_value ? Runtime::kSetThreadInWasm : Runtime::kClearThreadInWasm; - const Runtime::Function* fun = Runtime::FunctionForId(f); - DCHECK_EQ(0, fun->nargs); - const CallDescriptor* desc = Linkage::GetRuntimeCallDescriptor( - jsgraph()->zone(), f, fun->nargs, Operator::kNoProperties, - CallDescriptor::kNoFlags); - // CEntryStubConstant nodes have to be created and cached in the main - // thread. At the moment this is only done for CEntryStubConstant(1). - DCHECK_EQ(1, fun->result_size); - Node* inputs[] = {centry_stub_node_, - jsgraph()->ExternalConstant( - ExternalReference(f, jsgraph()->isolate())), // ref - jsgraph()->Int32Constant(fun->nargs), // arity - jsgraph()->NoContextConstant(), - *effect_, - *control_}; - - Node* node = jsgraph()->graph()->NewNode(jsgraph()->common()->Call(desc), - arraysize(inputs), inputs); - *effect_ = node; - return node; + // Using two functions instead of taking the new value as a parameter saves + // one instruction on each call to set up the parameter. + ExternalReference ref = + new_value ? ExternalReference::wasm_set_thread_in_wasm_flag( + jsgraph()->isolate()) + : ExternalReference::wasm_clear_thread_in_wasm_flag( + jsgraph()->isolate()); + MachineSignature::Builder sig_builder(jsgraph()->zone(), 0, 0); + return BuildCCall( + sig_builder.Build(), + graph()->NewNode(jsgraph()->common()->ExternalConstant(ref))); } // Only call this function for code which is not reused across instantiations, -// as we do not patch the embedded context. +// as we do not patch the embedded js_context. Node* WasmGraphBuilder::BuildCallToRuntimeWithContext(Runtime::FunctionId f, - Node* context, + Node* js_context, Node** parameters, int parameter_count) { - // Setting and clearing the thread-in-wasm flag should not be done as a normal - // runtime call. - DCHECK_NE(f, Runtime::kSetThreadInWasm); - DCHECK_NE(f, Runtime::kClearThreadInWasm); // We're leaving Wasm code, so clear the flag. *control_ = BuildModifyThreadInWasmFlag(false); + // Since the thread-in-wasm flag is clear, it is as if we are calling from JS. + Node* call = BuildCallToRuntimeWithContextFromJS(f, js_context, parameters, + parameter_count); + + // Restore the thread-in-wasm flag, since we have returned to Wasm. + *control_ = BuildModifyThreadInWasmFlag(true); + + return call; +} +// This version of BuildCallToRuntime does not clear and set the thread-in-wasm +// flag. +Node* WasmGraphBuilder::BuildCallToRuntimeWithContextFromJS( + Runtime::FunctionId f, Node* js_context, Node* const* parameters, + int parameter_count) { const Runtime::Function* fun = Runtime::FunctionForId(f); CallDescriptor* desc = Linkage::GetRuntimeCallDescriptor( jsgraph()->zone(), f, fun->nargs, Operator::kNoProperties, @@ -3065,9 +3320,9 @@ Node* WasmGraphBuilder::BuildCallToRuntimeWithContext(Runtime::FunctionId f, // CEntryStubConstant nodes have to be created and cached in the main // thread. At the moment this is only done for CEntryStubConstant(1). DCHECK_EQ(1, fun->result_size); - // At the moment we only allow 3 parameters. If more parameters are needed, + // At the moment we only allow 4 parameters. If more parameters are needed, // increase this constant accordingly. - static const int kMaxParams = 3; + static const int kMaxParams = 4; DCHECK_GE(kMaxParams, parameter_count); Node* inputs[kMaxParams + 6]; int count = 0; @@ -3078,7 +3333,7 @@ Node* WasmGraphBuilder::BuildCallToRuntimeWithContext(Runtime::FunctionId f, inputs[count++] = jsgraph()->ExternalConstant( ExternalReference(f, jsgraph()->isolate())); // ref inputs[count++] = jsgraph()->Int32Constant(fun->nargs); // arity - inputs[count++] = context; // context + inputs[count++] = js_context; // js_context inputs[count++] = *effect_; inputs[count++] = *control_; @@ -3086,9 +3341,6 @@ Node* WasmGraphBuilder::BuildCallToRuntimeWithContext(Runtime::FunctionId f, count, inputs); *effect_ = node; - // Restore the thread-in-wasm flag, since we have returned to Wasm. - *control_ = BuildModifyThreadInWasmFlag(true); - return node; } @@ -3132,39 +3384,43 @@ void WasmGraphBuilder::BoundsCheckMem(MachineType memtype, Node* index, uint32_t offset, wasm::WasmCodePosition position) { if (FLAG_wasm_no_bounds_checks) return; + DCHECK_NOT_NULL(*mem_size_); - uint64_t min_size = static_cast<uint64_t>(env_->module->initial_pages) * - wasm::WasmModule::kPageSize; - uint64_t max_size = static_cast<uint64_t>(env_->module->has_maximum_pages - ? env_->module->maximum_pages - : wasm::kV8MaxWasmMemoryPages) * - wasm::WasmModule::kPageSize; + uint32_t min_size = env_->module->initial_pages * wasm::WasmModule::kPageSize; + uint32_t max_size = + (env_->module->has_maximum_pages ? env_->module->maximum_pages + : wasm::kV8MaxWasmMemoryPages) * + wasm::WasmModule::kPageSize; byte access_size = wasm::WasmOpcodes::MemSize(memtype); - uint64_t end_offset = static_cast<uint64_t>(offset) + access_size; - if (end_offset > max_size) { + if (access_size > max_size || offset > max_size - access_size) { // The access will be out of bounds, even for the largest memory. TrapIfEq32(wasm::kTrapMemOutOfBounds, jsgraph()->Int32Constant(0), 0, position); return; } + uint32_t end_offset = offset + access_size; if (end_offset > min_size) { // The end offset is larger than the smallest memory. // Dynamically check the end offset against the actual memory size, which // is not known at compile time. - Node* cond = graph()->NewNode( - jsgraph()->machine()->Uint32LessThanOrEqual(), - jsgraph()->IntPtrConstant(static_cast<uintptr_t>(end_offset)), - jsgraph()->RelocatableInt32Constant( - static_cast<uint32_t>(env_->mem_size), - RelocInfo::WASM_MEMORY_SIZE_REFERENCE)); + Node* cond; + if (jsgraph()->machine()->Is32()) { + cond = graph()->NewNode(jsgraph()->machine()->Uint32LessThanOrEqual(), + jsgraph()->Int32Constant(end_offset), *mem_size_); + } else { + cond = graph()->NewNode( + jsgraph()->machine()->Uint64LessThanOrEqual(), + jsgraph()->Int64Constant(static_cast<int64_t>(end_offset)), + *mem_size_); + } TrapIfFalse(wasm::kTrapMemOutOfBounds, cond, position); } else { // The end offset is within the bounds of the smallest memory, so only // one check is required. Check to see if the index is also a constant. - Uint32Matcher m(index); + UintPtrMatcher m(index); if (m.HasValue()) { uint64_t index_val = m.Value(); if ((index_val + offset + access_size) <= min_size) { @@ -3175,11 +3431,22 @@ void WasmGraphBuilder::BoundsCheckMem(MachineType memtype, Node* index, } } - uint64_t effective_size = env_->mem_size - (end_offset - 1); - Node* cond = graph()->NewNode(jsgraph()->machine()->Uint32LessThan(), index, - jsgraph()->RelocatableInt32Constant( - static_cast<uint32_t>(effective_size), - RelocInfo::WASM_MEMORY_SIZE_REFERENCE)); + Node* effective_size; + if (jsgraph()->machine()->Is32()) { + effective_size = + graph()->NewNode(jsgraph()->machine()->Int32Sub(), *mem_size_, + jsgraph()->Int32Constant(end_offset - 1)); + } else { + effective_size = graph()->NewNode( + jsgraph()->machine()->Int64Sub(), *mem_size_, + jsgraph()->Int64Constant(static_cast<int64_t>(end_offset - 1))); + } + + const Operator* less = jsgraph()->machine()->Is32() + ? jsgraph()->machine()->Uint32LessThan() + : jsgraph()->machine()->Uint64LessThan(); + + Node* cond = graph()->NewNode(less, index, effective_size); TrapIfFalse(wasm::kTrapMemOutOfBounds, cond, position); } @@ -3204,29 +3471,50 @@ const Operator* WasmGraphBuilder::GetSafeStoreOperator(int offset, return jsgraph()->machine()->UnalignedStore(rep); } +Node* WasmGraphBuilder::TraceMemoryOperation(bool is_store, + MachineRepresentation rep, + Node* index, uint32_t offset, + wasm::WasmCodePosition position) { + Node* address = graph()->NewNode(jsgraph()->machine()->Int32Add(), + Int32Constant(offset), index); + Node* addr_low = BuildChangeInt32ToSmi(graph()->NewNode( + jsgraph()->machine()->Word32And(), address, Int32Constant(0xffff))); + Node* addr_high = BuildChangeInt32ToSmi(graph()->NewNode( + jsgraph()->machine()->Word32Shr(), address, Int32Constant(16))); + int32_t rep_i = static_cast<int32_t>(rep); + Node* params[] = { + jsgraph()->SmiConstant(is_store), // is_store + jsgraph()->SmiConstant(rep_i), // mem rep + addr_low, // address lower half word + addr_high // address higher half word + }; + Node* call = + BuildCallToRuntime(Runtime::kWasmTraceMemory, params, arraysize(params)); + SetSourcePosition(call, position); + return call; +} + Node* WasmGraphBuilder::LoadMem(wasm::ValueType type, MachineType memtype, Node* index, uint32_t offset, uint32_t alignment, wasm::WasmCodePosition position) { Node* load; + if (jsgraph()->machine()->Is64()) { + index = + graph()->NewNode(jsgraph()->machine()->ChangeUint32ToUint64(), index); + } // Wasm semantics throw on OOB. Introduce explicit bounds check. if (!FLAG_wasm_trap_handler || !V8_TRAP_HANDLER_SUPPORTED) { BoundsCheckMem(memtype, index, offset, position); } - if (jsgraph()->machine()->Is64()) { - index = - graph()->NewNode(jsgraph()->machine()->ChangeUint32ToUint64(), index); - } if (memtype.representation() == MachineRepresentation::kWord8 || jsgraph()->machine()->UnalignedLoadSupported(memtype.representation())) { - if (FLAG_wasm_trap_handler && V8_TRAP_HANDLER_SUPPORTED) { - DCHECK(FLAG_wasm_guard_pages); - Node* position_node = jsgraph()->Int32Constant(position); + if (trap_handler::UseTrapHandler()) { load = graph()->NewNode(jsgraph()->machine()->ProtectedLoad(memtype), - MemBuffer(offset), index, position_node, *effect_, - *control_); + MemBuffer(offset), index, *effect_, *control_); + SetSourcePosition(load, position); } else { load = graph()->NewNode(jsgraph()->machine()->Load(memtype), MemBuffer(offset), index, *effect_, *control_); @@ -3257,6 +3545,11 @@ Node* WasmGraphBuilder::LoadMem(wasm::ValueType type, MachineType memtype, } } + if (FLAG_wasm_trace_memory) { + TraceMemoryOperation(false, memtype.representation(), index, offset, + position); + } + return load; } @@ -3266,15 +3559,15 @@ Node* WasmGraphBuilder::StoreMem(MachineType memtype, Node* index, wasm::ValueType type) { Node* store; + if (jsgraph()->machine()->Is64()) { + index = + graph()->NewNode(jsgraph()->machine()->ChangeUint32ToUint64(), index); + } // Wasm semantics throw on OOB. Introduce explicit bounds check. if (!FLAG_wasm_trap_handler || !V8_TRAP_HANDLER_SUPPORTED) { BoundsCheckMem(memtype, index, offset, position); } - if (jsgraph()->machine()->Is64()) { - index = - graph()->NewNode(jsgraph()->machine()->ChangeUint32ToUint64(), index); - } #if defined(V8_TARGET_BIG_ENDIAN) val = BuildChangeEndiannessStore(val, memtype, type); #endif @@ -3282,10 +3575,10 @@ Node* WasmGraphBuilder::StoreMem(MachineType memtype, Node* index, if (memtype.representation() == MachineRepresentation::kWord8 || jsgraph()->machine()->UnalignedStoreSupported(memtype.representation())) { if (FLAG_wasm_trap_handler && V8_TRAP_HANDLER_SUPPORTED) { - Node* position_node = jsgraph()->Int32Constant(position); store = graph()->NewNode( jsgraph()->machine()->ProtectedStore(memtype.representation()), - MemBuffer(offset), index, val, position_node, *effect_, *control_); + MemBuffer(offset), index, val, *effect_, *control_); + SetSourcePosition(store, position); } else { StoreRepresentation rep(memtype.representation(), kNoWriteBarrier); store = @@ -3303,19 +3596,26 @@ Node* WasmGraphBuilder::StoreMem(MachineType memtype, Node* index, *effect_ = store; + if (FLAG_wasm_trace_memory) { + TraceMemoryOperation(true, memtype.representation(), index, offset, + position); + } + return store; } Node* WasmGraphBuilder::BuildAsmjsLoadMem(MachineType type, Node* index) { // TODO(turbofan): fold bounds checks for constant asm.js loads. // asm.js semantics use CheckedLoad (i.e. OOB reads return 0ish). + DCHECK_NOT_NULL(*mem_size_); + DCHECK_NOT_NULL(*mem_start_); if (jsgraph()->machine()->Is64()) { index = graph()->NewNode(jsgraph()->machine()->ChangeUint32ToUint64(), index); } const Operator* op = jsgraph()->machine()->CheckedLoad(type); Node* load = - graph()->NewNode(op, MemBuffer(0), index, MemSize(), *effect_, *control_); + graph()->NewNode(op, *mem_start_, index, *mem_size_, *effect_, *control_); *effect_ = load; return load; } @@ -3324,13 +3624,15 @@ Node* WasmGraphBuilder::BuildAsmjsStoreMem(MachineType type, Node* index, Node* val) { // TODO(turbofan): fold bounds checks for constant asm.js stores. // asm.js semantics use CheckedStore (i.e. ignore OOB writes). + DCHECK_NOT_NULL(*mem_size_); + DCHECK_NOT_NULL(*mem_start_); if (jsgraph()->machine()->Is64()) { index = graph()->NewNode(jsgraph()->machine()->ChangeUint32ToUint64(), index); } const Operator* op = jsgraph()->machine()->CheckedStore(type.representation()); - Node* store = graph()->NewNode(op, MemBuffer(0), index, MemSize(), val, + Node* store = graph()->NewNode(op, *mem_start_, index, *mem_size_, val, *effect_, *control_); *effect_ = store; return val; @@ -3348,7 +3650,7 @@ Node* WasmGraphBuilder::String(const char* string) { Graph* WasmGraphBuilder::graph() { return jsgraph()->graph(); } void WasmGraphBuilder::LowerInt64() { - if (!jsgraph()->machine()->Is32()) return; + if (jsgraph()->machine()->Is64()) return; Int64Lowering r(jsgraph()->graph(), jsgraph()->machine(), jsgraph()->common(), jsgraph()->zone(), sig_); r.LowerGraph(); @@ -3793,31 +4095,66 @@ Node* WasmGraphBuilder::Simd8x16ShuffleOp(const uint8_t shuffle[16], V(I32AtomicCompareExchange8U, CompareExchange, Uint8) \ V(I32AtomicCompareExchange16U, CompareExchange, Uint16) +#define ATOMIC_LOAD_LIST(V) \ + V(I32AtomicLoad, Uint32) \ + V(I32AtomicLoad8U, Uint8) \ + V(I32AtomicLoad16U, Uint16) + +#define ATOMIC_STORE_LIST(V) \ + V(I32AtomicStore, Uint32, kWord32) \ + V(I32AtomicStore8U, Uint8, kWord8) \ + V(I32AtomicStore16U, Uint16, kWord16) + Node* WasmGraphBuilder::AtomicOp(wasm::WasmOpcode opcode, Node* const* inputs, + uint32_t alignment, uint32_t offset, wasm::WasmCodePosition position) { + // TODO(gdeepti): Add alignment validation, traps on misalignment Node* node; switch (opcode) { -#define BUILD_ATOMIC_BINOP(Name, Operation, Type) \ - case wasm::kExpr##Name: { \ - BoundsCheckMem(MachineType::Type(), inputs[0], 0, position); \ - node = graph()->NewNode( \ - jsgraph()->machine()->Atomic##Operation(MachineType::Type()), \ - MemBuffer(0), inputs[0], inputs[1], *effect_, *control_); \ - break; \ +#define BUILD_ATOMIC_BINOP(Name, Operation, Type) \ + case wasm::kExpr##Name: { \ + BoundsCheckMem(MachineType::Type(), inputs[0], offset, position); \ + node = graph()->NewNode( \ + jsgraph()->machine()->Atomic##Operation(MachineType::Type()), \ + MemBuffer(offset), inputs[0], inputs[1], *effect_, *control_); \ + break; \ } ATOMIC_BINOP_LIST(BUILD_ATOMIC_BINOP) #undef BUILD_ATOMIC_BINOP -#define BUILD_ATOMIC_TERNARY_OP(Name, Operation, Type) \ - case wasm::kExpr##Name: { \ - BoundsCheckMem(MachineType::Type(), inputs[0], 0, position); \ - node = graph()->NewNode( \ - jsgraph()->machine()->Atomic##Operation(MachineType::Type()), \ - MemBuffer(0), inputs[0], inputs[1], inputs[2], *effect_, *control_); \ - break; \ +#define BUILD_ATOMIC_TERNARY_OP(Name, Operation, Type) \ + case wasm::kExpr##Name: { \ + BoundsCheckMem(MachineType::Type(), inputs[0], offset, position); \ + node = graph()->NewNode( \ + jsgraph()->machine()->Atomic##Operation(MachineType::Type()), \ + MemBuffer(offset), inputs[0], inputs[1], inputs[2], *effect_, \ + *control_); \ + break; \ } ATOMIC_TERNARY_LIST(BUILD_ATOMIC_TERNARY_OP) #undef BUILD_ATOMIC_TERNARY_OP + +#define BUILD_ATOMIC_LOAD_OP(Name, Type) \ + case wasm::kExpr##Name: { \ + BoundsCheckMem(MachineType::Type(), inputs[0], offset, position); \ + node = graph()->NewNode( \ + jsgraph()->machine()->AtomicLoad(MachineType::Type()), \ + MemBuffer(offset), inputs[0], *effect_, *control_); \ + break; \ + } + ATOMIC_LOAD_LIST(BUILD_ATOMIC_LOAD_OP) +#undef BUILD_ATOMIC_LOAD_OP + +#define BUILD_ATOMIC_STORE_OP(Name, Type, Rep) \ + case wasm::kExpr##Name: { \ + BoundsCheckMem(MachineType::Type(), inputs[0], offset, position); \ + node = graph()->NewNode( \ + jsgraph()->machine()->AtomicStore(MachineRepresentation::Rep), \ + MemBuffer(offset), inputs[0], inputs[1], *effect_, *control_); \ + break; \ + } + ATOMIC_STORE_LIST(BUILD_ATOMIC_STORE_OP) +#undef BUILD_ATOMIC_STORE_OP default: FATAL_UNSUPPORTED_OPCODE(opcode); } @@ -3825,17 +4162,28 @@ Node* WasmGraphBuilder::AtomicOp(wasm::WasmOpcode opcode, Node* const* inputs, return node; } -static void RecordFunctionCompilation(CodeEventListener::LogEventsAndTags tag, - Isolate* isolate, Handle<Code> code, - const char* message, uint32_t index, - const wasm::WasmName& module_name, - const wasm::WasmName& func_name) { - DCHECK(isolate->logger()->is_logging_code_events() || - isolate->is_profiling()); +#undef ATOMIC_BINOP_LIST +#undef ATOMIC_TERNARY_LIST +#undef ATOMIC_LOAD_LIST +#undef ATOMIC_STORE_LIST + +namespace { +bool must_record_function_compilation(Isolate* isolate) { + return isolate->logger()->is_logging_code_events() || isolate->is_profiling(); +} + +PRINTF_FORMAT(4, 5) +void RecordFunctionCompilation(CodeEventListener::LogEventsAndTags tag, + Isolate* isolate, Handle<Code> code, + const char* format, ...) { + DCHECK(must_record_function_compilation(isolate)); ScopedVector<char> buffer(128); - SNPrintF(buffer, "%s#%d:%.*s:%.*s", message, index, module_name.length(), - module_name.start(), func_name.length(), func_name.start()); + va_list arguments; + va_start(arguments, format); + int len = VSNPrintF(buffer, format, arguments); + CHECK_LT(0, len); + va_end(arguments); Handle<String> name_str = isolate->factory()->NewStringFromAsciiChecked(buffer.start()); Handle<String> script_str = @@ -3845,9 +4193,11 @@ static void RecordFunctionCompilation(CodeEventListener::LogEventsAndTags tag, PROFILE(isolate, CodeCreateEvent(tag, AbstractCode::cast(*code), *shared, *script_str, 0, 0)); } +} // namespace Handle<Code> CompileJSToWasmWrapper(Isolate* isolate, wasm::WasmModule* module, - Handle<Code> wasm_code, uint32_t index) { + Handle<Code> wasm_code, uint32_t index, + Address wasm_context_address) { const wasm::WasmFunction* func = &module->functions[index]; //---------------------------------------------------------------------------- @@ -3869,15 +4219,13 @@ Handle<Code> CompileJSToWasmWrapper(Isolate* isolate, wasm::WasmModule* module, std::vector<wasm::SignatureMap*>(), // signature_maps std::vector<Handle<Code>>(), // function_code BUILTIN_CODE(isolate, Illegal), // default_function_code - 0, - 0, 0}; WasmGraphBuilder builder(&env, &zone, &jsgraph, CEntryStub(isolate, 1).GetCode(), func->sig); builder.set_control_ptr(&control); builder.set_effect_ptr(&effect); - builder.BuildJSToWasmWrapper(wasm_code); + builder.BuildJSToWasmWrapper(wasm_code, wasm_context_address); //---------------------------------------------------------------------------- // Run the compilation pipeline. @@ -3893,50 +4241,67 @@ Handle<Code> CompileJSToWasmWrapper(Isolate* isolate, wasm::WasmModule* module, static_cast<int>(module->functions[index].sig->parameter_count()); CallDescriptor* incoming = Linkage::GetJSCallDescriptor( &zone, false, params + 1, CallDescriptor::kNoFlags); - Code::Flags flags = Code::ComputeFlags(Code::JS_TO_WASM_FUNCTION); - bool debugging = -#if DEBUG - true; -#else - FLAG_print_opt_code || FLAG_trace_turbo || FLAG_trace_turbo_graph; -#endif - Vector<const char> func_name = ArrayVector("js-to-wasm"); +#ifdef DEBUG + EmbeddedVector<char, 32> func_name; static unsigned id = 0; - Vector<char> buffer; - if (debugging) { - buffer = Vector<char>::New(128); - int chars = SNPrintF(buffer, "js-to-wasm#%d", id); - func_name = Vector<const char>::cast(buffer.SubVector(0, chars)); - } + func_name.Truncate(SNPrintF(func_name, "js-to-wasm#%d", id++)); +#else + Vector<const char> func_name = CStrVector("js-to-wasm"); +#endif - CompilationInfo info(func_name, isolate, &zone, flags); + CompilationInfo info(func_name, isolate, &zone, Code::JS_TO_WASM_FUNCTION); Handle<Code> code = Pipeline::GenerateCodeForTesting(&info, incoming, &graph); #ifdef ENABLE_DISASSEMBLER if (FLAG_print_opt_code && !code.is_null()) { OFStream os(stdout); - code->Disassemble(buffer.start(), os); + code->Disassemble(func_name.start(), os); } #endif - if (debugging) { - buffer.Dispose(); - } - if (isolate->logger()->is_logging_code_events() || isolate->is_profiling()) { - char func_name[32]; - SNPrintF(ArrayVector(func_name), "js-to-wasm#%d", func->func_index); + if (must_record_function_compilation(isolate)) { RecordFunctionCompilation(CodeEventListener::FUNCTION_TAG, isolate, code, - "js-to-wasm", index, wasm::WasmName("export"), - CStrVector(func_name)); + "%.*s", func_name.length(), func_name.start()); } + return code; } -Handle<Code> CompileWasmToJSWrapper(Isolate* isolate, Handle<JSReceiver> target, - wasm::FunctionSig* sig, uint32_t index, - Handle<String> module_name, - MaybeHandle<String> import_name, - wasm::ModuleOrigin origin) { +void ValidateImportWrapperReferencesImmovables(Handle<Code> wrapper) { +#if !DEBUG + return; +#endif + // We expect the only embedded objects to be those originating from + // a snapshot, which are immovable. + DisallowHeapAllocation no_gc; + if (wrapper.is_null()) return; + static constexpr int kAllGCRefs = (1 << (RelocInfo::LAST_GCED_ENUM + 1)) - 1; + for (RelocIterator it(*wrapper, kAllGCRefs); !it.done(); it.next()) { + RelocInfo::Mode mode = it.rinfo()->rmode(); + Object* target = nullptr; + switch (mode) { + case RelocInfo::CODE_TARGET: + // this would be either one of the stubs or builtins, because + // we didn't link yet. + target = reinterpret_cast<Object*>(it.rinfo()->target_address()); + break; + case RelocInfo::EMBEDDED_OBJECT: + target = it.rinfo()->target_object(); + break; + default: + UNREACHABLE(); + } + CHECK_NOT_NULL(target); + bool is_immovable = + target->IsSmi() || Heap::IsImmovable(HeapObject::cast(target)); + CHECK(is_immovable); + } +} + +Handle<Code> CompileWasmToJSWrapper( + Isolate* isolate, Handle<JSReceiver> target, wasm::FunctionSig* sig, + uint32_t index, wasm::ModuleOrigin origin, + Handle<FixedArray> global_js_imports_table) { //---------------------------------------------------------------------------- // Create the Graph //---------------------------------------------------------------------------- @@ -3958,10 +4323,20 @@ Handle<Code> CompileWasmToJSWrapper(Isolate* isolate, Handle<JSReceiver> target, source_position_table); builder.set_control_ptr(&control); builder.set_effect_ptr(&effect); - builder.BuildWasmToJSWrapper(target); + if (builder.BuildWasmToJSWrapper(target, global_js_imports_table, index)) { + global_js_imports_table->set( + OffsetForImportData(index, WasmGraphBuilder::kFunction), *target); + if (target->IsJSFunction()) { + Handle<JSFunction> function = Handle<JSFunction>::cast(target); + global_js_imports_table->set( + OffsetForImportData(index, WasmGraphBuilder::kFunctionContext), + function->context()); + global_js_imports_table->set( + OffsetForImportData(index, WasmGraphBuilder::kGlobalProxy), + function->context()->global_proxy()); + } + } - Handle<Code> code = Handle<Code>::null(); - { if (FLAG_trace_turbo_graph) { // Simple textual RPO. OFStream os(stdout); os << "-- Graph after change lowering -- " << std::endl; @@ -3973,48 +4348,105 @@ Handle<Code> CompileWasmToJSWrapper(Isolate* isolate, Handle<JSReceiver> target, if (machine.Is32()) { incoming = GetI32WasmCallDescriptor(&zone, incoming); } - Code::Flags flags = Code::ComputeFlags(Code::WASM_TO_JS_FUNCTION); - bool debugging = -#if DEBUG - true; + +#ifdef DEBUG + EmbeddedVector<char, 32> func_name; + static unsigned id = 0; + func_name.Truncate(SNPrintF(func_name, "wasm-to-js#%d", id++)); #else - FLAG_print_opt_code || FLAG_trace_turbo || FLAG_trace_turbo_graph; + Vector<const char> func_name = CStrVector("wasm-to-js"); #endif - Vector<const char> func_name = ArrayVector("wasm-to-js"); - static unsigned id = 0; - Vector<char> buffer; - if (debugging) { - buffer = Vector<char>::New(128); - int chars = SNPrintF(buffer, "wasm-to-js#%d", id); - func_name = Vector<const char>::cast(buffer.SubVector(0, chars)); - } - CompilationInfo info(func_name, isolate, &zone, flags); - code = Pipeline::GenerateCodeForTesting(&info, incoming, &graph, nullptr, - source_position_table); + CompilationInfo info(func_name, isolate, &zone, Code::WASM_TO_JS_FUNCTION); + Handle<Code> code = Pipeline::GenerateCodeForTesting( + &info, incoming, &graph, nullptr, source_position_table); + ValidateImportWrapperReferencesImmovables(code); + Handle<FixedArray> deopt_data = + isolate->factory()->NewFixedArray(2, TENURED); + intptr_t loc = + reinterpret_cast<intptr_t>(global_js_imports_table.location()); + Handle<Object> loc_handle = isolate->factory()->NewHeapNumberFromBits(loc); + deopt_data->set(0, *loc_handle); + Handle<Object> index_handle = isolate->factory()->NewNumberFromInt( + OffsetForImportData(index, WasmGraphBuilder::kFunction)); + deopt_data->set(1, *index_handle); + code->set_deoptimization_data(*deopt_data); #ifdef ENABLE_DISASSEMBLER if (FLAG_print_opt_code && !code.is_null()) { OFStream os(stdout); - code->Disassemble(buffer.start(), os); + code->Disassemble(func_name.start(), os); } #endif - if (debugging) { - buffer.Dispose(); - } + + if (must_record_function_compilation(isolate)) { + RecordFunctionCompilation(CodeEventListener::FUNCTION_TAG, isolate, code, + "%.*s", func_name.length(), func_name.start()); + } + + return code; +} + +Handle<Code> CompileWasmToWasmWrapper(Isolate* isolate, Handle<Code> target, + wasm::FunctionSig* sig, uint32_t index, + Address new_wasm_context_address) { + //---------------------------------------------------------------------------- + // Create the Graph + //---------------------------------------------------------------------------- + Zone zone(isolate->allocator(), ZONE_NAME); + Graph graph(&zone); + CommonOperatorBuilder common(&zone); + MachineOperatorBuilder machine(&zone); + JSGraph jsgraph(isolate, &graph, &common, nullptr, nullptr, &machine); + + Node* control = nullptr; + Node* effect = nullptr; + + WasmGraphBuilder builder(nullptr, &zone, &jsgraph, Handle<Code>(), sig); + builder.set_control_ptr(&control); + builder.set_effect_ptr(&effect); + builder.BuildWasmToWasmWrapper(target, new_wasm_context_address); + if (HasInt64ParamOrReturn(sig)) builder.LowerInt64(); + + if (FLAG_trace_turbo_graph) { // Simple textual RPO. + OFStream os(stdout); + os << "-- Graph after change lowering -- " << std::endl; + os << AsRPO(graph); + } + + // Schedule and compile to machine code. + CallDescriptor* incoming = GetWasmCallDescriptor(&zone, sig); + if (machine.Is32()) { + incoming = GetI32WasmCallDescriptor(&zone, incoming); + } + bool debugging = +#if DEBUG + true; +#else + FLAG_print_opt_code || FLAG_trace_turbo || FLAG_trace_turbo_graph; +#endif + Vector<const char> func_name = ArrayVector("wasm-to-wasm"); + static unsigned id = 0; + Vector<char> buffer; + if (debugging) { + buffer = Vector<char>::New(128); + int chars = SNPrintF(buffer, "wasm-to-wasm#%d", id); + func_name = Vector<const char>::cast(buffer.SubVector(0, chars)); + } + + CompilationInfo info(func_name, isolate, &zone, Code::WASM_FUNCTION); + Handle<Code> code = Pipeline::GenerateCodeForTesting(&info, incoming, &graph); +#ifdef ENABLE_DISASSEMBLER + if (FLAG_print_opt_code && !code.is_null()) { + OFStream os(stdout); + code->Disassemble(buffer.start(), os); + } +#endif + if (debugging) { + buffer.Dispose(); } if (isolate->logger()->is_logging_code_events() || isolate->is_profiling()) { - const char* function_name = nullptr; - size_t function_name_size = 0; - if (!import_name.is_null()) { - Handle<String> handle = import_name.ToHandleChecked(); - function_name = handle->ToCString().get(); - function_name_size = static_cast<size_t>(handle->length()); - } RecordFunctionCompilation(CodeEventListener::FUNCTION_TAG, isolate, code, - "wasm-to-js", index, - {module_name->ToCString().get(), - static_cast<size_t>(module_name->length())}, - {function_name, function_name_size}); + "wasm-to-wasm#%d", index); } return code; @@ -4048,7 +4480,7 @@ Handle<Code> CompileWasmInterpreterEntry(Isolate* isolate, uint32_t func_index, { if (FLAG_trace_turbo_graph) { // Simple textual RPO. OFStream os(stdout); - os << "-- Wasm to interpreter graph -- " << std::endl; + os << "-- Wasm interpreter entry graph -- " << std::endl; os << AsRPO(graph); } @@ -4057,27 +4489,27 @@ Handle<Code> CompileWasmInterpreterEntry(Isolate* isolate, uint32_t func_index, if (machine.Is32()) { incoming = GetI32WasmCallDescriptor(&zone, incoming); } - Code::Flags flags = Code::ComputeFlags(Code::WASM_INTERPRETER_ENTRY); - EmbeddedVector<char, 32> debug_name; - int name_len = SNPrintF(debug_name, "wasm-to-interpreter#%d", func_index); - DCHECK(name_len > 0 && name_len < debug_name.length()); - debug_name.Truncate(name_len); - DCHECK_EQ('\0', debug_name.start()[debug_name.length()]); - - CompilationInfo info(debug_name, isolate, &zone, flags); +#ifdef DEBUG + EmbeddedVector<char, 32> func_name; + func_name.Truncate( + SNPrintF(func_name, "wasm-interpreter-entry#%d", func_index)); +#else + Vector<const char> func_name = CStrVector("wasm-interpreter-entry"); +#endif + + CompilationInfo info(func_name, isolate, &zone, + Code::WASM_INTERPRETER_ENTRY); code = Pipeline::GenerateCodeForTesting(&info, incoming, &graph, nullptr); #ifdef ENABLE_DISASSEMBLER if (FLAG_print_opt_code && !code.is_null()) { OFStream os(stdout); - code->Disassemble(debug_name.start(), os); + code->Disassemble(func_name.start(), os); } #endif - if (isolate->logger()->is_logging_code_events() || - isolate->is_profiling()) { + if (must_record_function_compilation(isolate)) { RecordFunctionCompilation(CodeEventListener::FUNCTION_TAG, isolate, code, - "wasm-to-interpreter", func_index, - wasm::WasmName("module"), debug_name); + "%.*s", func_name.length(), func_name.start()); } } @@ -4089,7 +4521,8 @@ Handle<Code> CompileWasmInterpreterEntry(Isolate* isolate, uint32_t func_index, return code; } -Handle<Code> CompileCWasmEntry(Isolate* isolate, wasm::FunctionSig* sig) { +Handle<Code> CompileCWasmEntry(Isolate* isolate, wasm::FunctionSig* sig, + Address wasm_context_address) { Zone zone(isolate->allocator(), ZONE_NAME); Graph graph(&zone); CommonOperatorBuilder common(&zone); @@ -4103,7 +4536,7 @@ Handle<Code> CompileCWasmEntry(Isolate* isolate, wasm::FunctionSig* sig) { CEntryStub(isolate, 1).GetCode(), sig); builder.set_control_ptr(&control); builder.set_effect_ptr(&effect); - builder.BuildCWasmEntry(); + builder.BuildCWasmEntry(wasm_context_address); if (FLAG_trace_turbo_graph) { // Simple textual RPO. OFStream os(stdout); @@ -4115,7 +4548,6 @@ Handle<Code> CompileCWasmEntry(Isolate* isolate, wasm::FunctionSig* sig) { CallDescriptor* incoming = Linkage::GetJSCallDescriptor( &zone, false, CWasmEntryParameters::kNumParameters + 1, CallDescriptor::kNoFlags); - Code::Flags flags = Code::ComputeFlags(Code::C_WASM_ENTRY); // Build a name in the form "c-wasm-entry:<params>:<returns>". static constexpr size_t kMaxNameLen = 128; @@ -4134,7 +4566,7 @@ Handle<Code> CompileCWasmEntry(Isolate* isolate, wasm::FunctionSig* sig) { debug_name[name_len] = '\0'; Vector<const char> debug_name_vec(debug_name, name_len); - CompilationInfo info(debug_name_vec, isolate, &zone, flags); + CompilationInfo info(debug_name_vec, isolate, &zone, Code::C_WASM_ENTRY); Handle<Code> code = Pipeline::GenerateCodeForTesting(&info, incoming, &graph); #ifdef ENABLE_DISASSEMBLER if (FLAG_print_opt_code && !code.is_null()) { @@ -4166,7 +4598,8 @@ SourcePositionTable* WasmCompilationUnit::BuildGraphForWasmFunction( SourcePositionTable* source_position_table = new (jsgraph_->zone()) SourcePositionTable(jsgraph_->graph()); WasmGraphBuilder builder(env_, jsgraph_->zone(), jsgraph_, centry_stub_, - func_body_.sig, source_position_table); + func_body_.sig, source_position_table, + runtime_exception_support_); graph_construction_result_ = wasm::BuildTFGraph(isolate_->allocator(), &builder, func_body_); @@ -4181,7 +4614,8 @@ SourcePositionTable* WasmCompilationUnit::BuildGraphForWasmFunction( builder.LowerInt64(); - if (builder.has_simd() && !CpuFeatures::SupportsWasmSimd128()) { + if (builder.has_simd() && + (!CpuFeatures::SupportsWasmSimd128() || lower_simd_)) { SimdScalarLowering(jsgraph_, func_body_.sig).LowerGraph(); } @@ -4216,51 +4650,19 @@ Vector<const char> GetDebugName(Zone* zone, wasm::WasmName name, int index) { } // namespace WasmCompilationUnit::WasmCompilationUnit( - Isolate* isolate, const wasm::ModuleWireBytes& wire_bytes, ModuleEnv* env, - const wasm::WasmFunction* function, Handle<Code> centry_stub) - : WasmCompilationUnit( - isolate, env, - wasm::FunctionBody{function->sig, function->code.offset(), - wire_bytes.start() + function->code.offset(), - wire_bytes.start() + function->code.end_offset()}, - wire_bytes.GetNameOrNull(function), function->func_index, - centry_stub) {} - -WasmCompilationUnit::WasmCompilationUnit(Isolate* isolate, ModuleEnv* env, - wasm::FunctionBody body, - wasm::WasmName name, int index, - Handle<Code> centry_stub) - : isolate_(isolate), - env_(env), - func_body_(body), - func_name_(name), - counters_(isolate->counters()), - centry_stub_(centry_stub), - func_index_(index) {} - -WasmCompilationUnit::WasmCompilationUnit( - Isolate* isolate, const wasm::ModuleWireBytes& wire_bytes, ModuleEnv* env, - const wasm::WasmFunction* function, Handle<Code> centry_stub, - const std::shared_ptr<Counters>& async_counters) - : WasmCompilationUnit( - isolate, env, - wasm::FunctionBody{function->sig, function->code.offset(), - wire_bytes.start() + function->code.offset(), - wire_bytes.start() + function->code.end_offset()}, - wire_bytes.GetNameOrNull(function), function->func_index, centry_stub, - async_counters) {} - -WasmCompilationUnit::WasmCompilationUnit( Isolate* isolate, ModuleEnv* env, wasm::FunctionBody body, wasm::WasmName name, int index, Handle<Code> centry_stub, - const std::shared_ptr<Counters>& async_counters) + Counters* counters, RuntimeExceptionSupport exception_support, + bool lower_simd) : isolate_(isolate), env_(env), func_body_(body), func_name_(name), - counters_(async_counters.get()), + counters_(counters ? counters : isolate->counters()), centry_stub_(centry_stub), - func_index_(index) {} + func_index_(index), + runtime_exception_support_(exception_support), + lower_simd_(lower_simd) {} void WasmCompilationUnit::ExecuteCompilation() { auto timed_histogram = env_->module->is_wasm() @@ -4315,8 +4717,7 @@ void WasmCompilationUnit::ExecuteCompilation() { } info_.reset(new CompilationInfo( GetDebugName(compilation_zone_.get(), func_name_, func_index_), - isolate_, compilation_zone_.get(), - Code::ComputeFlags(Code::WASM_FUNCTION))); + isolate_, compilation_zone_.get(), Code::WASM_FUNCTION)); ZoneVector<trap_handler::ProtectedInstructionData> protected_instructions( compilation_zone_.get()); @@ -4350,15 +4751,16 @@ MaybeHandle<Code> WasmCompilationUnit::FinishCompilation( wasm::ErrorThrower* thrower) { if (!ok_) { if (graph_construction_result_.failed()) { - // Add the function as another context for the exception - ScopedVector<char> buffer(128); + // Add the function as another context for the exception. + EmbeddedVector<char, 128> message; if (func_name_.start() == nullptr) { - SNPrintF(buffer, "Compiling wasm function #%d failed", func_index_); + SNPrintF(message, "Compiling wasm function #%d failed", func_index_); } else { - SNPrintF(buffer, "Compiling wasm function #%d:%.*s failed", func_index_, - func_name_.length(), func_name_.start()); + wasm::TruncatedUserString<> trunc_name(func_name_); + SNPrintF(message, "Compiling wasm function #%d:%.*s failed", + func_index_, trunc_name.length(), trunc_name.start()); } - thrower->CompileFailed(buffer.start(), graph_construction_result_); + thrower->CompileFailed(message.start(), graph_construction_result_); } return {}; @@ -4373,11 +4775,11 @@ MaybeHandle<Code> WasmCompilationUnit::FinishCompilation( Handle<Code> code = info_->code(); DCHECK(!code.is_null()); - if (isolate_->logger()->is_logging_code_events() || - isolate_->is_profiling()) { + if (must_record_function_compilation(isolate_)) { + wasm::TruncatedUserString<> trunc_name(func_name_); RecordFunctionCompilation(CodeEventListener::FUNCTION_TAG, isolate_, code, - "WASM_function", func_index_, - wasm::WasmName("module"), func_name_); + "wasm_function#%d:%.*s", func_index_, + trunc_name.length(), trunc_name.start()); } if (FLAG_trace_wasm_decode_time) { @@ -4395,12 +4797,20 @@ MaybeHandle<Code> WasmCompilationUnit::CompileWasmFunction( wasm::ErrorThrower* thrower, Isolate* isolate, const wasm::ModuleWireBytes& wire_bytes, ModuleEnv* env, const wasm::WasmFunction* function) { - WasmCompilationUnit unit(isolate, wire_bytes, env, function, - CEntryStub(isolate, 1).GetCode()); + wasm::FunctionBody function_body{ + function->sig, function->code.offset(), + wire_bytes.start() + function->code.offset(), + wire_bytes.start() + function->code.end_offset()}; + WasmCompilationUnit unit( + isolate, env, function_body, wire_bytes.GetNameOrNull(function), + function->func_index, CEntryStub(isolate, 1).GetCode()); unit.ExecuteCompilation(); return unit.FinishCompilation(thrower); } +#undef WASM_64 +#undef FATAL_UNSUPPORTED_OPCODE + } // namespace compiler } // namespace internal } // namespace v8 |