Commit 4e71b6ba authored by Michael Starzinger's avatar Michael Starzinger Committed by Commit Bot

[wasm] Introduce WASM_EXCEPTION_OBJECT instance type.

This new instance type will be used for wrapper objects representing
exported exceptions. Currently the objects are empty and only serve as
an identity for exported exceptions. Eventually they will also need to
reference the signature underlying the exception to perform a signature
check upon import.

R=clemensh@chromium.org
TEST=mjsunit/wasm/exceptions-import
BUG=v8:8091

Change-Id: Ifdd561fc000090f4a985aeb45549fd7110849646
Reviewed-on: https://chromium-review.googlesource.com/1215166
Commit-Queue: Michael Starzinger <mstarzinger@chromium.org>
Reviewed-by: 's avatarClemens Hammacher <clemensh@chromium.org>
Cr-Commit-Position: refs/heads/master@{#55752}
parent c98b50fb
......@@ -245,6 +245,7 @@ class StringWrapper;
class SymbolWrapper;
class Undetectable;
class UniqueName;
class WasmExceptionObject;
class WasmExportedFunctionData;
class WasmGlobalObject;
class WasmMemoryObject;
......
......@@ -238,10 +238,11 @@ Type::bitset BitsetType::Lub(HeapObjectType const& type) {
case JS_WEAK_MAP_TYPE:
case JS_WEAK_SET_TYPE:
case JS_PROMISE_TYPE:
case WASM_MODULE_TYPE:
case WASM_EXCEPTION_TYPE:
case WASM_GLOBAL_TYPE:
case WASM_INSTANCE_TYPE:
case WASM_MEMORY_TYPE:
case WASM_MODULE_TYPE:
case WASM_TABLE_TYPE:
DCHECK(!type.is_callable());
DCHECK(!type.is_undetectable());
......
......@@ -329,6 +329,7 @@ enum ContextLookupFlags {
V(STRING_ITERATOR_MAP_INDEX, Map, string_iterator_map) \
V(SYMBOL_FUNCTION_INDEX, JSFunction, symbol_function) \
V(NATIVE_FUNCTION_MAP_INDEX, Map, native_function_map) \
V(WASM_EXCEPTION_CONSTRUCTOR_INDEX, JSFunction, wasm_exception_constructor) \
V(WASM_GLOBAL_CONSTRUCTOR_INDEX, JSFunction, wasm_global_constructor) \
V(WASM_INSTANCE_CONSTRUCTOR_INDEX, JSFunction, wasm_instance_constructor) \
V(WASM_MEMORY_CONSTRUCTOR_INDEX, JSFunction, wasm_memory_constructor) \
......
......@@ -735,6 +735,7 @@ ReturnType BodyDescriptorApply(InstanceType type, T1 p1, T2 p2, T3 p3, T4 p4) {
case JS_INTL_PLURAL_RULES_TYPE:
case JS_INTL_RELATIVE_TIME_FORMAT_TYPE:
#endif // V8_INTL_SUPPORT
case WASM_EXCEPTION_TYPE:
case WASM_GLOBAL_TYPE:
case WASM_MEMORY_TYPE:
case WASM_MODULE_TYPE:
......
......@@ -227,6 +227,7 @@ void HeapObject::HeapObjectVerify(Isolate* isolate) {
case JS_API_OBJECT_TYPE:
case JS_SPECIAL_API_OBJECT_TYPE:
case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
case WASM_EXCEPTION_TYPE:
case WASM_GLOBAL_TYPE:
case WASM_MEMORY_TYPE:
case WASM_TABLE_TYPE:
......
......@@ -207,6 +207,7 @@ namespace internal {
V(JS_DATA_VIEW_TYPE)
#define INSTANCE_TYPE_LIST_AFTER_INTL(V) \
V(WASM_EXCEPTION_TYPE) \
V(WASM_GLOBAL_TYPE) \
V(WASM_INSTANCE_TYPE) \
V(WASM_MEMORY_TYPE) \
......
......@@ -192,6 +192,7 @@ void HeapObject::HeapObjectPrint(std::ostream& os) { // NOLINT
case JS_ARGUMENTS_TYPE:
case JS_ERROR_TYPE:
// TODO(titzer): debug printing for more wasm objects
case WASM_EXCEPTION_TYPE:
case WASM_GLOBAL_TYPE:
case WASM_MEMORY_TYPE:
case WASM_TABLE_TYPE:
......
......@@ -3218,6 +3218,7 @@ VisitorId Map::GetVisitorId(Map* map) {
case JS_INTL_PLURAL_RULES_TYPE:
case JS_INTL_RELATIVE_TIME_FORMAT_TYPE:
#endif // V8_INTL_SUPPORT
case WASM_EXCEPTION_TYPE:
case WASM_GLOBAL_TYPE:
case WASM_MEMORY_TYPE:
case WASM_MODULE_TYPE:
......
......@@ -84,6 +84,7 @@
// - JSNumberFormat // If V8_INTL_SUPPORT enabled.
// - JSPluralRules // If V8_INTL_SUPPORT enabled.
// - JSRelativeTimeFormat // If V8_INTL_SUPPORT enabled.
// - WasmExceptionObject
// - WasmGlobalObject
// - WasmInstanceObject
// - WasmMemoryObject
......@@ -599,6 +600,7 @@ enum InstanceType : uint16_t {
JS_INTL_RELATIVE_TIME_FORMAT_TYPE,
#endif // V8_INTL_SUPPORT
WASM_EXCEPTION_TYPE,
WASM_GLOBAL_TYPE,
WASM_INSTANCE_TYPE,
WASM_MEMORY_TYPE,
......@@ -914,6 +916,7 @@ class ZoneForwardList;
V(UncompiledDataWithoutPreParsedScope) \
V(Undetectable) \
V(UniqueName) \
V(WasmExceptionObject) \
V(WasmGlobalObject) \
V(WasmInstanceObject) \
V(WasmMemoryObject) \
......@@ -1038,6 +1041,7 @@ class ZoneForwardList;
UNCOMPILED_DATA_WITHOUT_PRE_PARSED_SCOPE_TYPE) \
V(UncompiledDataWithPreParsedScope, \
UNCOMPILED_DATA_WITH_PRE_PARSED_SCOPE_TYPE) \
V(WasmExceptionObject, WASM_EXCEPTION_TYPE) \
V(WasmGlobalObject, WASM_GLOBAL_TYPE) \
V(WasmInstanceObject, WASM_INSTANCE_TYPE) \
V(WasmMemoryObject, WASM_MEMORY_TYPE) \
......
......@@ -245,6 +245,7 @@ class InstanceBuilder {
Handle<JSArrayBuffer> globals_;
std::vector<TableInstance> table_instances_;
std::vector<Handle<JSFunction>> js_wrappers_;
std::vector<Handle<WasmExceptionObject>> exception_wrappers_;
Handle<WasmExportedFunction> start_function_;
JSToWasmWrapperCache js_to_wasm_cache_;
std::vector<SanitizedImport> sanitized_imports_;
......@@ -1837,7 +1838,7 @@ bool InstanceBuilder::NeedsWrappers() const {
}
// Process the exports, creating wrappers for functions, tables, memories,
// and globals.
// globals, and exceptions.
void InstanceBuilder::ProcessExports(Handle<WasmInstanceObject> instance) {
Handle<FixedArray> export_wrappers(module_object_->export_wrappers(),
isolate_);
......@@ -1861,6 +1862,10 @@ void InstanceBuilder::ProcessExports(Handle<WasmInstanceObject> instance) {
}
}
// TODO(mstarzinger): The {exception_wrappers_} table is only needed until we
// have an exception table per instance which can then be used directly.
exception_wrappers_.resize(module_->exceptions.size());
Handle<JSObject> exports_object;
bool is_asm_js = false;
switch (module_->origin) {
......@@ -2017,9 +2022,14 @@ void InstanceBuilder::ProcessExports(Handle<WasmInstanceObject> instance) {
}
case kExternalException: {
const WasmException& exception = module_->exceptions[exp.index];
// TODO(mstarzinger): Only temporary placeholder, use wrapper object.
desc.set_value(handle(Smi::FromInt(exp.index), isolate_));
USE(exception);
Handle<WasmExceptionObject> wrapper = exception_wrappers_[exp.index];
if (wrapper.is_null()) {
wrapper = WasmExceptionObject::New(isolate_);
// TODO(mstarzinger): Store exception signature in wrapper.
USE(exception);
exception_wrappers_[exp.index] = wrapper;
}
desc.set_value(wrapper);
break;
}
default:
......
......@@ -1094,6 +1094,15 @@ void WebAssemblyGlobal(const v8::FunctionCallbackInfo<v8::Value>& args) {
args.GetReturnValue().Set(Utils::ToLocal(global_js_object));
}
// WebAssembly.Exception
void WebAssemblyException(const v8::FunctionCallbackInfo<v8::Value>& args) {
v8::Isolate* isolate = args.GetIsolate();
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
HandleScope scope(isolate);
ScheduledErrorThrower thrower(i_isolate, "WebAssembly.Excepion()");
thrower.TypeError("WebAssembly.Exception cannot be called");
}
constexpr const char* kName_WasmGlobalObject = "WebAssembly.Global";
constexpr const char* kName_WasmMemoryObject = "WebAssembly.Memory";
constexpr const char* kName_WasmInstanceObject = "WebAssembly.Instance";
......@@ -1579,11 +1588,11 @@ void WasmJs::Install(Isolate* isolate, bool exposed_on_global_object) {
JSObject::AddProperty(isolate, memory_proto, factory->to_string_tag_symbol(),
v8_str(isolate, "WebAssembly.Memory"), ro_attributes);
// Setup Global
// The context is not set up completely yet. That's why we cannot use
// {WasmFeaturesFromIsolate} and have to use {WasmFeaturesFromFlags} instead.
auto enabled_features = i::wasm::WasmFeaturesFromFlags();
// Setup Global
if (enabled_features.mut_global) {
Handle<JSFunction> global_constructor =
InstallFunc(isolate, webassembly, "Global", WebAssemblyGlobal, 1);
......@@ -1603,6 +1612,21 @@ void WasmJs::Install(Isolate* isolate, bool exposed_on_global_object) {
v8_str(isolate, "WebAssembly.Global"), ro_attributes);
}
// Setup Exception
if (enabled_features.eh) {
Handle<JSFunction> exception_constructor =
InstallFunc(isolate, webassembly, "Exception", WebAssemblyException, 1);
context->set_wasm_exception_constructor(*exception_constructor);
SetDummyInstanceTemplate(isolate, exception_constructor);
JSFunction::EnsureHasInitialMap(exception_constructor);
Handle<JSObject> exception_proto(
JSObject::cast(exception_constructor->instance_prototype()), isolate);
i::Handle<i::Map> exception_map = isolate->factory()->NewMap(
i::WASM_EXCEPTION_TYPE, WasmExceptionObject::kSize);
JSFunction::SetInitialMap(exception_constructor, exception_map,
exception_proto);
}
// Setup errors
attributes = static_cast<PropertyAttributes>(DONT_ENUM);
Handle<JSFunction> compile_error(
......
......@@ -22,6 +22,7 @@ namespace v8 {
namespace internal {
CAST_ACCESSOR(WasmDebugInfo)
CAST_ACCESSOR(WasmExceptionObject)
CAST_ACCESSOR(WasmExportedFunctionData)
CAST_ACCESSOR(WasmGlobalObject)
CAST_ACCESSOR(WasmInstanceObject)
......
......@@ -1343,6 +1343,17 @@ Address WasmInstanceObject::GetCallTarget(uint32_t func_index) {
return native_module->GetCallTargetForFunction(func_index);
}
// static
Handle<WasmExceptionObject> WasmExceptionObject::New(Isolate* isolate) {
Handle<JSFunction> exception_cons(
isolate->native_context()->wasm_exception_constructor(), isolate);
Handle<JSObject> exception_object =
isolate->factory()->NewJSObject(exception_cons, TENURED);
Handle<WasmExceptionObject> exception =
Handle<WasmExceptionObject>::cast(exception_object);
return exception;
}
bool WasmExportedFunction::IsWasmExportedFunction(Object* object) {
if (!object->IsJSFunction()) return false;
JSFunction* js_function = JSFunction::cast(object);
......
......@@ -472,6 +472,21 @@ class WasmInstanceObject : public JSObject {
typedef BodyDescriptor BodyDescriptorWeak;
};
// Representation of WebAssembly.Exception JavaScript-level object.
class WasmExceptionObject : public JSObject {
public:
DECL_CAST(WasmExceptionObject)
// Layout description.
#define WASM_EXCEPTION_OBJECT_FIELDS(V) V(kSize, 0)
DEFINE_FIELD_OFFSET_CONSTANTS(JSObject::kHeaderSize,
WASM_EXCEPTION_OBJECT_FIELDS)
#undef WASM_EXCEPTION_OBJECT_FIELDS
static Handle<WasmExceptionObject> New(Isolate* isolate);
};
// A WASM function that is wrapped and exported to JavaScript.
class WasmExportedFunction : public JSFunction {
public:
......
......@@ -15,10 +15,9 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
let instance = builder.instantiate();
assertTrue(Object.prototype.hasOwnProperty.call(instance.exports, 'ex'));
// TODO(mstarzinger): The following two expectations are only temporary until
// we actually have proper wrapper objects for exported exception types.
assertEquals("number", typeof instance.exports.ex);
assertEquals(except, instance.exports.ex);
assertEquals("object", typeof instance.exports.ex);
assertInstanceof(instance.exports.ex, WebAssembly.Exception);
assertSame(instance.exports.ex.constructor, WebAssembly.Exception);
})();
(function TestExportMultiple() {
......@@ -69,3 +68,14 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
let exports = WebAssembly.Module.exports(module);
assertArrayEquals([{ name: "ex", kind: "exception" }], exports);
})();
(function TestConstructorNonCallable() {
print(arguments.callee.name);
// TODO(wasm): Currently the constructor function of an exported exception is
// not callable. This can/will change once the proposal matures, at which
// point we should add a full exceptions-api.js test suite for the API and
// remove this test case from this file.
assertThrows(
() => WebAssembly.Exception(), TypeError,
/WebAssembly.Exception cannot be called/);
})();
......@@ -167,13 +167,14 @@ INSTANCE_TYPES = {
1089: "JS_INTL_NUMBER_FORMAT_TYPE",
1090: "JS_INTL_PLURAL_RULES_TYPE",
1091: "JS_INTL_RELATIVE_TIME_FORMAT_TYPE",
1092: "WASM_GLOBAL_TYPE",
1093: "WASM_INSTANCE_TYPE",
1094: "WASM_MEMORY_TYPE",
1095: "WASM_MODULE_TYPE",
1096: "WASM_TABLE_TYPE",
1097: "JS_BOUND_FUNCTION_TYPE",
1098: "JS_FUNCTION_TYPE",
1092: "WASM_EXCEPTION_TYPE",
1093: "WASM_GLOBAL_TYPE",
1094: "WASM_INSTANCE_TYPE",
1095: "WASM_MEMORY_TYPE",
1096: "WASM_MODULE_TYPE",
1097: "WASM_TABLE_TYPE",
1098: "JS_BOUND_FUNCTION_TYPE",
1099: "JS_FUNCTION_TYPE",
}
# List of known V8 maps.
......
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