[wasm] Make {WebAssembly.Function} work on any iterable.
This makes sure the "parameters" and "results" properties of the passed FunctionType object can be arbitrary iterable objects, not just plain JavaScript arrays. R=clemensh@chromium.org TEST=mjsunit/wasm/type-reflection BUG=v8:7742 Change-Id: Icba18c418e549deba9fff1855be4956813b1a953 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1733071 Commit-Queue: Michael Starzinger <mstarzinger@chromium.org> Reviewed-by: Clemens Hammacher <clemensh@chromium.org> Cr-Commit-Position: refs/heads/master@{#63049}
This commit is contained in:
parent
f51e0368ea
commit
d335cb6a11
@ -1378,6 +1378,21 @@ void WebAssemblyException(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
thrower.TypeError("WebAssembly.Exception cannot be called");
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
uint32_t GetIterableLength(i::Isolate* isolate, Local<Context> context,
|
||||
Local<Object> iterable) {
|
||||
Local<String> length = Utils::ToLocal(isolate->factory()->length_string());
|
||||
MaybeLocal<Value> property = iterable->Get(context, length);
|
||||
if (property.IsEmpty()) return i::kMaxUInt32;
|
||||
MaybeLocal<Uint32> number = property.ToLocalChecked()->ToArrayIndex(context);
|
||||
if (number.IsEmpty()) return i::kMaxUInt32;
|
||||
DCHECK_NE(i::kMaxUInt32, number.ToLocalChecked()->Value());
|
||||
return number.ToLocalChecked()->Value();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// WebAssembly.Function
|
||||
void WebAssemblyFunction(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
v8::Isolate* isolate = args.GetIsolate();
|
||||
@ -1402,13 +1417,16 @@ void WebAssemblyFunction(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
function_type->Get(context, parameters_key);
|
||||
v8::Local<v8::Value> parameters_value;
|
||||
if (!parameters_maybe.ToLocal(¶meters_value)) return;
|
||||
// TODO(7742): Allow any iterable, not just {Array} here.
|
||||
if (!parameters_value->IsArray()) {
|
||||
if (!parameters_value->IsObject()) {
|
||||
thrower.TypeError("Argument 0 must be a function type with 'parameters'");
|
||||
return;
|
||||
}
|
||||
Local<Array> parameters = parameters_value.As<Array>();
|
||||
uint32_t parameters_len = parameters->Length();
|
||||
Local<Object> parameters = parameters_value.As<Object>();
|
||||
uint32_t parameters_len = GetIterableLength(i_isolate, context, parameters);
|
||||
if (parameters_len == i::kMaxUInt32) {
|
||||
thrower.TypeError("Argument 0 contains parameters without 'length'");
|
||||
return;
|
||||
}
|
||||
if (parameters_len > i::wasm::kV8MaxWasmFunctionParams) {
|
||||
thrower.TypeError("Argument 0 contains too many parameters");
|
||||
return;
|
||||
@ -1420,13 +1438,16 @@ void WebAssemblyFunction(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
function_type->Get(context, results_key);
|
||||
v8::Local<v8::Value> results_value;
|
||||
if (!results_maybe.ToLocal(&results_value)) return;
|
||||
// TODO(7742): Allow any iterable, not just {Array} here.
|
||||
if (!results_value->IsArray()) {
|
||||
if (!results_value->IsObject()) {
|
||||
thrower.TypeError("Argument 0 must be a function type with 'results'");
|
||||
return;
|
||||
}
|
||||
Local<Array> results = results_value.As<Array>();
|
||||
uint32_t results_len = results->Length();
|
||||
Local<Object> results = results_value.As<Object>();
|
||||
uint32_t results_len = GetIterableLength(i_isolate, context, results);
|
||||
if (results_len == i::kMaxUInt32) {
|
||||
thrower.TypeError("Argument 0 contains results without 'length'");
|
||||
return;
|
||||
}
|
||||
if (results_len > (enabled_features.mv
|
||||
? i::wasm::kV8MaxWasmFunctionMultiReturns
|
||||
: i::wasm::kV8MaxWasmFunctionReturns)) {
|
||||
|
@ -209,6 +209,42 @@ load('test/mjsunit/wasm/wasm-module-builder.js');
|
||||
() => new WebAssembly.Function({parameters:[], results:[]}, _ => 0));
|
||||
})();
|
||||
|
||||
(function TestFunctionConstructorNonArray1() {
|
||||
let log = []; // Populated with a log of accesses.
|
||||
let two = { toString: () => "2" }; // Just a fancy "2".
|
||||
let logger = new Proxy({ length: two, "0": "i32", "1": "f32"}, {
|
||||
get: function(obj, prop) { log.push(prop); return Reflect.get(obj, prop); },
|
||||
set: function(obj, prop, val) { assertUnreachable(); }
|
||||
});
|
||||
let fun = new WebAssembly.Function({parameters:logger, results:[]}, _ => 0);
|
||||
assertArrayEquals(["i32", "f32"], WebAssembly.Function.type(fun).parameters);
|
||||
assertArrayEquals(["length", "0", "1"], log);
|
||||
})();
|
||||
|
||||
(function TestFunctionConstructorNonArray2() {
|
||||
let throw1 = { get length() { throw new Error("cannot see length"); }};
|
||||
let throw2 = { length: { toString: _ => { throw new Error("no length") } } };
|
||||
let throw3 = { length: "not a length value, this also throws" };
|
||||
assertThrows(
|
||||
() => new WebAssembly.Function({parameters:throw1, results:[]}), Error,
|
||||
/cannot see length/);
|
||||
assertThrows(
|
||||
() => new WebAssembly.Function({parameters:throw2, results:[]}), Error,
|
||||
/no length/);
|
||||
assertThrows(
|
||||
() => new WebAssembly.Function({parameters:throw3, results:[]}), TypeError,
|
||||
/Argument 0 contains parameters without 'length'/);
|
||||
assertThrows(
|
||||
() => new WebAssembly.Function({parameters:[], results:throw1}), Error,
|
||||
/cannot see length/);
|
||||
assertThrows(
|
||||
() => new WebAssembly.Function({parameters:[], results:throw2}), Error,
|
||||
/no length/);
|
||||
assertThrows(
|
||||
() => new WebAssembly.Function({parameters:[], results:throw3}), TypeError,
|
||||
/Argument 0 contains results without 'length'/);
|
||||
})();
|
||||
|
||||
(function TestFunctionConstructedFunction() {
|
||||
let fun = new WebAssembly.Function({parameters:[], results:[]}, _ => 0);
|
||||
assertTrue(fun instanceof WebAssembly.Function);
|
||||
|
Loading…
Reference in New Issue
Block a user