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

[wasm] Fast paths in EvaluateInitExpression

We add fast paths for the most common types of expressions in
{EvaluateInitExpression} to improve instantiation time. We fall back to
full expression decoding for less common operators, or for expressions
with operands.

Bug: chromium:1284557
Change-Id: I39a1816176974058b801cdad6eaaa6da156cea04
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3367627Reviewed-by: 's avatarClemens Backes <clemensb@chromium.org>
Commit-Queue: Manos Koukoutos <manoskouk@chromium.org>
Cr-Commit-Position: refs/heads/main@{#78497}
parent 8e9d8e17
......@@ -208,6 +208,15 @@ class Decoder {
return result;
}
// Reads a LEB128 variable-length signed 64-bit integer and advances {pc_}.
int64_t consume_i64v(const char* name = nullptr) {
uint32_t length = 0;
int64_t result =
read_leb<int64_t, kFullValidation, kTrace>(pc_, &length, name);
pc_ += length;
return result;
}
// Consume {size} bytes and send them to the bit bucket, advancing {pc_}.
void consume_bytes(uint32_t size, const char* name = "skip") {
// Only trace if the name is not null.
......
......@@ -246,6 +246,9 @@ HeapType read_heap_type(Decoder* decoder, const byte* pc,
}
}
HeapType consume_heap_type(Decoder* decoder, const WasmModule* module,
const WasmFeatures& enabled);
// Read a value type starting at address {pc} using {decoder}.
// No bytes are consumed.
// The length of the read value type is written in {length}.
......
......@@ -20,6 +20,17 @@ namespace v8 {
namespace internal {
namespace wasm {
namespace value_type_reader {
HeapType consume_heap_type(Decoder* decoder, const WasmModule* module,
const WasmFeatures& enabled) {
uint32_t length;
HeapType result = value_type_reader::read_heap_type<Decoder::kFullValidation>(
decoder, decoder->pc(), &length, module, enabled);
decoder->consume_bytes(length, "heap type");
return result;
}
} // namespace value_type_reader
bool DecodeLocalDecls(const WasmFeatures& enabled, BodyLocalDecls* decls,
const WasmModule* module, const byte* start,
const byte* end) {
......
......@@ -1793,12 +1793,8 @@ class ModuleDecoderImpl : public Decoder {
}
HeapType consume_super_type() {
uint32_t type_length;
HeapType result = value_type_reader::read_heap_type<kFullValidation>(
this, this->pc(), &type_length, module_.get(),
origin_ == kWasmOrigin ? enabled_features_ : WasmFeatures::None());
consume_bytes(type_length, "supertype");
return result;
return value_type_reader::consume_heap_type(this, module_.get(),
enabled_features_);
}
ValueType consume_storage_type() {
......
......@@ -942,12 +942,68 @@ WasmValue EvaluateInitExpression(
InitExprInterface::kStrictFunctions) {
base::Vector<const byte> module_bytes =
instance->module_object().native_module()->wire_bytes();
FunctionBody body(FunctionSig::Build(zone, {expected}, {}), init.offset(),
module_bytes.begin() + init.offset(),
module_bytes.begin() + init.end_offset());
const byte* start = module_bytes.begin() + init.offset();
const byte* end = module_bytes.begin() + init.end_offset();
// We implement a fast path for the most common expressions, so we do not have
// to allocate a WasmFullDecoder. It is possible that the first expression we
// encounter is only an operand of a more complex expression. Therefore we
// have to check we reached the end of the expression in each case.
switch (static_cast<WasmOpcode>(*start)) {
case kExprI32Const: {
Decoder decoder(start + 1, end);
int32_t value = decoder.consume_i32v();
if (*decoder.pc() == kExprEnd) return WasmValue(value);
break;
}
case kExprI64Const: {
Decoder decoder(start + 1, end);
int64_t value = decoder.consume_i64v();
if (*decoder.pc() == kExprEnd) return WasmValue(value);
break;
}
case kExprGlobalGet: {
Decoder decoder(start + 1, end);
uint32_t index = decoder.consume_u32v();
if (*decoder.pc() == kExprEnd) {
return WasmInstanceObject::GetGlobalValue(
instance, instance->module()->globals[index]);
}
break;
}
case kExprRefFunc: {
Decoder decoder(start + 1, end);
uint32_t index = decoder.consume_u32v();
if (*decoder.pc() == kExprEnd) {
Handle<Object> value =
function_strictness == InitExprInterface::kLazyFunctions
? Handle<Object>(Smi::FromInt(index), isolate)
: Handle<Object>::cast(
WasmInstanceObject::GetOrCreateWasmInternalFunction(
isolate, instance, index));
return WasmValue(value, expected);
}
break;
}
case kExprRefNull: {
Decoder decoder(start + 1, end);
value_type_reader::consume_heap_type(&decoder, instance->module(),
WasmFeatures::All());
if (*decoder.pc() == kExprEnd) {
return WasmValue(isolate->factory()->null_value(), expected);
}
break;
}
default:
break;
}
auto sig = FixedSizeSignature<ValueType>::Returns(expected);
FunctionBody body(&sig, init.offset(), start, end);
WasmFeatures detected;
// We use kFullValidation so we do not have to create another instance of
// WasmFullDecoder, which would cost us >50Kb binary code size.
// We use kFullValidation so we do not have to create another template
// instance of WasmFullDecoder, which would cost us >50Kb binary code size.
WasmFullDecoder<Decoder::kFullValidation, InitExprInterface, kInitExpression>
decoder(zone, instance->module(), WasmFeatures::All(), &detected, body,
instance->module(), isolate, instance, function_strictness);
......
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