diff --git a/BUILD.gn b/BUILD.gn index da2e26a739..d54096f80e 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -4102,6 +4102,7 @@ v8_source_set("v8_base_without_compiler") { "src/wasm/wasm-external-refs.cc", "src/wasm/wasm-features.cc", "src/wasm/wasm-import-wrapper-cache.cc", + "src/wasm/wasm-init-expr.cc", "src/wasm/wasm-js.cc", "src/wasm/wasm-module-builder.cc", "src/wasm/wasm-module-sourcemap.cc", diff --git a/src/wasm/module-decoder.cc b/src/wasm/module-decoder.cc index 4ef0875a00..74e1f3b3fe 100644 --- a/src/wasm/module-decoder.cc +++ b/src/wasm/module-decoder.cc @@ -1421,46 +1421,7 @@ class ModuleDecoderImpl : public Decoder { ModuleOrigin origin_; ValueType TypeOf(const WasmInitExpr& expr) { - switch (expr.kind()) { - case WasmInitExpr::kNone: - return kWasmVoid; - case WasmInitExpr::kGlobalGet: - return expr.immediate().index < module_->globals.size() - ? module_->globals[expr.immediate().index].type - : kWasmVoid; - case WasmInitExpr::kI32Const: - return kWasmI32; - case WasmInitExpr::kI64Const: - return kWasmI64; - case WasmInitExpr::kF32Const: - return kWasmF32; - case WasmInitExpr::kF64Const: - return kWasmF64; - case WasmInitExpr::kS128Const: - return kWasmS128; - case WasmInitExpr::kRefFuncConst: { - uint32_t heap_type = - enabled_features_.has_typed_funcref() - ? module_->functions[expr.immediate().index].sig_index - : HeapType::kFunc; - return ValueType::Ref(heap_type, kNonNullable); - } - case WasmInitExpr::kRefNullConst: - return ValueType::Ref(expr.immediate().heap_type, kNullable); - case WasmInitExpr::kRttCanon: { - return ValueType::Rtt(expr.immediate().heap_type, 0); - } - case WasmInitExpr::kRttSub: - case WasmInitExpr::kRttFreshSub: { - ValueType operand_type = TypeOf(*expr.operand()); - if (operand_type.is_rtt()) { - return ValueType::Rtt(expr.immediate().heap_type, - operand_type.depth() + 1); - } else { - return kWasmVoid; - } - } - } + return expr.type(module_.get(), enabled_features_); } bool has_seen_unordered_section(SectionCode section_code) { diff --git a/src/wasm/module-instantiate.cc b/src/wasm/module-instantiate.cc index c8f3843798..ef2bfb2401 100644 --- a/src/wasm/module-instantiate.cc +++ b/src/wasm/module-instantiate.cc @@ -426,13 +426,13 @@ class InstanceBuilder { int ProcessImports(Handle instance); template - T* GetRawGlobalPtr(const WasmGlobal& global); + T* GetRawUntaggedGlobalPtr(const WasmGlobal& global); // Process initialization of globals. void InitGlobals(Handle instance); - Handle RecursivelyEvaluateGlobalInitializer( - const WasmInitExpr& init, Handle instance); + WasmValue EvaluateInitExpression(const WasmInitExpr& init, + Handle instance); // Process the exports, creating wrappers for functions, tables, memories, // and globals. @@ -934,7 +934,7 @@ void InstanceBuilder::WriteGlobalValue(const WasmGlobal& global, double num) { global.type.name().c_str()); switch (global.type.kind()) { case kI32: - WriteLittleEndianValue(GetRawGlobalPtr(global), + WriteLittleEndianValue(GetRawUntaggedGlobalPtr(global), DoubleToInt32(num)); break; case kI64: @@ -943,11 +943,12 @@ void InstanceBuilder::WriteGlobalValue(const WasmGlobal& global, double num) { // https://github.com/WebAssembly/JS-BigInt-integration/issues/12 UNREACHABLE(); case kF32: - WriteLittleEndianValue(GetRawGlobalPtr(global), + WriteLittleEndianValue(GetRawUntaggedGlobalPtr(global), DoubleToFloat32(num)); break; case kF64: - WriteLittleEndianValue(GetRawGlobalPtr(global), num); + WriteLittleEndianValue(GetRawUntaggedGlobalPtr(global), + num); break; default: UNREACHABLE(); @@ -959,7 +960,8 @@ void InstanceBuilder::WriteGlobalValue(const WasmGlobal& global, int64_t num) { raw_buffer_ptr(untagged_globals_, 0), global.offset, num, global.type.name().c_str()); DCHECK_EQ(kWasmI64, global.type); - WriteLittleEndianValue(GetRawGlobalPtr(global), num); + WriteLittleEndianValue(GetRawUntaggedGlobalPtr(global), + num); } void InstanceBuilder::WriteGlobalValue(const WasmGlobal& global, @@ -969,25 +971,29 @@ void InstanceBuilder::WriteGlobalValue(const WasmGlobal& global, switch (global.type.kind()) { case kI32: { int32_t num = value->GetI32(); - WriteLittleEndianValue(GetRawGlobalPtr(global), num); + WriteLittleEndianValue(GetRawUntaggedGlobalPtr(global), + num); TRACE("%d", num); break; } case kI64: { int64_t num = value->GetI64(); - WriteLittleEndianValue(GetRawGlobalPtr(global), num); + WriteLittleEndianValue(GetRawUntaggedGlobalPtr(global), + num); TRACE("%" PRId64, num); break; } case kF32: { float num = value->GetF32(); - WriteLittleEndianValue(GetRawGlobalPtr(global), num); + WriteLittleEndianValue(GetRawUntaggedGlobalPtr(global), + num); TRACE("%f", num); break; } case kF64: { double num = value->GetF64(); - WriteLittleEndianValue(GetRawGlobalPtr(global), num); + WriteLittleEndianValue(GetRawUntaggedGlobalPtr(global), + num); TRACE("%lf", num); break; } @@ -1603,45 +1609,78 @@ int InstanceBuilder::ProcessImports(Handle instance) { } template -T* InstanceBuilder::GetRawGlobalPtr(const WasmGlobal& global) { +T* InstanceBuilder::GetRawUntaggedGlobalPtr(const WasmGlobal& global) { return reinterpret_cast(raw_buffer_ptr(untagged_globals_, global.offset)); } -Handle InstanceBuilder::RecursivelyEvaluateGlobalInitializer( +WasmValue InstanceBuilder::EvaluateInitExpression( const WasmInitExpr& init, Handle instance) { switch (init.kind()) { - case WasmInitExpr::kI32Const: - case WasmInitExpr::kI64Const: - case WasmInitExpr::kF32Const: - case WasmInitExpr::kF64Const: - case WasmInitExpr::kS128Const: - case WasmInitExpr::kRefNullConst: - case WasmInitExpr::kRefFuncConst: case WasmInitExpr::kNone: - // Handled directly by {InitGlobals()}, can't occur as recursive case. UNREACHABLE(); - break; + case WasmInitExpr::kI32Const: + return WasmValue(init.immediate().i32_const); + case WasmInitExpr::kI64Const: + return WasmValue(init.immediate().i64_const); + case WasmInitExpr::kF32Const: + return WasmValue(init.immediate().f32_const); + case WasmInitExpr::kF64Const: + return WasmValue(init.immediate().f64_const); + case WasmInitExpr::kS128Const: + return WasmValue(Simd128(init.immediate().s128_const.data())); + case WasmInitExpr::kRefNullConst: + return WasmValue(handle(ReadOnlyRoots(isolate_).null_value(), isolate_), + init.type(module_, enabled_)); + case WasmInitExpr::kRefFuncConst: { + auto function = WasmInstanceObject::GetOrCreateWasmExternalFunction( + isolate_, instance, init.immediate().index); + return WasmValue(function, init.type(module_, enabled_)); + } case WasmInitExpr::kGlobalGet: { - // We can only get here for reference-type globals, but we don't have - // enough information to DCHECK that directly. - DCHECK(enabled_.has_reftypes() || enabled_.has_eh()); - uint32_t old_offset = module_->globals[init.immediate().index].offset; - DCHECK(static_cast(old_offset) < tagged_globals_->length()); - return handle(tagged_globals_->get(old_offset), isolate_); + const WasmGlobal& global = module_->globals[init.immediate().index]; + switch (global.type.kind()) { + case kI32: + return WasmValue(*GetRawUntaggedGlobalPtr(global)); + case kI64: + return WasmValue(*GetRawUntaggedGlobalPtr(global)); + case kF32: + return WasmValue(*GetRawUntaggedGlobalPtr(global)); + case kF64: + return WasmValue(*GetRawUntaggedGlobalPtr(global)); + case kS128: + return WasmValue(Simd128(GetRawUntaggedGlobalPtr(global))); + case kRef: + case kOptRef: + case kRtt: + case kRttWithDepth: { + DCHECK(static_cast(global.offset) < tagged_globals_->length()); + return WasmValue( + handle(tagged_globals_->get(global.offset), isolate_), + init.type(module_, enabled_)); + } + case kI8: + case kI16: + case kBottom: + case kVoid: + UNREACHABLE(); + } } case WasmInitExpr::kRttCanon: { int map_index = init.immediate().index; - return handle(instance->managed_object_maps().get(map_index), isolate_); + return WasmValue( + handle(instance->managed_object_maps().get(map_index), isolate_), + init.type(module_, enabled_)); } case WasmInitExpr::kRttSub: case WasmInitExpr::kRttFreshSub: { uint32_t type = init.immediate().index; - Handle parent = - RecursivelyEvaluateGlobalInitializer(*init.operand(), instance); - return AllocateSubRtt(isolate_, instance, type, Handle::cast(parent), - init.kind() == WasmInitExpr::kRttSub - ? WasmRttSubMode::kCanonicalize - : WasmRttSubMode::kFresh); + WasmValue parent = EvaluateInitExpression(*init.operand(), instance); + return WasmValue(AllocateSubRtt(isolate_, instance, type, + Handle::cast(parent.to_ref()), + init.kind() == WasmInitExpr::kRttSub + ? WasmRttSubMode::kCanonicalize + : WasmRttSubMode::kFresh), + init.type(module_, enabled_)); } } } @@ -1649,76 +1688,16 @@ Handle InstanceBuilder::RecursivelyEvaluateGlobalInitializer( // Process initialization of globals. void InstanceBuilder::InitGlobals(Handle instance) { for (const WasmGlobal& global : module_->globals) { - if (global.mutability && global.imported) { - continue; - } + if (global.mutability && global.imported) continue; + // Happens with imported globals. + if (global.init.kind() == WasmInitExpr::kNone) continue; - switch (global.init.kind()) { - case WasmInitExpr::kI32Const: - WriteLittleEndianValue(GetRawGlobalPtr(global), - global.init.immediate().i32_const); - break; - case WasmInitExpr::kI64Const: - WriteLittleEndianValue(GetRawGlobalPtr(global), - global.init.immediate().i64_const); - break; - case WasmInitExpr::kF32Const: - WriteLittleEndianValue(GetRawGlobalPtr(global), - global.init.immediate().f32_const); - break; - case WasmInitExpr::kF64Const: - WriteLittleEndianValue(GetRawGlobalPtr(global), - global.init.immediate().f64_const); - break; - case WasmInitExpr::kS128Const: - DCHECK(enabled_.has_simd()); - WriteLittleEndianValue>( - GetRawGlobalPtr>(global), - global.init.immediate().s128_const); - break; - case WasmInitExpr::kRefNullConst: - DCHECK(enabled_.has_reftypes() || enabled_.has_eh()); - if (global.imported) break; // We already initialized imported globals. + WasmValue value = EvaluateInitExpression(global.init, instance); - tagged_globals_->set(global.offset, - ReadOnlyRoots(isolate_).null_value(), - SKIP_WRITE_BARRIER); - break; - case WasmInitExpr::kRefFuncConst: { - DCHECK(enabled_.has_reftypes()); - auto function = WasmInstanceObject::GetOrCreateWasmExternalFunction( - isolate_, instance, global.init.immediate().index); - tagged_globals_->set(global.offset, *function); - break; - } - case WasmInitExpr::kGlobalGet: { - // Initialize with another global. - uint32_t new_offset = global.offset; - uint32_t old_offset = - module_->globals[global.init.immediate().index].offset; - TRACE("init [globals+%u] = [globals+%d]\n", global.offset, old_offset); - if (global.type.is_reference()) { - DCHECK(enabled_.has_reftypes()); - tagged_globals_->set(new_offset, tagged_globals_->get(old_offset)); - } else { - size_t size = (global.type == kWasmI64 || global.type == kWasmF64) - ? sizeof(double) - : sizeof(int32_t); - base::Memcpy(raw_buffer_ptr(untagged_globals_, new_offset), - raw_buffer_ptr(untagged_globals_, old_offset), size); - } - break; - } - case WasmInitExpr::kRttCanon: - case WasmInitExpr::kRttSub: - case WasmInitExpr::kRttFreshSub: - tagged_globals_->set( - global.offset, - *RecursivelyEvaluateGlobalInitializer(global.init, instance)); - break; - case WasmInitExpr::kNone: - // Happens with imported globals. - break; + if (value.type().is_reference()) { + tagged_globals_->set(global.offset, *value.to_ref()); + } else { + value.CopyTo(GetRawUntaggedGlobalPtr(global)); } } } diff --git a/src/wasm/value-type.h b/src/wasm/value-type.h index 580311df22..c12496759f 100644 --- a/src/wasm/value-type.h +++ b/src/wasm/value-type.h @@ -186,6 +186,18 @@ enum ValueKind : uint8_t { #undef DEF_ENUM }; +constexpr bool is_numeric(ValueKind kind) { + switch (kind) { +#define NUMERIC_CASE(kind, ...) \ + case k##kind: \ + return true; + FOREACH_NUMERIC_VALUE_TYPE(NUMERIC_CASE) +#undef NUMERIC_CASE + default: + return false; + } +} + constexpr bool is_reference(ValueKind kind) { return kind == kRef || kind == kOptRef || kind == kRtt || kind == kRttWithDepth; @@ -312,6 +324,8 @@ class ValueType { } /******************************** Type checks *******************************/ + constexpr bool is_numeric() const { return wasm::is_numeric(kind()); } + constexpr bool is_reference() const { return wasm::is_reference(kind()); } constexpr bool is_object_reference() const { diff --git a/src/wasm/wasm-init-expr.cc b/src/wasm/wasm-init-expr.cc new file mode 100644 index 0000000000..79fe221741 --- /dev/null +++ b/src/wasm/wasm-init-expr.cc @@ -0,0 +1,58 @@ +// Copyright 2021 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/wasm-init-expr.h" + +#include "src/wasm/wasm-features.h" +#include "src/wasm/wasm-module.h" + +namespace v8 { +namespace internal { +namespace wasm { + +ValueType WasmInitExpr::type(const WasmModule* module, + const WasmFeatures& enabled_features) const { + switch (kind()) { + case kNone: + return kWasmBottom; + case kGlobalGet: + return immediate().index < module->globals.size() + ? module->globals[immediate().index].type + : kWasmBottom; + case kI32Const: + return kWasmI32; + case kI64Const: + return kWasmI64; + case kF32Const: + return kWasmF32; + case kF64Const: + return kWasmF64; + case kS128Const: + return kWasmS128; + case kRefFuncConst: { + uint32_t heap_type = enabled_features.has_typed_funcref() + ? module->functions[immediate().index].sig_index + : HeapType::kFunc; + return ValueType::Ref(heap_type, kNonNullable); + } + case kRefNullConst: + return ValueType::Ref(immediate().heap_type, kNullable); + case kRttCanon: + return ValueType::Rtt(immediate().heap_type, 0); + case kRttSub: + case kRttFreshSub: { + ValueType operand_type = operand()->type(module, enabled_features); + if (!operand_type.is_rtt()) return kWasmBottom; + if (operand_type.has_depth()) { + return ValueType::Rtt(immediate().heap_type, operand_type.depth() + 1); + } else { + return ValueType::Rtt(immediate().heap_type); + } + } + } +} + +} // namespace wasm +} // namespace internal +} // namespace v8 diff --git a/src/wasm/wasm-init-expr.h b/src/wasm/wasm-init-expr.h index 0be83ff72e..eaa3d734f4 100644 --- a/src/wasm/wasm-init-expr.h +++ b/src/wasm/wasm-init-expr.h @@ -17,6 +17,9 @@ namespace v8 { namespace internal { namespace wasm { +struct WasmModule; +class WasmFeatures; + // Representation of an initializer expression. class WasmInitExpr { public: @@ -144,6 +147,9 @@ class WasmInitExpr { return !(*this == other); } + ValueType type(const WasmModule* module, + const WasmFeatures& enabled_features) const; + private: Immediate immediate_; Operator kind_; diff --git a/src/wasm/wasm-value.h b/src/wasm/wasm-value.h index faaad18076..600504f0ef 100644 --- a/src/wasm/wasm-value.h +++ b/src/wasm/wasm-value.h @@ -48,6 +48,11 @@ class Simd128 { FOREACH_SIMD_TYPE(DEFINE_SIMD_TYPE_SPECIFIC_METHODS) #undef DEFINE_SIMD_TYPE_SPECIFIC_METHODS + explicit Simd128(byte* bytes) { + base::Memcpy(static_cast(val_), reinterpret_cast(bytes), + kSimd128Size); + } + const uint8_t* bytes() { return val_; } template @@ -128,6 +133,12 @@ class WasmValue { !memcmp(bit_pattern_, other.bit_pattern_, 16); } + void CopyTo(byte* to) { + DCHECK(type_.is_numeric()); + base::Memcpy(static_cast(to), static_cast(bit_pattern_), + type_.element_size_bytes()); + } + template inline T to() const;