Commit 32e48cf5 authored by Michael Starzinger's avatar Michael Starzinger Committed by Commit Bot

[wasm] Support {WebAssembly.Function} object construction.

This makes the WebAssembly function constructor return a proper function
object. Note that the returned object is not yet callable, only the
prototype structure is in place.

R=jkummerow@chromium.org
TEST=mjsunit/wasm/type-reflection
BUG=v8:7742

Change-Id: If6a3d0ae7078b5526606eef1b8fd4815353b850b
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1627343
Commit-Queue: Michael Starzinger <mstarzinger@chromium.org>
Reviewed-by: 's avatarJakob Kummerow <jkummerow@chromium.org>
Cr-Commit-Position: refs/heads/master@{#61792}
parent be62dcc2
......@@ -880,6 +880,8 @@ extern class WasmExportedFunctionData extends Struct {
function_index: Smi;
}
extern class WasmJSFunctionData extends Struct { wrapper_code: Code; }
extern class WasmCapiFunctionData extends Struct {
call_target: RawPtr;
embedder_data: RawPtr;
......
......@@ -13511,6 +13511,7 @@ TNode<Code> CodeStubAssembler::GetSharedFunctionInfoCode(
UNCOMPILED_DATA_WITHOUT_PREPARSE_DATA_TYPE,
UNCOMPILED_DATA_WITH_PREPARSE_DATA_TYPE,
FUNCTION_TEMPLATE_INFO_TYPE,
WASM_JS_FUNCTION_DATA_TYPE,
WASM_CAPI_FUNCTION_DATA_TYPE};
Label check_is_bytecode_array(this);
Label check_is_exported_function_data(this);
......@@ -13519,6 +13520,7 @@ TNode<Code> CodeStubAssembler::GetSharedFunctionInfoCode(
Label check_is_uncompiled_data_with_preparse_data(this);
Label check_is_function_template_info(this);
Label check_is_interpreter_data(this);
Label check_is_wasm_js_function_data(this);
Label check_is_wasm_capi_function_data(this);
Label* case_labels[] = {&check_is_bytecode_array,
&check_is_exported_function_data,
......@@ -13526,6 +13528,7 @@ TNode<Code> CodeStubAssembler::GetSharedFunctionInfoCode(
&check_is_uncompiled_data_without_preparse_data,
&check_is_uncompiled_data_with_preparse_data,
&check_is_function_template_info,
&check_is_wasm_js_function_data,
&check_is_wasm_capi_function_data};
STATIC_ASSERT(arraysize(case_values) == arraysize(case_labels));
Switch(data_type, &check_is_interpreter_data, case_values, case_labels,
......@@ -13569,6 +13572,12 @@ TNode<Code> CodeStubAssembler::GetSharedFunctionInfoCode(
CAST(sfi_data), InterpreterData::kInterpreterTrampolineOffset));
Goto(&done);
// IsWasmJSFunctionData: Use the wrapper code.
BIND(&check_is_wasm_js_function_data);
sfi_code = CAST(
LoadObjectField(CAST(sfi_data), WasmJSFunctionData::kWrapperCodeOffset));
Goto(&done);
// IsWasmCapiFunctionData: Use the wrapper code.
BIND(&check_is_wasm_capi_function_data);
sfi_code = CAST(LoadObjectField(CAST(sfi_data),
......
......@@ -327,6 +327,7 @@ class WasmExceptionObject;
class WasmExceptionTag;
class WasmExportedFunctionData;
class WasmGlobalObject;
class WasmJSFunctionData;
class WasmMemoryObject;
class WasmModuleObject;
class WasmTableObject;
......
......@@ -357,6 +357,7 @@ Type::bitset BitsetType::Lub(const MapRefLike& map) {
case WASM_DEBUG_INFO_TYPE:
case WASM_EXCEPTION_TAG_TYPE:
case WASM_EXPORTED_FUNCTION_DATA_TYPE:
case WASM_JS_FUNCTION_DATA_TYPE:
case LOAD_HANDLER_TYPE:
case STORE_HANDLER_TYPE:
case ASYNC_GENERATOR_REQUEST_TYPE:
......
......@@ -1047,7 +1047,8 @@ void SharedFunctionInfo::SharedFunctionInfoVerify(Isolate* isolate) {
CHECK(HasWasmExportedFunctionData() || IsApiFunction() ||
HasBytecodeArray() || HasAsmWasmData() || HasBuiltinId() ||
HasUncompiledDataWithPreparseData() ||
HasUncompiledDataWithoutPreparseData() || HasWasmCapiFunctionData());
HasUncompiledDataWithoutPreparseData() || HasWasmJSFunctionData() ||
HasWasmCapiFunctionData());
CHECK(script_or_debug_info().IsUndefined(isolate) ||
script_or_debug_info().IsScript() || HasDebugInfo());
......@@ -1800,6 +1801,8 @@ USE_TORQUE_VERIFIER(FunctionTemplateRareData)
USE_TORQUE_VERIFIER(WasmCapiFunctionData)
USE_TORQUE_VERIFIER(WasmJSFunctionData)
USE_TORQUE_VERIFIER(ObjectTemplateInfo)
void AllocationSite::AllocationSiteVerify(Isolate* isolate) {
......
......@@ -1866,6 +1866,12 @@ void WasmExportedFunctionData::WasmExportedFunctionDataPrint(
os << "\n";
}
void WasmJSFunctionData::WasmJSFunctionDataPrint(std::ostream& os) { // NOLINT
PrintHeader(os, "WasmJSFunctionData");
os << "\n - wrapper_code: " << Brief(wrapper_code());
os << "\n";
}
void WasmModuleObject::WasmModuleObjectPrint(std::ostream& os) { // NOLINT
PrintHeader(os, "WasmModuleObject");
os << "\n - module: " << module();
......
......@@ -2412,7 +2412,7 @@ Handle<JSFunction> Factory::NewFunction(const NewFunctionArgs& args) {
Handle<NativeContext> context(isolate()->native_context());
Handle<Map> map = args.GetMap(isolate());
Handle<SharedFunctionInfo> info =
NewSharedFunctionInfo(args.name_, args.maybe_exported_function_data_,
NewSharedFunctionInfo(args.name_, args.maybe_wasm_function_data_,
args.maybe_builtin_id_, kNormalFunction);
// Proper language mode in shared function info will be set later.
......@@ -4224,7 +4224,21 @@ NewFunctionArgs NewFunctionArgs::ForWasm(
NewFunctionArgs args;
args.name_ = name;
args.maybe_map_ = map;
args.maybe_exported_function_data_ = exported_function_data;
args.maybe_wasm_function_data_ = exported_function_data;
args.language_mode_ = LanguageMode::kSloppy;
args.prototype_mutability_ = MUTABLE;
return args;
}
// static
NewFunctionArgs NewFunctionArgs::ForWasm(
Handle<String> name, Handle<WasmJSFunctionData> js_function_data,
Handle<Map> map) {
NewFunctionArgs args;
args.name_ = name;
args.maybe_map_ = map;
args.maybe_wasm_function_data_ = js_function_data;
args.language_mode_ = LanguageMode::kSloppy;
args.prototype_mutability_ = MUTABLE;
......
......@@ -67,6 +67,7 @@ class UncompiledDataWithoutPreparseData;
class UncompiledDataWithPreparseData;
class WasmCapiFunctionData;
class WasmExportedFunctionData;
class WasmJSFunctionData;
class WeakCell;
struct SourceRange;
template <typename T>
......@@ -1113,6 +1114,9 @@ class NewFunctionArgs final {
static NewFunctionArgs ForWasm(
Handle<String> name,
Handle<WasmExportedFunctionData> exported_function_data, Handle<Map> map);
static NewFunctionArgs ForWasm(Handle<String> name,
Handle<WasmJSFunctionData> js_function_data,
Handle<Map> map);
V8_EXPORT_PRIVATE static NewFunctionArgs ForBuiltin(Handle<String> name,
Handle<Map> map,
int builtin_id);
......@@ -1141,7 +1145,7 @@ class NewFunctionArgs final {
Handle<String> name_;
MaybeHandle<Map> maybe_map_;
MaybeHandle<WasmExportedFunctionData> maybe_exported_function_data_;
MaybeHandle<Struct> maybe_wasm_function_data_;
bool should_create_and_set_initial_map_ = false;
InstanceType type_;
......
......@@ -179,6 +179,7 @@ enum InstanceType : uint16_t {
WASM_DEBUG_INFO_TYPE,
WASM_EXCEPTION_TAG_TYPE,
WASM_EXPORTED_FUNCTION_DATA_TYPE,
WASM_JS_FUNCTION_DATA_TYPE,
CALLABLE_TASK_TYPE, // FIRST_MICROTASK_TYPE
CALLBACK_TASK_TYPE,
......
......@@ -119,6 +119,7 @@ namespace internal {
V(WASM_DEBUG_INFO_TYPE) \
V(WASM_EXCEPTION_TAG_TYPE) \
V(WASM_EXPORTED_FUNCTION_DATA_TYPE) \
V(WASM_JS_FUNCTION_DATA_TYPE) \
\
V(CALLABLE_TASK_TYPE) \
V(CALLBACK_TASK_TYPE) \
......@@ -342,6 +343,7 @@ namespace internal {
V(_, WASM_EXCEPTION_TAG_TYPE, WasmExceptionTag, wasm_exception_tag) \
V(_, WASM_EXPORTED_FUNCTION_DATA_TYPE, WasmExportedFunctionData, \
wasm_exported_function_data) \
V(_, WASM_JS_FUNCTION_DATA_TYPE, WasmJSFunctionData, wasm_js_function_data) \
V(_, CALLABLE_TASK_TYPE, CallableTask, callable_task) \
V(_, CALLBACK_TASK_TYPE, CallbackTask, callback_task) \
V(_, PROMISE_FULFILL_REACTION_JOB_TASK_TYPE, PromiseFulfillReactionJobTask, \
......
......@@ -4919,6 +4919,8 @@ Code SharedFunctionInfo::GetCode() const {
DCHECK(code.IsCode());
DCHECK(code.is_interpreter_trampoline_builtin());
return code;
} else if (data.IsWasmJSFunctionData()) {
return wasm_js_function_data().wrapper_code();
} else if (data.IsWasmCapiFunctionData()) {
return wasm_capi_function_data().wrapper_code();
}
......@@ -4931,6 +4933,11 @@ WasmExportedFunctionData SharedFunctionInfo::wasm_exported_function_data()
return WasmExportedFunctionData::cast(function_data());
}
WasmJSFunctionData SharedFunctionInfo::wasm_js_function_data() const {
DCHECK(HasWasmJSFunctionData());
return WasmJSFunctionData::cast(function_data());
}
WasmCapiFunctionData SharedFunctionInfo::wasm_capi_function_data() const {
DCHECK(HasWasmCapiFunctionData());
return WasmCapiFunctionData::cast(function_data());
......
......@@ -663,6 +663,10 @@ bool SharedFunctionInfo::HasWasmExportedFunctionData() const {
return function_data().IsWasmExportedFunctionData();
}
bool SharedFunctionInfo::HasWasmJSFunctionData() const {
return function_data().IsWasmJSFunctionData();
}
bool SharedFunctionInfo::HasWasmCapiFunctionData() const {
return function_data().IsWasmCapiFunctionData();
}
......
......@@ -34,6 +34,7 @@ class DebugInfo;
class IsCompiledScope;
class WasmCapiFunctionData;
class WasmExportedFunctionData;
class WasmJSFunctionData;
// Data collected by the pre-parser storing information about scopes and inner
// functions.
......@@ -368,6 +369,8 @@ class SharedFunctionInfo : public HeapObject {
inline bool HasUncompiledDataWithoutPreparseData() const;
inline bool HasWasmExportedFunctionData() const;
WasmExportedFunctionData wasm_exported_function_data() const;
inline bool HasWasmJSFunctionData() const;
WasmJSFunctionData wasm_js_function_data() const;
inline bool HasWasmCapiFunctionData() const;
WasmCapiFunctionData wasm_capi_function_data() const;
......
......@@ -1466,8 +1466,12 @@ void WebAssemblyFunction(const v8::FunctionCallbackInfo<v8::Value>& args) {
return;
}
// TODO(7742): Implement ability to construct.
UNIMPLEMENTED();
i::wasm::FunctionSig* sig = builder.Build();
i::Handle<i::JSReceiver> callable =
Utils::OpenHandle(*args[1].As<Function>());
i::Handle<i::JSFunction> result =
i::WasmJSFunction::New(i_isolate, sig, callable);
args.GetReturnValue().Set(Utils::ToLocal(result));
}
constexpr const char* kName_WasmGlobalObject = "WebAssembly.Global";
......
......@@ -308,6 +308,17 @@ SMI_ACCESSORS(WasmExportedFunctionData, jump_table_offset,
kJumpTableOffsetOffset)
SMI_ACCESSORS(WasmExportedFunctionData, function_index, kFunctionIndexOffset)
// WasmJSFunction
WasmJSFunction::WasmJSFunction(Address ptr) : JSFunction(ptr) {
SLOW_DCHECK(IsWasmJSFunction(*this));
}
CAST_ACCESSOR(WasmJSFunction)
// WasmJSFunctionData
OBJECT_CONSTRUCTORS_IMPL(WasmJSFunctionData, Struct)
CAST_ACCESSOR(WasmJSFunctionData)
ACCESSORS(WasmJSFunctionData, wrapper_code, Code, kWrapperCodeOffset)
// WasmCapiFunction
WasmCapiFunction::WasmCapiFunction(Address ptr) : JSFunction(ptr) {
SLOW_DCHECK(IsWasmCapiFunction(*this));
......
......@@ -2133,6 +2133,33 @@ wasm::FunctionSig* WasmExportedFunction::sig() {
return instance().module()->functions[function_index()].sig;
}
// static
bool WasmJSFunction::IsWasmJSFunction(Object object) {
if (!object.IsJSFunction()) return false;
JSFunction js_function = JSFunction::cast(object);
return js_function.shared().HasWasmJSFunctionData();
}
Handle<WasmJSFunction> WasmJSFunction::New(Isolate* isolate,
wasm::FunctionSig* sig,
Handle<JSReceiver> callable) {
Handle<WasmJSFunctionData> function_data =
Handle<WasmJSFunctionData>::cast(isolate->factory()->NewStruct(
WASM_JS_FUNCTION_DATA_TYPE, AllocationType::kOld));
// TODO(7742): Make this callable by using a proper wrapper code.
function_data->set_wrapper_code(
isolate->builtins()->builtin(Builtins::kIllegal));
Handle<String> name = isolate->factory()->Function_string();
if (callable->IsJSFunction()) {
name = JSFunction::GetName(Handle<JSFunction>::cast(callable));
}
Handle<Map> function_map = isolate->wasm_exported_function_map();
NewFunctionArgs args =
NewFunctionArgs::ForWasm(name, function_data, function_map);
Handle<JSFunction> js_function = isolate->factory()->NewFunction(args);
return Handle<WasmJSFunction>::cast(js_function);
}
Address WasmCapiFunction::GetHostCallTarget() const {
return shared().wasm_capi_function_data().call_target();
}
......
......@@ -652,6 +652,7 @@ class WasmExceptionPackage : public JSReceiver {
};
// A Wasm function that is wrapped and exported to JavaScript.
// Representation of WebAssembly.Function JavaScript-level object.
class WasmExportedFunction : public JSFunction {
public:
WasmInstanceObject instance();
......@@ -671,6 +672,19 @@ class WasmExportedFunction : public JSFunction {
OBJECT_CONSTRUCTORS(WasmExportedFunction, JSFunction);
};
// A Wasm function that was created by wrapping a JavaScript callable.
// Representation of WebAssembly.Function JavaScript-level object.
class WasmJSFunction : public JSFunction {
public:
static bool IsWasmJSFunction(Object object);
static Handle<WasmJSFunction> New(Isolate* isolate, wasm::FunctionSig* sig,
Handle<JSReceiver> callable);
DECL_CAST(WasmJSFunction)
OBJECT_CONSTRUCTORS(WasmJSFunction, JSFunction);
};
// An external function exposed to Wasm via the C/C++ API.
class WasmCapiFunction : public JSFunction {
public:
......@@ -735,6 +749,26 @@ class WasmExportedFunctionData : public Struct {
OBJECT_CONSTRUCTORS(WasmExportedFunctionData, Struct);
};
// Information for a WasmJSFunction which is referenced as the function data of
// the SharedFunctionInfo underlying the function. For details please see the
// {SharedFunctionInfo::HasWasmJSFunctionData} predicate.
class WasmJSFunctionData : public Struct {
public:
DECL_ACCESSORS(wrapper_code, Code)
DECL_CAST(WasmJSFunctionData)
// Dispatched behavior.
DECL_PRINTER(WasmJSFunctionData)
DECL_VERIFIER(WasmJSFunctionData)
// Layout description.
DEFINE_FIELD_OFFSET_CONSTANTS(HeapObject::kHeaderSize,
TORQUE_GENERATED_WASM_JSFUNCTION_DATA_FIELDS)
OBJECT_CONSTRUCTORS(WasmJSFunctionData, Struct);
};
class WasmDebugInfo : public Struct {
public:
NEVER_READ_ONLY_SPACE
......
......@@ -197,9 +197,25 @@ load('test/mjsunit/wasm/wasm-module-builder.js');
assertThrows(
() => new WebAssembly.Function({parameters:[], results:[]}, {}), TypeError,
/Argument 1 must be a function/);
assertDoesNotThrow(
() => new WebAssembly.Function({parameters:[], results:[]}, _ => 0));
})();
(function TestFunctionExportedFunctions() {
(function TestFunctionConstructedFunction() {
let fun = new WebAssembly.Function({parameters:[], results:[]}, _ => 0);
assertTrue(fun instanceof WebAssembly.Function);
assertTrue(fun instanceof Function);
assertTrue(fun instanceof Object);
assertSame(fun.__proto__, WebAssembly.Function.prototype);
assertSame(fun.__proto__.__proto__, Function.prototype);
assertSame(fun.__proto__.__proto__.__proto__, Object.prototype);
assertSame(fun.constructor, WebAssembly.Function);
assertEquals(typeof fun, 'function');
// TODO(7742): Enable once it is callable.
// assertDoesNotThrow(() => fun());
})();
(function TestFunctionExportedFunction() {
let builder = new WasmModuleBuilder();
builder.addFunction("fun", kSig_v_v).addBody([]).exportFunc();
let instance = builder.instantiate();
......
This diff is collapsed.
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