Commit 92b7c728 authored by ahaas's avatar ahaas Committed by Commit bot

[wasm] Throw a type error if an I64 is exported to JS.

As required by the spec, ToJS now throws a TypeError fit I64 values
instead of truncating the I64 value to I32. To throw a TypeError I
introduced a new runtime function because the existing
Runtime::kThrowWasmError does not throw a TypeError. Since we have calls
to two runtime functions now, and an additional one is needed for stack
checks, I extracted the call to runtime functions into a helper function.

R=titzer@chromium.org

TEST=mjsunit/wasm/ffi-error.js:I64InSignatureThrows

Review-Url: https://codereview.chromium.org/2254803002
Cr-Commit-Position: refs/heads/master@{#38718}
parent 49c14f63
......@@ -63,6 +63,39 @@ void MergeControlToEnd(JSGraph* jsgraph, Node* node) {
}
}
Node* BuildCallToRuntime(Runtime::FunctionId f, JSGraph* jsgraph,
Handle<Context> context, Node** parameters,
int parameter_count, Node** effect_ptr,
Node** control_ptr) {
// At the moment we only allow 2 parameters. If more parameters are needed,
// then the size of {inputs} below has to be increased accordingly.
DCHECK(parameter_count <= 2);
const Runtime::Function* fun = Runtime::FunctionForId(f);
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[8];
int count = 0;
inputs[count++] = jsgraph->CEntryStubConstant(fun->result_size);
for (int i = 0; i < parameter_count; i++) {
inputs[count++] = parameters[i];
}
inputs[count++] = jsgraph->ExternalConstant(
ExternalReference(f, jsgraph->isolate())); // ref
inputs[count++] = jsgraph->Int32Constant(fun->nargs); // arity
inputs[count++] = jsgraph->HeapConstant(context); // context
inputs[count++] = *effect_ptr;
inputs[count++] = *control_ptr;
Node* node =
jsgraph->graph()->NewNode(jsgraph->common()->Call(desc), count, inputs);
*effect_ptr = node;
return node;
}
} // namespace
// A helper that handles building graph fragments for trapping.
......@@ -226,30 +259,11 @@ class WasmTrapHelper : public ZoneObject {
Node* trap_position_smi = builder_->BuildChangeInt32ToSmi(trap_position_);
if (module && !module->instance->context.is_null()) {
// Use the module context to call the runtime to throw an exception.
Runtime::FunctionId f = Runtime::kThrowWasmError;
const Runtime::Function* fun = Runtime::FunctionForId(f);
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[] = {
jsgraph()->CEntryStubConstant(fun->result_size), // C entry
trap_reason_smi, // message id
trap_position_smi, // byte position
jsgraph()->ExternalConstant(
ExternalReference(f, jsgraph()->isolate())), // ref
jsgraph()->Int32Constant(fun->nargs), // arity
builder_->HeapConstant(module->instance->context), // context
*effect_ptr,
*control_ptr};
Node* node = graph()->NewNode(
common()->Call(desc), static_cast<int>(arraysize(inputs)), inputs);
*effect_ptr = node;
*control_ptr = graph()->NewNode(common()->IfSuccess(), node);
Node* parameters[] = {trap_reason_smi, // message id
trap_position_smi}; // byte position
BuildCallToRuntime(Runtime::kThrowWasmError, jsgraph(),
module->instance->context, parameters,
arraysize(parameters), effect_ptr, control_ptr);
}
if (false) {
// End the control flow with a throw
......@@ -2187,15 +2201,11 @@ Node* WasmGraphBuilder::ToJS(Node* node, wasm::LocalType type) {
case wasm::kAstI32:
return BuildChangeInt32ToTagged(node);
case wasm::kAstI64:
// TODO(titzer): i64->JS has no good solution right now. Using lower 32
// bits.
if (jsgraph()->machine()->Is64()) {
// On 32 bit platforms we do not have to do the truncation because the
// node we get in as a parameter only contains the low word anyways.
node = graph()->NewNode(jsgraph()->machine()->TruncateInt64ToInt32(),
node);
}
return BuildChangeInt32ToTagged(node);
DCHECK(module_ && !module_->instance->context.is_null());
// Throw a TypeError.
return BuildCallToRuntime(Runtime::kWasmThrowTypeError, jsgraph(),
module_->instance->context, nullptr, 0, effect_,
control_);
case wasm::kAstF32:
node = graph()->NewNode(jsgraph()->machine()->ChangeFloat32ToFloat64(),
node);
......@@ -2222,7 +2232,6 @@ Node* WasmGraphBuilder::BuildJavaScriptToNumber(Node* node, Node* context,
node, context, effect, control);
*effect_ = result;
*control_ = graph()->NewNode(jsgraph()->common()->IfSuccess(), result);
return result;
}
......
......@@ -539,7 +539,8 @@ class CallSiteUtils : public AllStatic {
T(WasmTrapFloatUnrepresentable, "integer result unrepresentable") \
T(WasmTrapFuncInvalid, "invalid function") \
T(WasmTrapFuncSigMismatch, "function signature mismatch") \
T(WasmTrapInvalidIndex, "invalid index into function table")
T(WasmTrapInvalidIndex, "invalid index into function table") \
T(WasmTrapTypeError, "invalid type")
class MessageTemplate {
public:
......
......@@ -109,5 +109,12 @@ RUNTIME_FUNCTION(Runtime_WasmGrowMemory) {
return *isolate->factory()->NewNumberFromInt(old_size /
wasm::WasmModule::kPageSize);
}
RUNTIME_FUNCTION(Runtime_WasmThrowTypeError) {
HandleScope scope(isolate);
DCHECK_EQ(0, args.length());
THROW_NEW_ERROR_RETURN_FAILURE(
isolate, NewTypeError(MessageTemplate::kWasmTrapTypeError));
}
} // namespace internal
} // namespace v8
......@@ -921,7 +921,9 @@ namespace internal {
F(DataViewSetFloat32, 4, 1) \
F(DataViewSetFloat64, 4, 1)
#define FOR_EACH_INTRINSIC_WASM(F) F(WasmGrowMemory, 1, 1)
#define FOR_EACH_INTRINSIC_WASM(F) \
F(WasmGrowMemory, 1, 1) \
F(WasmThrowTypeError, 0, 1)
#define FOR_EACH_INTRINSIC_RETURN_PAIR(F) \
F(LoadLookupSlotForCall, 1, 2)
......
......@@ -40,28 +40,6 @@ function assertFunction(module, func) {
return exp;
}
(function I64SubTest() {
var builder = new WasmModuleBuilder();
builder.addMemory(1, 1, true);
builder.addFunction("sub", kSig_l_ll)
.addBody([ // --
kExprGetLocal, 0, // --
kExprGetLocal, 1, // --
kExprI64Sub]) // --
.exportFunc()
var module = builder.instantiate();
assertModule(module, kPageSize);
// Check the properties of the sub function.
var sub = assertFunction(module, "sub");
assertEquals(-55, sub(33, 88));
assertEquals(-55555, sub(33333, 88888));
assertEquals(-5555555, sub(3333333, 8888888));
})();
(function SubTest() {
var builder = new WasmModuleBuilder();
......
......@@ -59,3 +59,22 @@ assertThrows(function() {
ffi.fun = 0;
testCallFFI(ffi);
});
(function I64InSignatureThrows() {
var builder = new WasmModuleBuilder();
builder.addMemory(1, 1, true);
builder.addFunction("function_with_invalid_signature", kSig_l_ll)
.addBody([ // --
kExprGetLocal, 0, // --
kExprGetLocal, 1, // --
kExprI64Sub]) // --
.exportFunc()
var module = builder.instantiate();
assertThrows(function() {
module.exports.function_with_invalid_signature(33, 88);
}, TypeError);
})();
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment