summaryrefslogtreecommitdiff
path: root/deps/v8/src/compiler/wasm-compiler.cc
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/src/compiler/wasm-compiler.cc')
-rw-r--r--deps/v8/src/compiler/wasm-compiler.cc1142
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