Commit cbefd831 authored by Manos Koukoutos's avatar Manos Koukoutos Committed by V8 LUCI CQ

[wasm] Optimize function tables in instantiation

When initializing a table entry with null or a function constant, do not
go through EvaluateInitExpression. Remove the option to treat functions
lazily in EvaluateInitExpression/InitExprInterface.

Drive-by: Shrink indirect tables by removing redundant field.

Bug: chromium:1284557
Change-Id: I78a64becebf4b967b0a440d43855e163ec190b7f
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3383135Reviewed-by: 's avatarJakob Kummerow <jkummerow@chromium.org>
Commit-Queue: Manos Koukoutos <manoskouk@chromium.org>
Cr-Commit-Position: refs/heads/main@{#78608}
parent 9b9bb9d6
...@@ -58,15 +58,10 @@ void InitExprInterface::RefFunc(FullDecoder* decoder, uint32_t function_index, ...@@ -58,15 +58,10 @@ void InitExprInterface::RefFunc(FullDecoder* decoder, uint32_t function_index,
} }
ValueType type = ValueType::Ref(module_->functions[function_index].sig_index, ValueType type = ValueType::Ref(module_->functions[function_index].sig_index,
kNonNullable); kNonNullable);
if (function_strictness_ == kStrictFunctions) { Handle<WasmInternalFunction> internal =
Handle<WasmInternalFunction> internal = WasmInstanceObject::GetOrCreateWasmInternalFunction(isolate_, instance_,
WasmInstanceObject::GetOrCreateWasmInternalFunction(isolate_, instance_, function_index);
function_index); result->runtime_value = WasmValue(internal, type);
result->runtime_value = WasmValue(internal, type);
} else {
result->runtime_value =
WasmValue(handle(Smi::FromInt(function_index), isolate_), type);
}
} }
void InitExprInterface::GlobalGet(FullDecoder* decoder, Value* result, void InitExprInterface::GlobalGet(FullDecoder* decoder, Value* result,
......
...@@ -44,20 +44,12 @@ class InitExprInterface { ...@@ -44,20 +44,12 @@ class InitExprInterface {
using FullDecoder = using FullDecoder =
WasmFullDecoder<validate, InitExprInterface, decoding_mode>; WasmFullDecoder<validate, InitExprInterface, decoding_mode>;
// Controls how function references are computed. {kLazyFunctions} means that
// only the index of the function will be computed, as a Smi.
// {kStrictFunctions} means we fully compute the function reference through
// {WasmInstanceObject::GetOrCreateWasmInternalFunction}.
enum FunctionStrictness { kLazyFunctions, kStrictFunctions };
InitExprInterface(const WasmModule* module, Isolate* isolate, InitExprInterface(const WasmModule* module, Isolate* isolate,
Handle<WasmInstanceObject> instance, Handle<WasmInstanceObject> instance)
FunctionStrictness function_strictness)
: module_(module), : module_(module),
outer_module_(nullptr), outer_module_(nullptr),
isolate_(isolate), isolate_(isolate),
instance_(instance), instance_(instance) {
function_strictness_(function_strictness) {
DCHECK_NOT_NULL(isolate); DCHECK_NOT_NULL(isolate);
} }
...@@ -91,7 +83,6 @@ class InitExprInterface { ...@@ -91,7 +83,6 @@ class InitExprInterface {
WasmModule* outer_module_; WasmModule* outer_module_;
Isolate* isolate_; Isolate* isolate_;
Handle<WasmInstanceObject> instance_; Handle<WasmInstanceObject> instance_;
FunctionStrictness function_strictness_;
}; };
} // namespace wasm } // namespace wasm
......
...@@ -936,11 +936,9 @@ bool HasDefaultToNumberBehaviour(Isolate* isolate, ...@@ -936,11 +936,9 @@ bool HasDefaultToNumberBehaviour(Isolate* isolate,
return true; return true;
} }
WasmValue EvaluateInitExpression( V8_INLINE WasmValue
Zone* zone, ConstantExpression expr, ValueType expected, Isolate* isolate, EvaluateInitExpression(Zone* zone, ConstantExpression expr, ValueType expected,
Handle<WasmInstanceObject> instance, Isolate* isolate, Handle<WasmInstanceObject> instance) {
InitExprInterface::FunctionStrictness function_strictness =
InitExprInterface::kStrictFunctions) {
switch (expr.kind()) { switch (expr.kind()) {
case ConstantExpression::kEmpty: case ConstantExpression::kEmpty:
UNREACHABLE(); UNREACHABLE();
...@@ -952,11 +950,8 @@ WasmValue EvaluateInitExpression( ...@@ -952,11 +950,8 @@ WasmValue EvaluateInitExpression(
case ConstantExpression::kRefFunc: { case ConstantExpression::kRefFunc: {
uint32_t index = expr.index(); uint32_t index = expr.index();
Handle<Object> value = Handle<Object> value =
function_strictness == InitExprInterface::kLazyFunctions WasmInstanceObject::GetOrCreateWasmInternalFunction(isolate, instance,
? Handle<Object>(Smi::FromInt(index), isolate) index);
: Handle<Object>::cast(
WasmInstanceObject::GetOrCreateWasmInternalFunction(
isolate, instance, index));
return WasmValue(value, expected); return WasmValue(value, expected);
} }
case ConstantExpression::kWireBytesRef: { case ConstantExpression::kWireBytesRef: {
...@@ -977,8 +972,7 @@ WasmValue EvaluateInitExpression( ...@@ -977,8 +972,7 @@ WasmValue EvaluateInitExpression(
WasmFullDecoder<Decoder::kFullValidation, InitExprInterface, WasmFullDecoder<Decoder::kFullValidation, InitExprInterface,
kInitExpression> kInitExpression>
decoder(zone, instance->module(), WasmFeatures::All(), &detected, decoder(zone, instance->module(), WasmFeatures::All(), &detected,
body, instance->module(), isolate, instance, body, instance->module(), isolate, instance);
function_strictness);
decoder.DecodeFunctionBody(); decoder.DecodeFunctionBody();
...@@ -1943,37 +1937,34 @@ void InstanceBuilder::ProcessExports(Handle<WasmInstanceObject> instance) { ...@@ -1943,37 +1937,34 @@ void InstanceBuilder::ProcessExports(Handle<WasmInstanceObject> instance) {
} }
namespace { namespace {
void SetTableEntry(Isolate* isolate, Handle<WasmInstanceObject> instance, V8_INLINE void SetFunctionTablePlaceholder(Isolate* isolate,
Handle<WasmTableObject> table_object, uint32_t table_index, Handle<WasmInstanceObject> instance,
uint32_t entry_index, Handle<Object> entry) { Handle<WasmTableObject> table_object,
uint32_t entry_index,
uint32_t func_index) {
const WasmModule* module = instance->module(); const WasmModule* module = instance->module();
if (IsSubtypeOf(table_object->type(), kWasmFuncRef, module) && const WasmFunction* function = &module->functions[func_index];
entry->IsSmi()) { MaybeHandle<WasmInternalFunction> wasm_internal_function =
// We might get a Smi entry for a function table, representing the WasmInstanceObject::GetWasmInternalFunction(isolate, instance,
// function's index. In this case, we need to initialize the table with a func_index);
// placeholder if the function has not been initialized. if (wasm_internal_function.is_null()) {
const uint32_t func_index = entry->ToSmi().value(); // No JSFunction entry yet exists for this function. Create a {Tuple2}
const WasmFunction* function = &module->functions[func_index]; // holding the information to lazily allocate one.
WasmTableObject::SetFunctionTablePlaceholder(
MaybeHandle<WasmInternalFunction> wasm_internal_function = isolate, table_object, entry_index, instance, func_index);
WasmInstanceObject::GetWasmInternalFunction(isolate, instance,
func_index);
if (wasm_internal_function.is_null()) {
// No JSFunction entry yet exists for this function. Create a {Tuple2}
// holding the information to lazily allocate one.
WasmTableObject::SetFunctionTablePlaceholder(
isolate, table_object, entry_index, instance, func_index);
} else {
table_object->entries().set(entry_index,
*wasm_internal_function.ToHandleChecked());
}
WasmTableObject::UpdateDispatchTables(isolate, table_object, entry_index,
function->sig, instance, func_index);
} else { } else {
// In all other cases, simply call {WasmTableObject::Set}. table_object->entries().set(entry_index,
WasmTableObject::Set(isolate, table_object, entry_index, entry); *wasm_internal_function.ToHandleChecked());
} }
WasmTableObject::UpdateDispatchTables(isolate, table_object, entry_index,
function->sig, instance, func_index);
}
V8_INLINE void SetFunctionTableNullEntry(Isolate* isolate,
Handle<WasmTableObject> table_object,
uint32_t entry_index) {
table_object->entries().set(entry_index, *isolate->factory()->null_value());
WasmTableObject::ClearDispatchTables(isolate, table_object, entry_index);
} }
} // namespace } // namespace
...@@ -1985,22 +1976,33 @@ void InstanceBuilder::InitializeNonDefaultableTables( ...@@ -1985,22 +1976,33 @@ void InstanceBuilder::InitializeNonDefaultableTables(
if (!table.type.is_defaultable()) { if (!table.type.is_defaultable()) {
auto table_object = handle( auto table_object = handle(
WasmTableObject::cast(instance->tables().get(table_index)), isolate_); WasmTableObject::cast(instance->tables().get(table_index)), isolate_);
Handle<Object> value = bool is_function_table = IsSubtypeOf(table.type, kWasmFuncRef, module_);
EvaluateInitExpression(&init_expr_zone_, table.initial_value, if (is_function_table &&
table.type, isolate_, instance, table.initial_value.kind() == ConstantExpression::kRefFunc) {
IsSubtypeOf(table_object->type(), kWasmFuncRef, for (uint32_t entry_index = 0; entry_index < table.initial_size;
instance->module()) entry_index++) {
? InitExprInterface::kLazyFunctions SetFunctionTablePlaceholder(isolate_, instance, table_object,
: InitExprInterface::kStrictFunctions) entry_index, table.initial_value.index());
.to_ref(); }
for (uint32_t entry_index = 0; entry_index < table.initial_size; } else if (is_function_table &&
entry_index++) { table.initial_value.kind() == ConstantExpression::kRefNull) {
SetTableEntry(isolate_, instance, table_object, table_index, for (uint32_t entry_index = 0; entry_index < table.initial_size;
entry_index, value); entry_index++) {
SetFunctionTableNullEntry(isolate_, table_object, entry_index);
}
} else {
Handle<Object> value =
EvaluateInitExpression(&init_expr_zone_, table.initial_value,
table.type, isolate_, instance)
.to_ref();
for (uint32_t entry_index = 0; entry_index < table.initial_size;
entry_index++) {
WasmTableObject::Set(isolate_, table_object, entry_index, value);
}
} }
}
} }
} }
}
namespace { namespace {
bool LoadElemSegmentImpl(Zone* zone, Isolate* isolate, bool LoadElemSegmentImpl(Zone* zone, Isolate* isolate,
...@@ -2028,14 +2030,19 @@ bool LoadElemSegmentImpl(Zone* zone, Isolate* isolate, ...@@ -2028,14 +2030,19 @@ bool LoadElemSegmentImpl(Zone* zone, Isolate* isolate,
for (size_t i = 0; i < count; ++i) { for (size_t i = 0; i < count; ++i) {
ConstantExpression entry = elem_segment.entries[src + i]; ConstantExpression entry = elem_segment.entries[src + i];
int entry_index = static_cast<int>(dst + i); int entry_index = static_cast<int>(dst + i);
Handle<Object> value = if (is_function_table && entry.kind() == ConstantExpression::kRefFunc) {
EvaluateInitExpression( SetFunctionTablePlaceholder(isolate, instance, table_object, entry_index,
zone, entry, elem_segment.type, isolate, instance, entry.index());
is_function_table ? InitExprInterface::kLazyFunctions } else if (is_function_table &&
: InitExprInterface::kStrictFunctions) entry.kind() == ConstantExpression::kRefNull) {
.to_ref(); SetFunctionTableNullEntry(isolate, table_object, entry_index);
SetTableEntry(isolate, instance, table_object, table_index, entry_index, } else {
value); Handle<Object> value =
EvaluateInitExpression(zone, entry, elem_segment.type, isolate,
instance)
.to_ref();
WasmTableObject::Set(isolate, table_object, entry_index, value);
}
} }
return true; return true;
} }
......
...@@ -106,7 +106,6 @@ size_t EstimateNativeAllocationsSize(const WasmModule* module) { ...@@ -106,7 +106,6 @@ size_t EstimateNativeAllocationsSize(const WasmModule* module) {
enum DispatchTableElements : int { enum DispatchTableElements : int {
kDispatchTableInstanceOffset, kDispatchTableInstanceOffset,
kDispatchTableIndexOffset, kDispatchTableIndexOffset,
kDispatchTableFunctionTableOffset,
// Marker: // Marker:
kDispatchTableNumElements kDispatchTableNumElements
}; };
......
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