Commit 73a27ef1 authored by Jakob Kummerow's avatar Jakob Kummerow Committed by Commit Bot

[wasm-gc] Create struct maps on instantiation

and avoid runtime calls for struct allocation. We can load the
map from the instance and do the allocation in a CSA builtin.

Bug: v8:7748
Change-Id: I76dfcb6c28800d69046b3d7381d3b8ba774fbf09
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2169099
Commit-Queue: Jakob Kummerow <jkummerow@chromium.org>
Reviewed-by: 's avatarAndreas Haas <ahaas@chromium.org>
Cr-Commit-Position: refs/heads/master@{#67617}
parent d6a02c02
...@@ -842,6 +842,7 @@ namespace internal { ...@@ -842,6 +842,7 @@ namespace internal {
TFC(WasmFloat32ToNumber, WasmFloat32ToNumber) \ TFC(WasmFloat32ToNumber, WasmFloat32ToNumber) \
TFC(WasmFloat64ToNumber, WasmFloat64ToNumber) \ TFC(WasmFloat64ToNumber, WasmFloat64ToNumber) \
TFS(WasmAllocateJSArray, kArraySize) \ TFS(WasmAllocateJSArray, kArraySize) \
TFS(WasmAllocateStruct, kMapIndex) \
TFC(WasmAtomicNotify, WasmAtomicNotify) \ TFC(WasmAtomicNotify, WasmAtomicNotify) \
TFS(WasmGetOwnProperty, kObject, kUniqueName) \ TFS(WasmGetOwnProperty, kObject, kUniqueName) \
TFC(WasmI32AtomicWait32, WasmI32AtomicWait32) \ TFC(WasmI32AtomicWait32, WasmI32AtomicWait32) \
......
...@@ -351,6 +351,19 @@ TF_BUILTIN(WasmTableCopy, WasmBuiltinsAssembler) { ...@@ -351,6 +351,19 @@ TF_BUILTIN(WasmTableCopy, WasmBuiltinsAssembler) {
src_table, dst, src, size); src_table, dst, src, size);
} }
TF_BUILTIN(WasmAllocateStruct, WasmBuiltinsAssembler) {
TNode<WasmInstanceObject> instance = LoadInstanceFromFrame();
TNode<Smi> map_index = CAST(Parameter(Descriptor::kMapIndex));
TNode<FixedArray> maps_list = LoadObjectField<FixedArray>(
instance, WasmInstanceObject::kManagedObjectMapsOffset);
TNode<Map> map = CAST(LoadFixedArrayElement(maps_list, map_index));
TNode<IntPtrT> instance_size =
TimesTaggedSize(LoadMapInstanceSizeInWords(map));
TNode<WasmStruct> result = UncheckedCast<WasmStruct>(Allocate(instance_size));
StoreMap(result, map);
Return(result);
}
#define DECLARE_THROW_RUNTIME_FN(name) \ #define DECLARE_THROW_RUNTIME_FN(name) \
TF_BUILTIN(ThrowWasm##name, WasmBuiltinsAssembler) { \ TF_BUILTIN(ThrowWasm##name, WasmBuiltinsAssembler) { \
TNode<WasmInstanceObject> instance = LoadInstanceFromFrame(); \ TNode<WasmInstanceObject> instance = LoadInstanceFromFrame(); \
......
...@@ -5049,12 +5049,24 @@ Node* StoreStructFieldUnchecked(MachineGraph* graph, WasmGraphAssembler* gasm, ...@@ -5049,12 +5049,24 @@ Node* StoreStructFieldUnchecked(MachineGraph* graph, WasmGraphAssembler* gasm,
Node* WasmGraphBuilder::StructNew(uint32_t struct_index, Node* WasmGraphBuilder::StructNew(uint32_t struct_index,
const wasm::StructType* type, const wasm::StructType* type,
Vector<Node*> fields) { Vector<Node*> fields) {
Node* runtime_args[] = { // This logic is duplicated from module-instantiate.cc.
graph()->NewNode(mcgraph()->common()->NumberConstant(struct_index))}; // TODO(jkummerow): Find a nicer solution.
// TODO(7748): Make this more efficient: ideally an inline allocation, int map_index = 0;
// or at least go through a builtin to save code size. const std::vector<uint8_t>& type_kinds = env_->module->type_kinds;
Node* s = BuildCallToRuntime(Runtime::kWasmStructNew, runtime_args, for (uint32_t i = 0; i < struct_index; i++) {
arraysize(runtime_args)); if (type_kinds[i] == wasm::kWasmStructTypeCode) map_index++;
}
CallDescriptor* call_descriptor =
GetBuiltinCallDescriptor<WasmAllocateStructDescriptor>(
this, StubCallMode::kCallBuiltinPointer);
Node* call_target = graph()->NewNode(
mcgraph()->common()->NumberConstant(Builtins::kWasmAllocateStruct));
Node* native_context =
LOAD_INSTANCE_FIELD(NativeContext, MachineType::TaggedPointer());
Node* s = gasm_->Call(call_descriptor, call_target,
gasm_->Int32Constant(map_index), native_context);
for (uint32_t i = 0; i < type->field_count(); i++) { for (uint32_t i = 0; i < type->field_count(); i++) {
StoreStructFieldUnchecked(mcgraph(), gasm_.get(), s, type, i, fields[i]); StoreStructFieldUnchecked(mcgraph(), gasm_.get(), s, type, i, fields[i]);
} }
......
...@@ -294,22 +294,6 @@ RUNTIME_FUNCTION(Runtime_WasmRefFunc) { ...@@ -294,22 +294,6 @@ RUNTIME_FUNCTION(Runtime_WasmRefFunc) {
return *function; return *function;
} }
RUNTIME_FUNCTION(Runtime_WasmStructNew) {
ClearThreadInWasmScope flag_scope;
HandleScope scope(isolate);
DCHECK_EQ(1, args.length());
Handle<WasmInstanceObject> instance =
handle(GetWasmInstanceOnStackTop(isolate), isolate);
DCHECK(isolate->context().is_null());
isolate->set_context(instance->native_context());
CONVERT_UINT32_ARG_CHECKED(struct_index, 0);
Handle<Map> map =
WasmInstanceObject::GetOrCreateStructMap(isolate, instance, struct_index);
Handle<Object> obj = isolate->factory()->NewWasmStruct(map);
return *obj;
}
RUNTIME_FUNCTION(Runtime_WasmFunctionTableGet) { RUNTIME_FUNCTION(Runtime_WasmFunctionTableGet) {
ClearThreadInWasmScope flag_scope; ClearThreadInWasmScope flag_scope;
HandleScope scope(isolate); HandleScope scope(isolate);
......
...@@ -552,27 +552,26 @@ namespace internal { ...@@ -552,27 +552,26 @@ namespace internal {
F(TypedArraySet, 2, 1) \ F(TypedArraySet, 2, 1) \
F(TypedArraySortFast, 1, 1) F(TypedArraySortFast, 1, 1)
#define FOR_EACH_INTRINSIC_WASM(F, I) \ #define FOR_EACH_INTRINSIC_WASM(F, I) \
F(ThrowWasmError, 1, 1) \ F(ThrowWasmError, 1, 1) \
F(ThrowWasmStackOverflow, 0, 1) \ F(ThrowWasmStackOverflow, 0, 1) \
F(WasmI32AtomicWait, 4, 1) \ F(WasmI32AtomicWait, 4, 1) \
F(WasmI64AtomicWait, 5, 1) \ F(WasmI64AtomicWait, 5, 1) \
F(WasmAtomicNotify, 3, 1) \ F(WasmAtomicNotify, 3, 1) \
F(WasmMemoryGrow, 2, 1) \ F(WasmMemoryGrow, 2, 1) \
F(WasmStackGuard, 0, 1) \ F(WasmStackGuard, 0, 1) \
F(WasmThrowCreate, 2, 1) \ F(WasmThrowCreate, 2, 1) \
F(WasmThrowTypeError, 0, 1) \ F(WasmThrowTypeError, 0, 1) \
F(WasmRefFunc, 1, 1) \ F(WasmRefFunc, 1, 1) \
F(WasmFunctionTableGet, 3, 1) \ F(WasmFunctionTableGet, 3, 1) \
F(WasmFunctionTableSet, 4, 1) \ F(WasmFunctionTableSet, 4, 1) \
F(WasmTableInit, 6, 1) \ F(WasmTableInit, 6, 1) \
F(WasmTableCopy, 6, 1) \ F(WasmTableCopy, 6, 1) \
F(WasmTableGrow, 3, 1) \ F(WasmTableGrow, 3, 1) \
F(WasmTableFill, 4, 1) \ F(WasmTableFill, 4, 1) \
F(WasmIsValidFuncRefValue, 1, 1) \ F(WasmIsValidFuncRefValue, 1, 1) \
F(WasmCompileLazy, 2, 1) \ F(WasmCompileLazy, 2, 1) \
F(WasmDebugBreak, 0, 1) \ F(WasmDebugBreak, 0, 1)
F(WasmStructNew, 1, 1)
#define FOR_EACH_INTRINSIC_WEAKREF(F, I) \ #define FOR_EACH_INTRINSIC_WEAKREF(F, I) \
F(ShrinkFinalizationRegistryUnregisterTokenMap, 1, 1) F(ShrinkFinalizationRegistryUnregisterTokenMap, 1, 1)
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include "src/tracing/trace-event.h" #include "src/tracing/trace-event.h"
#include "src/utils/utils.h" #include "src/utils/utils.h"
#include "src/wasm/module-compiler.h" #include "src/wasm/module-compiler.h"
#include "src/wasm/wasm-constants.h"
#include "src/wasm/wasm-external-refs.h" #include "src/wasm/wasm-external-refs.h"
#include "src/wasm/wasm-import-wrapper-cache.h" #include "src/wasm/wasm-import-wrapper-cache.h"
#include "src/wasm/wasm-module.h" #include "src/wasm/wasm-module.h"
...@@ -84,6 +85,24 @@ class CompileImportWrapperTask final : public CancelableTask { ...@@ -84,6 +85,24 @@ class CompileImportWrapperTask final : public CancelableTask {
WasmImportWrapperCache::ModificationScope* const cache_scope_; WasmImportWrapperCache::ModificationScope* const cache_scope_;
}; };
Handle<Map> CreateStructMap(Isolate* isolate, const WasmModule* module,
int struct_index) {
const wasm::StructType* type = module->struct_type(struct_index);
int inobject_properties = 0;
DCHECK_LE(type->total_fields_size(), kMaxInt - WasmStruct::kHeaderSize);
int instance_size =
WasmStruct::kHeaderSize + static_cast<int>(type->total_fields_size());
InstanceType instance_type = WASM_STRUCT_TYPE;
// TODO(jkummerow): If NO_ELEMENTS were supported, we could use that here.
ElementsKind elements_kind = TERMINAL_FAST_ELEMENTS_KIND;
Handle<Foreign> type_info =
isolate->factory()->NewForeign(reinterpret_cast<Address>(type));
Handle<Map> map = isolate->factory()->NewMap(
instance_type, instance_size, elements_kind, inobject_properties);
map->set_constructor_or_backpointer(*type_info);
return map;
}
} // namespace } // namespace
// A helper class to simplify instantiating a module from a module object. // A helper class to simplify instantiating a module from a module object.
...@@ -533,6 +552,27 @@ MaybeHandle<WasmInstanceObject> InstanceBuilder::Build() { ...@@ -533,6 +552,27 @@ MaybeHandle<WasmInstanceObject> InstanceBuilder::Build() {
if (thrower_->error()) return {}; if (thrower_->error()) return {};
} }
//--------------------------------------------------------------------------
// Create maps for managed objects (GC proposal).
//--------------------------------------------------------------------------
if (enabled_.has_gc()) {
int count = 0;
// TODO(7748): Add array support to both loops.
for (uint8_t type_kind : module_->type_kinds) {
if (type_kind == kWasmStructTypeCode) count++;
}
Handle<FixedArray> maps =
isolate_->factory()->NewUninitializedFixedArray(count);
for (int i = 0; i < static_cast<int>(module_->type_kinds.size()); i++) {
int index = 0;
if (module_->type_kinds[i] == kWasmStructTypeCode) {
Handle<Map> map = CreateStructMap(isolate_, module_, i);
maps->set(index++, *map);
}
}
instance->set_managed_object_maps(*maps);
}
//-------------------------------------------------------------------------- //--------------------------------------------------------------------------
// Create a wrapper for the start function. // Create a wrapper for the start function.
//-------------------------------------------------------------------------- //--------------------------------------------------------------------------
......
...@@ -266,6 +266,8 @@ OPTIONAL_ACCESSORS(WasmInstanceObject, exceptions_table, FixedArray, ...@@ -266,6 +266,8 @@ OPTIONAL_ACCESSORS(WasmInstanceObject, exceptions_table, FixedArray,
kExceptionsTableOffset) kExceptionsTableOffset)
OPTIONAL_ACCESSORS(WasmInstanceObject, wasm_external_functions, FixedArray, OPTIONAL_ACCESSORS(WasmInstanceObject, wasm_external_functions, FixedArray,
kWasmExternalFunctionsOffset) kWasmExternalFunctionsOffset)
ACCESSORS(WasmInstanceObject, managed_object_maps, FixedArray,
kManagedObjectMapsOffset)
void WasmInstanceObject::clear_padding() { void WasmInstanceObject::clear_padding() {
if (FIELD_SIZE(kOptionalPaddingOffset) != 0) { if (FIELD_SIZE(kOptionalPaddingOffset) != 0) {
......
...@@ -1230,6 +1230,7 @@ Handle<WasmInstanceObject> WasmInstanceObject::New( ...@@ -1230,6 +1230,7 @@ Handle<WasmInstanceObject> WasmInstanceObject::New(
module_object->native_module()->jump_table_start()); module_object->native_module()->jump_table_start());
instance->set_hook_on_function_call_address( instance->set_hook_on_function_call_address(
isolate->debug()->hook_on_function_call_address()); isolate->debug()->hook_on_function_call_address());
instance->set_managed_object_maps(*isolate->factory()->empty_fixed_array());
// Insert the new instance into the scripts weak list of instances. This list // Insert the new instance into the scripts weak list of instances. This list
// is used for breakpoints affecting all instances belonging to the script. // is used for breakpoints affecting all instances belonging to the script.
...@@ -1414,29 +1415,6 @@ WasmInstanceObject::GetOrCreateWasmExternalFunction( ...@@ -1414,29 +1415,6 @@ WasmInstanceObject::GetOrCreateWasmExternalFunction(
return result; return result;
} }
Handle<Map> WasmInstanceObject::GetOrCreateStructMap(
Isolate* isolate, Handle<WasmInstanceObject> instance, int struct_index) {
Handle<WasmModuleObject> module_object(instance->module_object(), isolate);
const WasmModule* module = module_object->module();
const wasm::StructType* type = module->struct_type(struct_index);
int inobject_properties = 0;
DCHECK_LE(type->total_fields_size(), kMaxInt - WasmStruct::kHeaderSize);
int instance_size =
WasmStruct::kHeaderSize + static_cast<int>(type->total_fields_size());
InstanceType instance_type = WASM_STRUCT_TYPE;
// TODO(jkummerow): If NO_ELEMENTS were supported, we could use that here.
ElementsKind elements_kind = TERMINAL_FAST_ELEMENTS_KIND;
Handle<Foreign> type_info =
isolate->factory()->NewForeign(reinterpret_cast<Address>(type));
Handle<Map> map = isolate->factory()->NewMap(
instance_type, instance_size, elements_kind, inobject_properties);
map->set_constructor_or_backpointer(*type_info);
// TODO(7748): Cache the map somewhere on the instance.
return map;
}
void WasmInstanceObject::SetWasmExternalFunction( void WasmInstanceObject::SetWasmExternalFunction(
Isolate* isolate, Handle<WasmInstanceObject> instance, int index, Isolate* isolate, Handle<WasmInstanceObject> instance, int index,
Handle<WasmExternalFunction> val) { Handle<WasmExternalFunction> val) {
......
...@@ -387,6 +387,7 @@ class WasmInstanceObject : public JSObject { ...@@ -387,6 +387,7 @@ class WasmInstanceObject : public JSObject {
DECL_OPTIONAL_ACCESSORS(managed_native_allocations, Foreign) DECL_OPTIONAL_ACCESSORS(managed_native_allocations, Foreign)
DECL_OPTIONAL_ACCESSORS(exceptions_table, FixedArray) DECL_OPTIONAL_ACCESSORS(exceptions_table, FixedArray)
DECL_OPTIONAL_ACCESSORS(wasm_external_functions, FixedArray) DECL_OPTIONAL_ACCESSORS(wasm_external_functions, FixedArray)
DECL_ACCESSORS(managed_object_maps, FixedArray)
DECL_PRIMITIVE_ACCESSORS(memory_start, byte*) DECL_PRIMITIVE_ACCESSORS(memory_start, byte*)
DECL_PRIMITIVE_ACCESSORS(memory_size, size_t) DECL_PRIMITIVE_ACCESSORS(memory_size, size_t)
DECL_PRIMITIVE_ACCESSORS(memory_mask, size_t) DECL_PRIMITIVE_ACCESSORS(memory_mask, size_t)
...@@ -446,6 +447,7 @@ class WasmInstanceObject : public JSObject { ...@@ -446,6 +447,7 @@ class WasmInstanceObject : public JSObject {
V(kManagedNativeAllocationsOffset, kTaggedSize) \ V(kManagedNativeAllocationsOffset, kTaggedSize) \
V(kExceptionsTableOffset, kTaggedSize) \ V(kExceptionsTableOffset, kTaggedSize) \
V(kWasmExternalFunctionsOffset, kTaggedSize) \ V(kWasmExternalFunctionsOffset, kTaggedSize) \
V(kManagedObjectMapsOffset, kTaggedSize) \
V(kRealStackLimitAddressOffset, kSystemPointerSize) \ V(kRealStackLimitAddressOffset, kSystemPointerSize) \
V(kDataSegmentStartsOffset, kSystemPointerSize) \ V(kDataSegmentStartsOffset, kSystemPointerSize) \
V(kDataSegmentSizesOffset, kSystemPointerSize) \ V(kDataSegmentSizesOffset, kSystemPointerSize) \
...@@ -483,7 +485,8 @@ class WasmInstanceObject : public JSObject { ...@@ -483,7 +485,8 @@ class WasmInstanceObject : public JSObject {
kIndirectFunctionTablesOffset, kIndirectFunctionTablesOffset,
kManagedNativeAllocationsOffset, kManagedNativeAllocationsOffset,
kExceptionsTableOffset, kExceptionsTableOffset,
kWasmExternalFunctionsOffset}; kWasmExternalFunctionsOffset,
kManagedObjectMapsOffset};
V8_EXPORT_PRIVATE const wasm::WasmModule* module(); V8_EXPORT_PRIVATE const wasm::WasmModule* module();
...@@ -575,10 +578,6 @@ class WasmInstanceObject : public JSObject { ...@@ -575,10 +578,6 @@ class WasmInstanceObject : public JSObject {
Handle<WasmInstanceObject>, Handle<WasmInstanceObject>,
uint32_t memory_index); uint32_t memory_index);
static Handle<Map> GetOrCreateStructMap(Isolate* isolate,
Handle<WasmInstanceObject> instance,
int struct_index);
OBJECT_CONSTRUCTORS(WasmInstanceObject, JSObject); OBJECT_CONSTRUCTORS(WasmInstanceObject, JSObject);
private: private:
......
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