LibWeb+LibWasm: Keep WebAssembly cache storage stable
These need to stay in place across rehashes so we can avoid querying their address on every collection cycle.
This commit is contained in:
parent
530c95fde5
commit
b3f3d68291
5 changed files with 17 additions and 18 deletions
|
|
@ -962,6 +962,11 @@ public:
|
||||||
return *m_heap;
|
return *m_heap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// For embedders that decide on a (shared) heap after constructing the machine. Must
|
||||||
|
// happen before any code runs.
|
||||||
|
bool has_heap() const { return m_heap != nullptr; }
|
||||||
|
void adopt_heap(GC::Heap&);
|
||||||
|
|
||||||
// Validate a module; permanently sets the module's validity status.
|
// Validate a module; permanently sets the module's validity status.
|
||||||
ErrorOr<void, ValidationError> validate(Module&, Optional<CompileCacheConfig> cache_config = {}, CompileToNative = CompileToNative::Yes);
|
ErrorOr<void, ValidationError> validate(Module&, Optional<CompileCacheConfig> cache_config = {}, CompileToNative = CompileToNative::Yes);
|
||||||
// Load and instantiate a module, and link it into this interpreter.
|
// Load and instantiate a module, and link it into this interpreter.
|
||||||
|
|
@ -1004,7 +1009,6 @@ private:
|
||||||
Optional<InstantiationError> allocate_all_initial_phase(Module const&, ModuleInstance&, Vector<ExternValue>&, Vector<Value>& global_values, Vector<Value>& table_initial_values, Vector<FunctionAddress>& own_functions);
|
Optional<InstantiationError> allocate_all_initial_phase(Module const&, ModuleInstance&, Vector<ExternValue>&, Vector<Value>& global_values, Vector<Value>& table_initial_values, Vector<FunctionAddress>& own_functions);
|
||||||
Optional<InstantiationError> allocate_all_final_phase(Module const&, ModuleInstance&, Vector<Vector<Reference>>& elements);
|
Optional<InstantiationError> allocate_all_final_phase(Module const&, ModuleInstance&, Vector<Vector<Reference>>& elements);
|
||||||
|
|
||||||
void adopt_heap(GC::Heap&);
|
|
||||||
void create_own_heap();
|
void create_own_heap();
|
||||||
|
|
||||||
class RootsProvider final : public GC::ConservativeRangeProvider {
|
class RootsProvider final : public GC::ConservativeRangeProvider {
|
||||||
|
|
|
||||||
|
|
@ -1638,8 +1638,7 @@ VALIDATE_INSTRUCTION(select_typed)
|
||||||
return Errors::invalid("select types"sv, "exactly one type"sv, required_types);
|
return Errors::invalid("select types"sv, "exactly one type"sv, required_types);
|
||||||
|
|
||||||
// https://webassembly.github.io/spec/core/valid/instructions.html#parametric-instructions
|
// https://webassembly.github.io/spec/core/valid/instructions.html#parametric-instructions
|
||||||
// select t: valid with [t t i32] -> [t] if the value type t is valid; both operands must
|
// select t: valid with [t t i32] -> [t] if the value type t is valid; both operands must match the annotated type.
|
||||||
// match the annotated type.
|
|
||||||
TRY(validate(required_types.first()));
|
TRY(validate(required_types.first()));
|
||||||
TRY(stack.take<ValueType::I32>());
|
TRY(stack.take<ValueType::I32>());
|
||||||
TRY(stack.take(required_types.first()));
|
TRY(stack.take(required_types.first()));
|
||||||
|
|
@ -1781,8 +1780,6 @@ VALIDATE_INSTRUCTION(table_copy)
|
||||||
auto lhs_table = TRY(validate(args.lhs));
|
auto lhs_table = TRY(validate(args.lhs));
|
||||||
auto rhs_table = TRY(validate(args.rhs));
|
auto rhs_table = TRY(validate(args.rhs));
|
||||||
|
|
||||||
// https://webassembly.github.io/spec/core/valid/instructions.html#table-instructions
|
|
||||||
// table.copy x y: the source table's reference type rt2 must match the destination's rt1.
|
|
||||||
if (!matches_reference_type(rhs_table.element_type(), lhs_table.element_type(), m_context.type_context()))
|
if (!matches_reference_type(rhs_table.element_type(), lhs_table.element_type(), m_context.type_context()))
|
||||||
return Errors::non_conforming_types("table.copy"sv, lhs_table.element_type(), rhs_table.element_type());
|
return Errors::non_conforming_types("table.copy"sv, lhs_table.element_type(), rhs_table.element_type());
|
||||||
|
|
||||||
|
|
@ -1806,9 +1803,6 @@ VALIDATE_INSTRUCTION(table_init)
|
||||||
|
|
||||||
auto& element_type = m_context.elements[args.element_index.value()];
|
auto& element_type = m_context.elements[args.element_index.value()];
|
||||||
|
|
||||||
// https://webassembly.github.io/spec/core/valid/instructions.html#table-instructions
|
|
||||||
// table.init x y: "The element segment C.elems[y] must match the reference type rt" of the
|
|
||||||
// table C.tables[x].
|
|
||||||
if (!matches_reference_type(element_type, table.element_type(), m_context.type_context()))
|
if (!matches_reference_type(element_type, table.element_type(), m_context.type_context()))
|
||||||
return Errors::non_conforming_types("table.init"sv, table.element_type(), element_type);
|
return Errors::non_conforming_types("table.init"sv, table.element_type(), element_type);
|
||||||
|
|
||||||
|
|
@ -2673,9 +2667,6 @@ VALIDATE_INSTRUCTION(call_indirect)
|
||||||
auto table = TRY(validate(args.table));
|
auto table = TRY(validate(args.table));
|
||||||
TRY(validate(args.type));
|
TRY(validate(args.type));
|
||||||
|
|
||||||
// https://webassembly.github.io/spec/core/valid/instructions.html#control-instructions
|
|
||||||
// call_indirect x y: "The table C.tables[x] must be of the form (at lim rt), and rt must
|
|
||||||
// match (ref null func)."
|
|
||||||
if (!matches_reference_type(table.element_type(), ValueType(ValueType::FunctionReference), m_context.type_context()))
|
if (!matches_reference_type(table.element_type(), ValueType(ValueType::FunctionReference), m_context.type_context()))
|
||||||
return Errors::invalid("table element type for call.indirect"sv, "a function reference"sv, table.element_type());
|
return Errors::invalid("table element type for call.indirect"sv, "a function reference"sv, table.element_type());
|
||||||
|
|
||||||
|
|
@ -2722,7 +2713,6 @@ VALIDATE_INSTRUCTION(return_call_indirect)
|
||||||
TRY(validate(args.type));
|
TRY(validate(args.type));
|
||||||
|
|
||||||
auto& table = m_context.tables[args.table.value()];
|
auto& table = m_context.tables[args.table.value()];
|
||||||
// See call_indirect: rt must match (ref null func).
|
|
||||||
if (!matches_reference_type(table.element_type(), ValueType(ValueType::FunctionReference), m_context.type_context()))
|
if (!matches_reference_type(table.element_type(), ValueType(ValueType::FunctionReference), m_context.type_context()))
|
||||||
return Errors::invalid("table element type for call.indirect"sv, "a function reference"sv, table.element_type());
|
return Errors::invalid("table element type for call.indirect"sv, "a function reference"sv, table.element_type());
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1573,8 +1573,6 @@ ParseResult<ElementSection::Element> ElementSection::Element::parse(ConstrainedS
|
||||||
|
|
||||||
// https://webassembly.github.io/spec/core/binary/modules.html#element-section
|
// https://webassembly.github.io/spec/core/binary/modules.html#element-section
|
||||||
// elemkind ::= 0x00 => (ref func)
|
// elemkind ::= 0x00 => (ref func)
|
||||||
// Segments listing function indices have the non-nullable type (ref func) (flags 0-3);
|
|
||||||
// the flag-4 expression shorthand has type funcref, i.e. (ref null func).
|
|
||||||
auto type = has_exprs ? ValueType(ValueType::FunctionReference) : ValueType(ValueType::FunctionReference, false);
|
auto type = has_exprs ? ValueType(ValueType::FunctionReference) : ValueType(ValueType::FunctionReference, false);
|
||||||
if (has_passive || has_explicit_index) {
|
if (has_passive || has_explicit_index) {
|
||||||
if (has_exprs) {
|
if (has_exprs) {
|
||||||
|
|
|
||||||
|
|
@ -55,15 +55,17 @@ static GC::Ref<WebIDL::Promise> compile_potential_webassembly_response(JS::VM&,
|
||||||
|
|
||||||
namespace Detail {
|
namespace Detail {
|
||||||
|
|
||||||
static GC::WeakHashMap<JS::Object, WebAssemblyCache>& caches()
|
// The caches hold AbstractMachines whose gc-roots providers keep pointers into them, so they
|
||||||
|
// live behind OwnPtrs and never move on rehash.
|
||||||
|
static GC::WeakHashMap<JS::Object, NonnullOwnPtr<WebAssemblyCache>>& caches()
|
||||||
{
|
{
|
||||||
static NeverDestroyed<GC::WeakHashMap<JS::Object, WebAssemblyCache>> caches;
|
static NeverDestroyed<GC::WeakHashMap<JS::Object, NonnullOwnPtr<WebAssemblyCache>>> caches;
|
||||||
return *caches;
|
return *caches;
|
||||||
}
|
}
|
||||||
|
|
||||||
WebAssemblyCache& get_cache(JS::Realm& realm)
|
WebAssemblyCache& get_cache(JS::Realm& realm)
|
||||||
{
|
{
|
||||||
return caches().ensure(realm.global_object());
|
return *caches().ensure(realm.global_object(), [] { return make<WebAssemblyCache>(); });
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -72,7 +74,7 @@ void visit_edges(JS::Object& object, JS::Cell::Visitor& visitor)
|
||||||
{
|
{
|
||||||
auto& global_object = HTML::relevant_global_object(object);
|
auto& global_object = HTML::relevant_global_object(object);
|
||||||
if (auto maybe_cache = Detail::caches().get(global_object); maybe_cache.has_value()) {
|
if (auto maybe_cache = Detail::caches().get(global_object); maybe_cache.has_value()) {
|
||||||
auto& cache = maybe_cache.value();
|
auto& cache = *maybe_cache.value();
|
||||||
visitor.visit(cache.function_instances());
|
visitor.visit(cache.function_instances());
|
||||||
visitor.visit(cache.imported_objects());
|
visitor.visit(cache.imported_objects());
|
||||||
visitor.visit(cache.extern_values());
|
visitor.visit(cache.extern_values());
|
||||||
|
|
|
||||||
|
|
@ -49,7 +49,12 @@ struct CompiledWebAssemblyModule : public RefCounted<CompiledWebAssemblyModule>
|
||||||
};
|
};
|
||||||
|
|
||||||
class WebAssemblyCache {
|
class WebAssemblyCache {
|
||||||
|
AK_MAKE_NONCOPYABLE(WebAssemblyCache);
|
||||||
|
AK_MAKE_NONMOVABLE(WebAssemblyCache);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
WebAssemblyCache() = default;
|
||||||
|
|
||||||
void add_compiled_module(NonnullRefPtr<CompiledWebAssemblyModule> module) { m_compiled_modules.append(module); }
|
void add_compiled_module(NonnullRefPtr<CompiledWebAssemblyModule> module) { m_compiled_modules.append(module); }
|
||||||
void add_function_instance(Wasm::FunctionAddress address, GC::Ptr<JS::NativeFunction> function) { m_function_instances.set(address, function); }
|
void add_function_instance(Wasm::FunctionAddress address, GC::Ptr<JS::NativeFunction> function) { m_function_instances.set(address, function); }
|
||||||
void add_imported_object(GC::Ptr<JS::Object> object) { m_imported_objects.set(object); }
|
void add_imported_object(GC::Ptr<JS::Object> object) { m_imported_objects.set(object); }
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue