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

[wasm][refactor] Clean up constant expressions

Changes:
- Rename InitExpression -> ConstantExpression in places which reference
  the ConstantExpression type.
- Move ConstantExpression to its own file, along with ValueOrError and
  EvaluateConstantExpression.

Change-Id: Ife572d783531216b6ea3d2626e4fbf4048463253
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3702798Reviewed-by: 's avatarClemens Backes <clemensb@chromium.org>
Commit-Queue: Manos Koukoutos <manoskouk@chromium.org>
Cr-Commit-Position: refs/heads/main@{#81204}
parent dc670a3c
......@@ -2480,6 +2480,10 @@ filegroup(
"src/wasm/code-space-access.cc",
"src/wasm/code-space-access.h",
"src/wasm/compilation-environment.h",
"src/wasm/constant-expression.cc",
"src/wasm/constant-expression.h",
"src/wasm/constant-expression-interface.cc",
"src/wasm/constant-expression-interface.h",
"src/wasm/decoder.h",
"src/wasm/function-body-decoder.cc",
"src/wasm/function-body-decoder.h",
......@@ -2488,8 +2492,6 @@ filegroup(
"src/wasm/function-compiler.h",
"src/wasm/graph-builder-interface.cc",
"src/wasm/graph-builder-interface.h",
"src/wasm/init-expr-interface.cc",
"src/wasm/init-expr-interface.h",
"src/wasm/jump-table-assembler.cc",
"src/wasm/jump-table-assembler.h",
"src/wasm/leb-helper.h",
......
......@@ -3579,12 +3579,13 @@ v8_header_set("v8_internal_headers") {
"src/wasm/canonical-types.h",
"src/wasm/code-space-access.h",
"src/wasm/compilation-environment.h",
"src/wasm/constant-expression-interface.h",
"src/wasm/constant-expression.h",
"src/wasm/decoder.h",
"src/wasm/function-body-decoder-impl.h",
"src/wasm/function-body-decoder.h",
"src/wasm/function-compiler.h",
"src/wasm/graph-builder-interface.h",
"src/wasm/init-expr-interface.h",
"src/wasm/jump-table-assembler.h",
"src/wasm/leb-helper.h",
"src/wasm/local-decl-encoder.h",
......@@ -4661,10 +4662,11 @@ v8_source_set("v8_base_without_compiler") {
"src/wasm/baseline/liftoff-compiler.cc",
"src/wasm/canonical-types.cc",
"src/wasm/code-space-access.cc",
"src/wasm/constant-expression-interface.cc",
"src/wasm/constant-expression.cc",
"src/wasm/function-body-decoder.cc",
"src/wasm/function-compiler.cc",
"src/wasm/graph-builder-interface.cc",
"src/wasm/init-expr-interface.cc",
"src/wasm/jump-table-assembler.cc",
"src/wasm/local-decl-encoder.cc",
"src/wasm/memory-protection-key.cc",
......
......@@ -1775,9 +1775,9 @@ Handle<Object> Factory::NewWasmArrayFromElementSegment(
AccountingAllocator allocator;
Zone zone(&allocator, ZONE_NAME);
for (uint32_t i = 0; i < length; i++) {
wasm::ValueOrError maybe_element =
wasm::EvaluateInitExpression(&zone, segment->entries[start_offset + i],
element_type, isolate(), instance);
wasm::ValueOrError maybe_element = wasm::EvaluateConstantExpression(
&zone, segment->entries[start_offset + i], element_type, isolate(),
instance);
if (wasm::is_error(maybe_element)) {
return handle(Smi::FromEnum(wasm::to_error(maybe_element)), isolate());
}
......
......@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/wasm/init-expr-interface.h"
#include "src/wasm/constant-expression-interface.h"
#include "src/execution/isolate.h"
#include "src/handles/handles-inl.h"
......@@ -17,36 +17,36 @@ namespace v8 {
namespace internal {
namespace wasm {
void InitExprInterface::I32Const(FullDecoder* decoder, Value* result,
int32_t value) {
void ConstantExpressionInterface::I32Const(FullDecoder* decoder, Value* result,
int32_t value) {
if (generate_value()) result->runtime_value = WasmValue(value);
}
void InitExprInterface::I64Const(FullDecoder* decoder, Value* result,
int64_t value) {
void ConstantExpressionInterface::I64Const(FullDecoder* decoder, Value* result,
int64_t value) {
if (generate_value()) result->runtime_value = WasmValue(value);
}
void InitExprInterface::F32Const(FullDecoder* decoder, Value* result,
float value) {
void ConstantExpressionInterface::F32Const(FullDecoder* decoder, Value* result,
float value) {
if (generate_value()) result->runtime_value = WasmValue(value);
}
void InitExprInterface::F64Const(FullDecoder* decoder, Value* result,
double value) {
void ConstantExpressionInterface::F64Const(FullDecoder* decoder, Value* result,
double value) {
if (generate_value()) result->runtime_value = WasmValue(value);
}
void InitExprInterface::S128Const(FullDecoder* decoder,
Simd128Immediate<validate>& imm,
Value* result) {
void ConstantExpressionInterface::S128Const(FullDecoder* decoder,
Simd128Immediate<validate>& imm,
Value* result) {
if (!generate_value()) return;
result->runtime_value = WasmValue(imm.value, kWasmS128);
}
void InitExprInterface::BinOp(FullDecoder* decoder, WasmOpcode opcode,
const Value& lhs, const Value& rhs,
Value* result) {
void ConstantExpressionInterface::BinOp(FullDecoder* decoder, WasmOpcode opcode,
const Value& lhs, const Value& rhs,
Value* result) {
if (!generate_value()) return;
switch (opcode) {
case kExprI32Add:
......@@ -78,14 +78,15 @@ void InitExprInterface::BinOp(FullDecoder* decoder, WasmOpcode opcode,
}
}
void InitExprInterface::RefNull(FullDecoder* decoder, ValueType type,
Value* result) {
void ConstantExpressionInterface::RefNull(FullDecoder* decoder, ValueType type,
Value* result) {
if (!generate_value()) return;
result->runtime_value = WasmValue(isolate_->factory()->null_value(), type);
}
void InitExprInterface::RefFunc(FullDecoder* decoder, uint32_t function_index,
Value* result) {
void ConstantExpressionInterface::RefFunc(FullDecoder* decoder,
uint32_t function_index,
Value* result) {
if (isolate_ == nullptr) {
outer_module_->functions[function_index].declared = true;
return;
......@@ -99,8 +100,9 @@ void InitExprInterface::RefFunc(FullDecoder* decoder, uint32_t function_index,
result->runtime_value = WasmValue(internal, type);
}
void InitExprInterface::GlobalGet(FullDecoder* decoder, Value* result,
const GlobalIndexImmediate<validate>& imm) {
void ConstantExpressionInterface::GlobalGet(
FullDecoder* decoder, Value* result,
const GlobalIndexImmediate<validate>& imm) {
if (!generate_value()) return;
const WasmGlobal& global = module_->globals[imm.index];
DCHECK(!global.mutability);
......@@ -117,7 +119,7 @@ void InitExprInterface::GlobalGet(FullDecoder* decoder, Value* result,
global.type);
}
void InitExprInterface::StructNewWithRtt(
void ConstantExpressionInterface::StructNewWithRtt(
FullDecoder* decoder, const StructIndexImmediate<validate>& imm,
const Value& rtt, const Value args[], Value* result) {
if (!generate_value()) return;
......@@ -132,9 +134,9 @@ void InitExprInterface::StructNewWithRtt(
ValueType::Ref(HeapType(imm.index), kNonNullable));
}
void InitExprInterface::StringConst(FullDecoder* decoder,
const StringConstImmediate<validate>& imm,
Value* result) {
void ConstantExpressionInterface::StringConst(
FullDecoder* decoder, const StringConstImmediate<validate>& imm,
Value* result) {
if (!generate_value()) return;
static_assert(base::IsInRange(kV8MaxWasmStringLiterals, 0, Smi::kMaxValue));
......@@ -178,7 +180,7 @@ WasmValue DefaultValueForType(ValueType type, Isolate* isolate) {
}
} // namespace
void InitExprInterface::StructNewDefault(
void ConstantExpressionInterface::StructNewDefault(
FullDecoder* decoder, const StructIndexImmediate<validate>& imm,
const Value& rtt, Value* result) {
if (!generate_value()) return;
......@@ -193,10 +195,9 @@ void InitExprInterface::StructNewDefault(
ValueType::Ref(HeapType(imm.index), kNonNullable));
}
void InitExprInterface::ArrayInit(FullDecoder* decoder,
const ArrayIndexImmediate<validate>& imm,
const base::Vector<Value>& elements,
const Value& rtt, Value* result) {
void ConstantExpressionInterface::ArrayInit(
FullDecoder* decoder, const ArrayIndexImmediate<validate>& imm,
const base::Vector<Value>& elements, const Value& rtt, Value* result) {
if (!generate_value()) return;
std::vector<WasmValue> element_values;
for (Value elem : elements) element_values.push_back(elem.runtime_value);
......@@ -207,7 +208,7 @@ void InitExprInterface::ArrayInit(FullDecoder* decoder,
ValueType::Ref(HeapType(imm.index), kNonNullable));
}
void InitExprInterface::ArrayInitFromSegment(
void ConstantExpressionInterface::ArrayInitFromSegment(
FullDecoder* decoder, const ArrayIndexImmediate<validate>& array_imm,
const IndexImmediate<validate>& segment_imm, const Value& offset_value,
const Value& length_value, const Value& rtt, Value* result) {
......@@ -267,16 +268,16 @@ void InitExprInterface::ArrayInitFromSegment(
}
}
void InitExprInterface::RttCanon(FullDecoder* decoder, uint32_t type_index,
Value* result) {
void ConstantExpressionInterface::RttCanon(FullDecoder* decoder,
uint32_t type_index, Value* result) {
if (!generate_value()) return;
result->runtime_value = WasmValue(
handle(instance_->managed_object_maps().get(type_index), isolate_),
ValueType::Rtt(type_index));
}
void InitExprInterface::DoReturn(FullDecoder* decoder,
uint32_t /*drop_values*/) {
void ConstantExpressionInterface::DoReturn(FullDecoder* decoder,
uint32_t /*drop_values*/) {
end_found_ = true;
// End decoding on "end".
decoder->set_end(decoder->pc() + 1);
......
......@@ -6,8 +6,8 @@
#error This header should only be included if WebAssembly is enabled.
#endif // !V8_ENABLE_WEBASSEMBLY
#ifndef V8_WASM_INIT_EXPR_INTERFACE_H_
#define V8_WASM_INIT_EXPR_INTERFACE_H_
#ifndef V8_WASM_CONSTANT_EXPRESSION_INTERFACE_H_
#define V8_WASM_CONSTANT_EXPRESSION_INTERFACE_H_
#include "src/wasm/decoder.h"
#include "src/wasm/function-body-decoder-impl.h"
......@@ -21,16 +21,16 @@ class JSArrayBuffer;
namespace wasm {
// An interface for WasmFullDecoder used to decode initializer expressions. This
// An interface for WasmFullDecoder used to decode constant expressions. This
// interface has two modes: only validation (when {isolate_ == nullptr}), which
// is used in module-decoder, and code-generation (when {isolate_ != nullptr}),
// which is used in module-instantiate. We merge two distinct functionalities
// in one class to reduce the number of WasmFullDecoder instantiations, and thus
// V8 binary code size.
class InitExprInterface {
class ConstantExpressionInterface {
public:
static constexpr Decoder::ValidateFlag validate = Decoder::kFullValidation;
static constexpr DecodingMode decoding_mode = kInitExpression;
static constexpr DecodingMode decoding_mode = kConstantExpression;
struct Value : public ValueBase<validate> {
WasmValue runtime_value;
......@@ -42,10 +42,10 @@ class InitExprInterface {
using Control = ControlBase<Value, validate>;
using FullDecoder =
WasmFullDecoder<validate, InitExprInterface, decoding_mode>;
WasmFullDecoder<validate, ConstantExpressionInterface, decoding_mode>;
InitExprInterface(const WasmModule* module, Isolate* isolate,
Handle<WasmInstanceObject> instance)
ConstantExpressionInterface(const WasmModule* module, Isolate* isolate,
Handle<WasmInstanceObject> instance)
: module_(module),
outer_module_(nullptr),
isolate_(isolate),
......@@ -53,7 +53,7 @@ class InitExprInterface {
DCHECK_NOT_NULL(isolate);
}
explicit InitExprInterface(WasmModule* outer_module)
explicit ConstantExpressionInterface(WasmModule* outer_module)
: module_(nullptr), outer_module_(outer_module), isolate_(nullptr) {}
#define EMPTY_INTERFACE_FUNCTION(name, ...) \
......@@ -100,4 +100,4 @@ class InitExprInterface {
} // namespace internal
} // namespace v8
#endif // V8_WASM_INIT_EXPR_INTERFACE_H_
#endif // V8_WASM_CONSTANT_EXPRESSION_INTERFACE_H_
// Copyright 2022 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/wasm/constant-expression.h"
#include "src/handles/handles.h"
#include "src/heap/factory-inl.h"
#include "src/heap/factory.h"
#include "src/objects/oddball.h"
#include "src/roots/roots.h"
#include "src/wasm/constant-expression-interface.h"
#include "src/wasm/function-body-decoder-impl.h"
#include "src/wasm/wasm-code-manager.h"
#include "src/wasm/wasm-module.h"
#include "src/wasm/wasm-objects.h"
#include "src/wasm/wasm-opcodes-inl.h"
namespace v8 {
namespace internal {
namespace wasm {
WireBytesRef ConstantExpression::wire_bytes_ref() const {
DCHECK_EQ(kind(), kWireBytesRef);
return WireBytesRef(OffsetField::decode(bit_field_),
LengthField::decode(bit_field_));
}
ValueOrError EvaluateConstantExpression(Zone* zone, ConstantExpression expr,
ValueType expected, Isolate* isolate,
Handle<WasmInstanceObject> instance) {
switch (expr.kind()) {
case ConstantExpression::kEmpty:
UNREACHABLE();
case ConstantExpression::kI32Const:
return WasmValue(expr.i32_value());
case ConstantExpression::kRefNull:
return WasmValue(isolate->factory()->null_value(),
ValueType::Ref(expr.repr(), kNullable));
case ConstantExpression::kRefFunc: {
uint32_t index = expr.index();
Handle<Object> value =
WasmInstanceObject::GetOrCreateWasmInternalFunction(isolate, instance,
index);
return WasmValue(value, expected);
}
case ConstantExpression::kWireBytesRef: {
WireBytesRef ref = expr.wire_bytes_ref();
base::Vector<const byte> module_bytes =
instance->module_object().native_module()->wire_bytes();
const byte* start = module_bytes.begin() + ref.offset();
const byte* end = module_bytes.begin() + ref.end_offset();
auto sig = FixedSizeSignature<ValueType>::Returns(expected);
FunctionBody body(&sig, ref.offset(), start, end);
WasmFeatures detected;
// 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, ConstantExpressionInterface,
kConstantExpression>
decoder(zone, instance->module(), WasmFeatures::All(), &detected,
body, instance->module(), isolate, instance);
decoder.DecodeFunctionBody();
return decoder.interface().has_error()
? ValueOrError(decoder.interface().error())
: ValueOrError(decoder.interface().computed_value());
}
}
}
} // namespace wasm
} // namespace internal
} // namespace v8
// Copyright 2022 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#if !V8_ENABLE_WEBASSEMBLY
#error This header should only be included if WebAssembly is enabled.
#endif // !V8_ENABLE_WEBASSEMBLY
#ifndef V8_WASM_CONSTANT_EXPRESSION_H_
#define V8_WASM_CONSTANT_EXPRESSION_H_
#include <stdint.h>
#include <variant>
#include "src/base/bit-field.h"
#include "src/wasm/value-type.h"
#include "src/wasm/wasm-value.h"
namespace v8 {
namespace internal {
enum class MessageTemplate;
class WasmInstanceObject;
namespace wasm {
class WireBytesRef;
// A representation of a constant expression. The most common expression types
// are hard-coded, while the rest are represented as a {WireBytesRef}.
class ConstantExpression {
public:
enum Kind {
kEmpty,
kI32Const,
kRefNull,
kRefFunc,
kWireBytesRef,
kLastKind = kWireBytesRef
};
union Value {
int32_t i32_value;
uint32_t index_or_offset;
HeapType::Representation repr;
};
ConstantExpression() : bit_field_(KindField::encode(kEmpty)) {}
static ConstantExpression I32Const(int32_t value) {
return ConstantExpression(ValueField::encode(value) |
KindField::encode(kI32Const));
}
static ConstantExpression RefFunc(uint32_t index) {
return ConstantExpression(ValueField::encode(index) |
KindField::encode(kRefFunc));
}
static ConstantExpression RefNull(HeapType::Representation repr) {
return ConstantExpression(ValueField::encode(repr) |
KindField::encode(kRefNull));
}
static ConstantExpression WireBytes(uint32_t offset, uint32_t length) {
return ConstantExpression(OffsetField::encode(offset) |
LengthField::encode(length) |
KindField::encode(kWireBytesRef));
}
Kind kind() const { return KindField::decode(bit_field_); }
bool is_set() const { return kind() != kEmpty; }
uint32_t index() const {
DCHECK_EQ(kind(), kRefFunc);
return ValueField::decode(bit_field_);
}
HeapType::Representation repr() const {
DCHECK_EQ(kind(), kRefNull);
return static_cast<HeapType::Representation>(
ValueField::decode(bit_field_));
}
int32_t i32_value() const {
DCHECK_EQ(kind(), kI32Const);
return ValueField::decode(bit_field_);
}
V8_EXPORT_PRIVATE WireBytesRef wire_bytes_ref() const;
private:
static constexpr int kValueBits = 32;
static constexpr int kLengthBits = 30;
static constexpr int kOffsetBits = 30;
static constexpr int kKindBits = 3;
// There are two possible combinations of fields: offset + length + kind if
// kind = kWireBytesRef, or value + kind for anything else.
using ValueField = base::BitField<uint32_t, 0, kValueBits, uint64_t>;
using OffsetField = base::BitField<uint32_t, 0, kOffsetBits, uint64_t>;
using LengthField = OffsetField::Next<uint32_t, kLengthBits>;
using KindField = LengthField::Next<Kind, kKindBits>;
// Make sure we reserve enough bits for a {WireBytesRef}'s length and offset.
static_assert(kV8MaxWasmModuleSize <= LengthField::kMax + 1);
static_assert(kV8MaxWasmModuleSize <= OffsetField::kMax + 1);
// Make sure kind fits in kKindBits.
static_assert(kLastKind <= KindField::kMax + 1);
explicit ConstantExpression(uint64_t bit_field) : bit_field_(bit_field) {}
uint64_t bit_field_;
};
// We want to keep {ConstantExpression} small to reduce memory usage during
// compilation/instantiation.
static_assert(sizeof(ConstantExpression) <= 8);
using ValueOrError = std::variant<WasmValue, MessageTemplate>;
V8_INLINE bool is_error(ValueOrError result) {
return std::holds_alternative<MessageTemplate>(result);
}
V8_INLINE MessageTemplate to_error(ValueOrError result) {
return std::get<MessageTemplate>(result);
}
V8_INLINE WasmValue to_value(ValueOrError result) {
return std::get<WasmValue>(result);
}
// Evaluates a constant expression.
// Returns a {WasmValue} if the evaluation succeeds, or an error as a
// {MessageTemplate} if it fails.
ValueOrError EvaluateConstantExpression(Zone* zone, ConstantExpression expr,
ValueType expected, Isolate* isolate,
Handle<WasmInstanceObject> instance);
} // namespace wasm
} // namespace internal
} // namespace v8
#endif // V8_WASM_CONSTANT_EXPRESSION_H_
......@@ -413,7 +413,7 @@ ValueType read_value_type(Decoder* decoder, const byte* pc,
}
} // namespace value_type_reader
enum DecodingMode { kFunctionBody, kInitExpression };
enum DecodingMode { kFunctionBody, kConstantExpression };
// Helpers for decoding different kinds of immediates which follow bytecodes.
template <Decoder::ValidateFlag validate>
......@@ -1362,7 +1362,7 @@ class WasmDecoder : public Decoder {
}
imm.global = &module_->globals[imm.index];
if (decoding_mode == kInitExpression) {
if (decoding_mode == kConstantExpression) {
if (!VALIDATE(!imm.global->mutability)) {
this->DecodeError(pc,
"mutable globals cannot be used in initializer "
......@@ -2750,7 +2750,7 @@ class WasmFullDecoder : public WasmDecoder<validate, decoding_mode> {
#define BUILD_SIMPLE_OPCODE(op, _, sig) \
DECODE(op) { \
if (decoding_mode == kInitExpression) { \
if (decoding_mode == kConstantExpression) { \
if (!VALIDATE(this->enabled_.has_extended_const())) { \
NonConstError(this, kExpr##op); \
return 0; \
......@@ -3690,13 +3690,13 @@ class WasmFullDecoder : public WasmDecoder<validate, decoding_mode> {
// Hence just list all implementations explicitly here, which also gives more
// freedom to use the same implementation for different opcodes.
#define DECODE_IMPL(opcode) DECODE_IMPL2(kExpr##opcode, opcode)
#define DECODE_IMPL2(opcode, name) \
if (idx == opcode) { \
if (decoding_mode == kInitExpression) { \
return &WasmFullDecoder::NonConstError; \
} else { \
return &WasmFullDecoder::Decode##name; \
} \
#define DECODE_IMPL2(opcode, name) \
if (idx == opcode) { \
if (decoding_mode == kConstantExpression) { \
return &WasmFullDecoder::NonConstError; \
} else { \
return &WasmFullDecoder::Decode##name; \
} \
}
#define DECODE_IMPL_CONST(opcode) DECODE_IMPL_CONST2(kExpr##opcode, opcode)
#define DECODE_IMPL_CONST2(opcode, name) \
......@@ -4078,7 +4078,7 @@ class WasmFullDecoder : public WasmDecoder<validate, decoding_mode> {
}
uint32_t DecodeSimdOpcode(WasmOpcode opcode, uint32_t opcode_length) {
if (decoding_mode == kInitExpression) {
if (decoding_mode == kConstantExpression) {
// Currently, only s128.const is allowed in initializer expressions.
if (opcode != kExprS128Const) {
this->DecodeError("opcode %s is not allowed in init. expressions",
......@@ -4232,7 +4232,7 @@ class WasmFullDecoder : public WasmDecoder<validate, decoding_mode> {
}
#define NON_CONST_ONLY \
if (decoding_mode == kInitExpression) { \
if (decoding_mode == kConstantExpression) { \
this->DecodeError("opcode %s is not allowed in init. expressions", \
this->SafeOpcodeNameAt(this->pc())); \
return 0; \
......@@ -5684,7 +5684,7 @@ class WasmFullDecoder : public WasmDecoder<validate, decoding_mode> {
}
void PushMergeValues(Control* c, Merge<Value>* merge) {
if (decoding_mode == kInitExpression) return;
if (decoding_mode == kConstantExpression) return;
DCHECK_EQ(c, &control_.back());
DCHECK(merge == &c->start_merge || merge == &c->end_merge);
DCHECK_LE(stack_ + c->stack_depth, stack_end_);
......@@ -5830,7 +5830,7 @@ class WasmFullDecoder : public WasmDecoder<validate, decoding_mode> {
uint32_t actual = stack_size() - control_.back().stack_depth;
// Here we have to check for !unreachable(), because we need to typecheck as
// if the current code is reachable even if it is spec-only reachable.
if (V8_LIKELY(decoding_mode == kInitExpression ||
if (V8_LIKELY(decoding_mode == kConstantExpression ||
!control_.back().unreachable())) {
if (V8_UNLIKELY(strict_count ? actual != drop_values + arity
: actual < drop_values + arity)) {
......
......@@ -14,9 +14,10 @@
#include "src/objects/objects-inl.h"
#include "src/utils/ostreams.h"
#include "src/wasm/canonical-types.h"
#include "src/wasm/constant-expression-interface.h"
#include "src/wasm/constant-expression.h"
#include "src/wasm/decoder.h"
#include "src/wasm/function-body-decoder-impl.h"
#include "src/wasm/init-expr-interface.h"
#include "src/wasm/struct-types.h"
#include "src/wasm/wasm-constants.h"
#include "src/wasm/wasm-engine.h"
......@@ -2009,8 +2010,8 @@ class ModuleDecoderImpl : public Decoder {
auto sig = FixedSizeSignature<ValueType>::Returns(expected);
FunctionBody body(&sig, buffer_offset_, pc_, end_);
WasmFeatures detected;
WasmFullDecoder<Decoder::kFullValidation, InitExprInterface,
kInitExpression>
WasmFullDecoder<Decoder::kFullValidation, ConstantExpressionInterface,
kConstantExpression>
decoder(&init_expr_zone_, module, enabled_features_, &detected, body,
module);
......
......@@ -16,7 +16,7 @@
#include "src/tracing/trace-event.h"
#include "src/utils/utils.h"
#include "src/wasm/code-space-access.h"
#include "src/wasm/init-expr-interface.h"
#include "src/wasm/constant-expression-interface.h"
#include "src/wasm/module-compiler.h"
#include "src/wasm/wasm-constants.h"
#include "src/wasm/wasm-engine.h"
......@@ -301,7 +301,7 @@ class InstanceBuilder {
Handle<WasmExportedFunction> start_function_;
std::vector<SanitizedImport> sanitized_imports_;
// We pass this {Zone} to the temporary {WasmFullDecoder} we allocate during
// each call to {EvaluateInitExpression}. This has been found to improve
// each call to {EvaluateConstantExpression}. This has been found to improve
// performance a bit over allocating a new {Zone} each time.
Zone init_expr_zone_;
......@@ -906,53 +906,6 @@ bool MaybeMarkError(ValueOrError value, ErrorThrower* thrower) {
}
} // namespace
ValueOrError EvaluateInitExpression(Zone* zone, ConstantExpression expr,
ValueType expected, Isolate* isolate,
Handle<WasmInstanceObject> instance) {
switch (expr.kind()) {
case ConstantExpression::kEmpty:
UNREACHABLE();
case ConstantExpression::kI32Const:
return WasmValue(expr.i32_value());
case ConstantExpression::kRefNull:
return WasmValue(isolate->factory()->null_value(),
ValueType::Ref(expr.repr(), kNullable));
case ConstantExpression::kRefFunc: {
uint32_t index = expr.index();
Handle<Object> value =
WasmInstanceObject::GetOrCreateWasmInternalFunction(isolate, instance,
index);
return WasmValue(value, expected);
}
case ConstantExpression::kWireBytesRef: {
WireBytesRef ref = expr.wire_bytes_ref();
base::Vector<const byte> module_bytes =
instance->module_object().native_module()->wire_bytes();
const byte* start = module_bytes.begin() + ref.offset();
const byte* end = module_bytes.begin() + ref.end_offset();
auto sig = FixedSizeSignature<ValueType>::Returns(expected);
FunctionBody body(&sig, ref.offset(), start, end);
WasmFeatures detected;
// 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);
decoder.DecodeFunctionBody();
return decoder.interface().has_error()
? ValueOrError(decoder.interface().error())
: ValueOrError(decoder.interface().computed_value());
}
}
}
// Look up an import value in the {ffi_} object specifically for linking an
// asm.js module. This only performs non-observable lookups, which allows
// falling back to JavaScript proper (and hence re-executing all lookups) if
......@@ -1011,7 +964,7 @@ void InstanceBuilder::LoadDataSegments(Handle<WasmInstanceObject> instance) {
size_t dest_offset;
if (module_->is_memory64) {
ValueOrError result = EvaluateInitExpression(
ValueOrError result = EvaluateConstantExpression(
&init_expr_zone_, segment.dest_addr, kWasmI64, isolate_, instance);
if (MaybeMarkError(result, thrower_)) return;
uint64_t dest_offset_64 = to_value(result).to_u64();
......@@ -1022,7 +975,7 @@ void InstanceBuilder::LoadDataSegments(Handle<WasmInstanceObject> instance) {
dest_offset = static_cast<size_t>(std::min(
dest_offset_64, uint64_t{std::numeric_limits<size_t>::max()}));
} else {
ValueOrError result = EvaluateInitExpression(
ValueOrError result = EvaluateConstantExpression(
&init_expr_zone_, segment.dest_addr, kWasmI32, isolate_, instance);
if (MaybeMarkError(result, thrower_)) return;
dest_offset = to_value(result).to_u32();
......@@ -1722,7 +1675,7 @@ void InstanceBuilder::InitGlobals(Handle<WasmInstanceObject> instance) {
// Happens with imported globals.
if (!global.init.is_set()) continue;
ValueOrError result = EvaluateInitExpression(
ValueOrError result = EvaluateConstantExpression(
&init_expr_zone_, global.init, global.type, isolate_, instance);
if (MaybeMarkError(result, thrower_)) return;
......@@ -1989,8 +1942,8 @@ void InstanceBuilder::InitializeNonDefaultableTables(
}
} else {
ValueOrError result =
EvaluateInitExpression(&init_expr_zone_, table.initial_value,
table.type, isolate_, instance);
EvaluateConstantExpression(&init_expr_zone_, table.initial_value,
table.type, isolate_, instance);
if (MaybeMarkError(result, thrower_)) return;
for (uint32_t entry_index = 0; entry_index < table.initial_size;
entry_index++) {
......@@ -2040,7 +1993,7 @@ base::Optional<MessageTemplate> LoadElemSegmentImpl(
entry.kind() == ConstantExpression::kRefNull) {
SetFunctionTableNullEntry(isolate, table_object, entry_index);
} else {
ValueOrError result = EvaluateInitExpression(
ValueOrError result = EvaluateConstantExpression(
zone, entry, elem_segment.type, isolate, instance);
if (is_error(result)) return to_error(result);
WasmTableObject::Set(isolate, table_object, entry_index,
......@@ -2059,7 +2012,7 @@ void InstanceBuilder::LoadTableSegments(Handle<WasmInstanceObject> instance) {
if (elem_segment.status != WasmElemSegment::kStatusActive) continue;
uint32_t table_index = elem_segment.table_index;
ValueOrError value = EvaluateInitExpression(
ValueOrError value = EvaluateConstantExpression(
&init_expr_zone_, elem_segment.offset, kWasmI32, isolate_, instance);
if (MaybeMarkError(value, thrower_)) return;
uint32_t dst = std::get<WasmValue>(value).to_u32();
......
......@@ -11,8 +11,6 @@
#include <stdint.h>
#include <variant>
#include "include/v8config.h"
#include "src/base/optional.h"
#include "src/common/message-template.h"
......@@ -50,22 +48,6 @@ base::Optional<MessageTemplate> LoadElemSegment(
uint32_t segment_index, uint32_t dst, uint32_t src,
uint32_t count) V8_WARN_UNUSED_RESULT;
using ValueOrError = std::variant<WasmValue, MessageTemplate>;
V8_INLINE bool is_error(ValueOrError result) {
return std::holds_alternative<MessageTemplate>(result);
}
V8_INLINE MessageTemplate to_error(ValueOrError result) {
return std::get<MessageTemplate>(result);
}
V8_INLINE WasmValue to_value(ValueOrError result) {
return std::get<WasmValue>(result);
}
ValueOrError EvaluateInitExpression(Zone* zone, ConstantExpression expr,
ValueType expected, Isolate* isolate,
Handle<WasmInstanceObject> instance);
} // namespace wasm
} // namespace internal
} // namespace v8
......
......@@ -18,6 +18,7 @@
#include "src/common/globals.h"
#include "src/handles/handles.h"
#include "src/wasm/branch-hint-map.h"
#include "src/wasm/constant-expression.h"
#include "src/wasm/signature-map.h"
#include "src/wasm/struct-types.h"
#include "src/wasm/wasm-constants.h"
......@@ -73,99 +74,6 @@ struct WasmFunction {
bool declared;
};
// A representation of a constant expression. The most common expression types
// are hard-coded, while the rest are represented as a {WireBytesRef}.
class ConstantExpression {
public:
enum Kind {
kEmpty,
kI32Const,
kRefNull,
kRefFunc,
kWireBytesRef,
kLastKind = kWireBytesRef
};
union Value {
int32_t i32_value;
uint32_t index_or_offset;
HeapType::Representation repr;
};
ConstantExpression() : bit_field_(KindField::encode(kEmpty)) {}
static ConstantExpression I32Const(int32_t value) {
return ConstantExpression(ValueField::encode(value) |
KindField::encode(kI32Const));
}
static ConstantExpression RefFunc(uint32_t index) {
return ConstantExpression(ValueField::encode(index) |
KindField::encode(kRefFunc));
}
static ConstantExpression RefNull(HeapType::Representation repr) {
return ConstantExpression(ValueField::encode(repr) |
KindField::encode(kRefNull));
}
static ConstantExpression WireBytes(uint32_t offset, uint32_t length) {
return ConstantExpression(OffsetField::encode(offset) |
LengthField::encode(length) |
KindField::encode(kWireBytesRef));
}
Kind kind() const { return KindField::decode(bit_field_); }
bool is_set() const { return kind() != kEmpty; }
uint32_t index() const {
DCHECK_EQ(kind(), kRefFunc);
return ValueField::decode(bit_field_);
}
HeapType::Representation repr() const {
DCHECK_EQ(kind(), kRefNull);
return static_cast<HeapType::Representation>(
ValueField::decode(bit_field_));
}
int32_t i32_value() const {
DCHECK_EQ(kind(), kI32Const);
return ValueField::decode(bit_field_);
}
WireBytesRef wire_bytes_ref() const {
DCHECK_EQ(kind(), kWireBytesRef);
return WireBytesRef(OffsetField::decode(bit_field_),
LengthField::decode(bit_field_));
}
private:
static constexpr int kValueBits = 32;
static constexpr int kLengthBits = 30;
static constexpr int kOffsetBits = 30;
static constexpr int kKindBits = 3;
// There are two possible combinations of fields: offset + length + kind if
// kind = kWireBytesRef, or value + kind for anything else.
using ValueField = base::BitField<uint32_t, 0, kValueBits, uint64_t>;
using OffsetField = base::BitField<uint32_t, 0, kOffsetBits, uint64_t>;
using LengthField = OffsetField::Next<uint32_t, kLengthBits>;
using KindField = LengthField::Next<Kind, kKindBits>;
// Make sure we reserve enough bits for a {WireBytesRef}'s length and offset.
static_assert(kV8MaxWasmModuleSize <= LengthField::kMax + 1);
static_assert(kV8MaxWasmModuleSize <= OffsetField::kMax + 1);
// Make sure kind fits in kKindBits.
static_assert(kLastKind <= KindField::kMax + 1);
explicit ConstantExpression(uint64_t bit_field) : bit_field_(bit_field) {}
uint64_t bit_field_;
};
// We want to keep {ConstantExpression} small to reduce memory usage during
// compilation/instantiation.
static_assert(sizeof(ConstantExpression) <= 8);
// Static representation of a wasm global variable.
struct WasmGlobal {
ValueType type; // type of the global.
......
......@@ -298,7 +298,7 @@ std::ostream& operator<<(std::ostream& os, const PrintName& name) {
class InitExprInterface {
public:
static constexpr Decoder::ValidateFlag validate = Decoder::kFullValidation;
static constexpr DecodingMode decoding_mode = kInitExpression;
static constexpr DecodingMode decoding_mode = kConstantExpression;
struct Value : public ValueBase<validate> {
WasmInitExpr init_expr;
......@@ -538,7 +538,7 @@ void DecodeAndAppendInitExpr(StdoutStream& os, Zone* zone,
module_bytes.start() + ref.end_offset());
WasmFeatures detected;
WasmFullDecoder<Decoder::kFullValidation, InitExprInterface,
kInitExpression>
kConstantExpression>
decoder(zone, module, WasmFeatures::All(), &detected, body, zone);
decoder.DecodeFunctionBody();
......
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