[wasm] Enable --wasm-type-canonicalization, remove old code

Bug: v8:7748
Change-Id: I74041f23ac64a3e509d82f84b4a710d23bbecbaf
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3893859
Reviewed-by: Jakob Kummerow <jkummerow@chromium.org>
Commit-Queue: Manos Koukoutos <manoskouk@chromium.org>
Cr-Commit-Position: refs/heads/main@{#83227}
This commit is contained in:
Manos Koukoutos 2022-09-14 13:51:10 +02:00 committed by V8 LUCI CQ
parent ac7edc1fdb
commit 7db6d76e97
25 changed files with 115 additions and 291 deletions

View File

@ -2527,8 +2527,6 @@ filegroup(
"src/wasm/names-provider.cc",
"src/wasm/names-provider.h",
"src/wasm/object-access.h",
"src/wasm/signature-map.cc",
"src/wasm/signature-map.h",
"src/wasm/simd-shuffle.cc",
"src/wasm/simd-shuffle.h",
"src/wasm/stacks.cc",

View File

@ -3625,7 +3625,6 @@ v8_header_set("v8_internal_headers") {
"src/wasm/module-instantiate.h",
"src/wasm/names-provider.h",
"src/wasm/object-access.h",
"src/wasm/signature-map.h",
"src/wasm/simd-shuffle.h",
"src/wasm/stacks.h",
"src/wasm/streaming-decoder.h",
@ -4767,7 +4766,6 @@ v8_source_set("v8_base_without_compiler") {
"src/wasm/module-decoder.cc",
"src/wasm/module-instantiate.cc",
"src/wasm/names-provider.cc",
"src/wasm/signature-map.cc",
"src/wasm/simd-shuffle.cc",
"src/wasm/stacks.cc",
"src/wasm/streaming-decoder.cc",

View File

@ -2842,17 +2842,11 @@ Node* WasmGraphBuilder::BuildIndirectCall(uint32_t table_index,
// Note: Since null entries are identified by having ift_sig_id (-1), we only
// need one comparison.
// TODO(9495): Change this if we should do full function subtyping instead.
Node* expected_sig_id;
if (v8_flags.wasm_type_canonicalization) {
Node* isorecursive_canonical_types =
LOAD_INSTANCE_FIELD(IsorecursiveCanonicalTypes, MachineType::Pointer());
expected_sig_id = gasm_->LoadImmutable(
MachineType::Uint32(), isorecursive_canonical_types,
gasm_->IntPtrConstant(sig_index * kInt32Size));
} else {
expected_sig_id =
Int32Constant(env_->module->per_module_canonical_type_ids[sig_index]);
}
Node* isorecursive_canonical_types =
LOAD_INSTANCE_FIELD(IsorecursiveCanonicalTypes, MachineType::Pointer());
Node* expected_sig_id =
gasm_->LoadImmutable(MachineType::Uint32(), isorecursive_canonical_types,
gasm_->IntPtrConstant(sig_index * kInt32Size));
Node* int32_scaled_key = gasm_->BuildChangeUint32ToUintPtr(
gasm_->Word32Shl(key, Int32Constant(2)));

View File

@ -1127,12 +1127,8 @@ DEFINE_BOOL(trace_wasm_inlining, false, "trace wasm inlining")
DEFINE_BOOL(trace_wasm_speculative_inlining, false,
"trace wasm speculative inlining")
DEFINE_BOOL(trace_wasm_typer, false, "trace wasm typer")
DEFINE_BOOL(wasm_type_canonicalization, false,
"apply isorecursive canonicalization on wasm types")
DEFINE_IMPLICATION(wasm_speculative_inlining, wasm_inlining)
DEFINE_WEAK_IMPLICATION(experimental_wasm_gc, wasm_speculative_inlining)
DEFINE_WEAK_IMPLICATION(experimental_wasm_typed_funcref,
wasm_type_canonicalization)
DEFINE_BOOL(wasm_loop_unrolling, true,
"enable loop unrolling for wasm functions")

View File

@ -7184,18 +7184,10 @@ class LiftoffCompiler {
nullptr, false, false, true);
// Compare against expected signature.
if (v8_flags.wasm_type_canonicalization) {
LOAD_INSTANCE_FIELD(tmp_const, IsorecursiveCanonicalTypes,
kSystemPointerSize, pinned);
__ Load(LiftoffRegister(tmp_const), tmp_const, no_reg,
imm.sig_imm.index * kInt32Size, LoadType::kI32Load);
} else {
uint32_t canonical_sig_num =
env_->module->per_module_canonical_type_ids[imm.sig_imm.index];
DCHECK_GE(canonical_sig_num, 0);
DCHECK_GE(kMaxInt, canonical_sig_num);
__ LoadConstant(LiftoffRegister(tmp_const), WasmValue(canonical_sig_num));
}
LOAD_INSTANCE_FIELD(tmp_const, IsorecursiveCanonicalTypes,
kSystemPointerSize, pinned);
__ Load(LiftoffRegister(tmp_const), tmp_const, no_reg,
imm.sig_imm.index * kInt32Size, LoadType::kI32Load);
Label* sig_mismatch_label =
AddOutOfLineTrap(decoder, WasmCode::kThrowWasmTrapFuncSigMismatch);

View File

@ -76,6 +76,7 @@ uint32_t TypeCanonicalizer::AddRecursiveGroup(const FunctionSig* sig) {
for (auto type : sig->parameters()) builder.AddParam(type);
const FunctionSig* allocated_sig = builder.Build();
group.types[0].type_def = TypeDefinition(allocated_sig, kNoSuperType);
group.types[0].is_relative_supertype = false;
canonical_groups_.emplace(group, canonical_index);
canonical_supertypes_.emplace_back(kNoSuperType);
}

View File

@ -754,7 +754,6 @@ class ModuleDecoderTemplate : public Decoder {
continue;
}
}
module_->signature_map.Freeze();
}
void DecodeImportSection() {

View File

@ -188,17 +188,15 @@ void CreateMapForType(Isolate* isolate, const WasmModule* module,
uint32_t canonical_type_index =
module->isorecursive_canonical_type_ids[type_index];
if (v8_flags.wasm_type_canonicalization) {
// Try to find the canonical map for this type in the isolate store.
canonical_rtts = handle(isolate->heap()->wasm_canonical_rtts(), isolate);
DCHECK_GT(static_cast<uint32_t>(canonical_rtts->length()),
canonical_type_index);
MaybeObject maybe_canonical_map = canonical_rtts->Get(canonical_type_index);
if (maybe_canonical_map.IsStrongOrWeak() &&
maybe_canonical_map.GetHeapObject().IsMap()) {
maps->set(type_index, maybe_canonical_map.GetHeapObject());
return;
}
// Try to find the canonical map for this type in the isolate store.
canonical_rtts = handle(isolate->heap()->wasm_canonical_rtts(), isolate);
DCHECK_GT(static_cast<uint32_t>(canonical_rtts->length()),
canonical_type_index);
MaybeObject maybe_canonical_map = canonical_rtts->Get(canonical_type_index);
if (maybe_canonical_map.IsStrongOrWeak() &&
maybe_canonical_map.GetHeapObject().IsMap()) {
maps->set(type_index, maybe_canonical_map.GetHeapObject());
return;
}
Handle<Map> rtt_parent;
@ -224,9 +222,7 @@ void CreateMapForType(Isolate* isolate, const WasmModule* module,
map = CreateFuncRefMap(isolate, module, rtt_parent, instance);
break;
}
if (v8_flags.wasm_type_canonicalization) {
canonical_rtts->Set(canonical_type_index, HeapObjectReference::Weak(*map));
}
canonical_rtts->Set(canonical_type_index, HeapObjectReference::Weak(*map));
maps->set(type_index, *map);
}
@ -661,10 +657,8 @@ MaybeHandle<WasmInstanceObject> InstanceBuilder::Build() {
//--------------------------------------------------------------------------
// Set up table storage space.
//--------------------------------------------------------------------------
if (v8_flags.wasm_type_canonicalization) {
instance->set_isorecursive_canonical_types(
module_->isorecursive_canonical_type_ids.data());
}
instance->set_isorecursive_canonical_types(
module_->isorecursive_canonical_type_ids.data());
int table_count = static_cast<int>(module_->tables.size());
{
for (int i = 0; i < table_count; i++) {
@ -723,8 +717,7 @@ MaybeHandle<WasmInstanceObject> InstanceBuilder::Build() {
// list.
//--------------------------------------------------------------------------
if (enabled_.has_gc()) {
if (v8_flags.wasm_type_canonicalization &&
module_->isorecursive_canonical_type_ids.size() > 0) {
if (module_->isorecursive_canonical_type_ids.size() > 0) {
uint32_t maximum_canonical_type_index =
*std::max_element(module_->isorecursive_canonical_type_ids.begin(),
module_->isorecursive_canonical_type_ids.end());
@ -1272,15 +1265,9 @@ bool InstanceBuilder::InitializeImportedIndirectFunctionTable(
const WasmModule* target_module = target_instance->module_object().module();
const WasmFunction& function = target_module->functions[function_index];
// Look up the signature's canonical id. In the case of
// !v8_flags.wasm_type_canonicalization, if there is no canonical id, then
// the signature does not appear at all in this module, so putting {-1} in
// the table will cause checks to always fail.
FunctionTargetAndRef entry(target_instance, function_index);
uint32_t canonicalized_sig_index =
v8_flags.wasm_type_canonicalization
? target_module->isorecursive_canonical_type_ids[function.sig_index]
: module_->signature_map.Find(*function.sig);
target_module->isorecursive_canonical_type_ids[function.sig_index];
instance->GetIndirectFunctionTable(isolate_, table_index)
->Set(i, canonicalized_sig_index, entry.call_target(), *entry.ref());
}

View File

@ -1,32 +0,0 @@
// Copyright 2016 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/signature-map.h"
#include "src/codegen/signature.h"
namespace v8 {
namespace internal {
namespace wasm {
uint32_t SignatureMap::FindOrInsert(const FunctionSig& sig) {
CHECK(!frozen_);
auto pos = map_.find(sig);
if (pos != map_.end()) return pos->second;
// Indexes are returned as int32_t, thus check against their limit.
CHECK_GE(kMaxInt, map_.size());
uint32_t index = static_cast<uint32_t>(map_.size());
map_.insert(std::make_pair(sig, index));
return index;
}
int32_t SignatureMap::Find(const FunctionSig& sig) const {
auto pos = map_.find(sig);
if (pos == map_.end()) return -1;
return static_cast<int32_t>(pos->second);
}
} // namespace wasm
} // namespace internal
} // namespace v8

View File

@ -1,55 +0,0 @@
// Copyright 2016 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_SIGNATURE_MAP_H_
#define V8_WASM_SIGNATURE_MAP_H_
#include <unordered_map>
#include "src/base/functional.h"
#include "src/codegen/signature.h"
#include "src/wasm/value-type.h"
namespace v8 {
namespace internal {
namespace wasm {
// A signature map canonicalizes signatures into a range of indices so that
// two different {FunctionSig} instances with the same contents map to the
// same index.
class V8_EXPORT_PRIVATE SignatureMap {
public:
// Allow default construction and move construction (because we have vectors
// of objects containing SignatureMaps), but disallow copy or assign. It's
// too easy to get security bugs by accidentally updating a copy of the map.
MOVE_ONLY_WITH_DEFAULT_CONSTRUCTORS(SignatureMap);
// Gets the index for a signature, assigning a new index if necessary.
uint32_t FindOrInsert(const FunctionSig& sig);
// Gets the index for a signature, returning {-1} if not found.
int32_t Find(const FunctionSig& sig) const;
// Disallows further insertions to this signature map.
void Freeze() { frozen_ = true; }
size_t size() const { return map_.size(); }
bool is_frozen() const { return frozen_; }
private:
bool frozen_ = false;
std::unordered_map<FunctionSig, uint32_t, base::hash<FunctionSig>> map_;
};
} // namespace wasm
} // namespace internal
} // namespace v8
#endif // V8_WASM_SIGNATURE_MAP_H_

View File

@ -640,7 +640,6 @@ size_t EstimateStoredSize(const WasmModule* module) {
(module->signature_zone ? module->signature_zone->allocation_size()
: 0) +
VectorSize(module->types) +
VectorSize(module->per_module_canonical_type_ids) +
VectorSize(module->isorecursive_canonical_type_ids) +
VectorSize(module->functions) + VectorSize(module->data_segments) +
VectorSize(module->tables) + VectorSize(module->import_table) +

View File

@ -20,7 +20,6 @@
#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"
#include "src/wasm/wasm-init-expr.h"
@ -515,10 +514,6 @@ struct V8_EXPORT_PRIVATE WasmModule {
void add_type(TypeDefinition type) {
types.push_back(type);
uint32_t canonical_id = type.kind == TypeDefinition::kFunction
? signature_map.FindOrInsert(*type.function_sig)
: 0;
per_module_canonical_type_ids.push_back(canonical_id);
// Isorecursive canonical type will be computed later.
isorecursive_canonical_type_ids.push_back(kNoSuperType);
}
@ -571,14 +566,9 @@ struct V8_EXPORT_PRIVATE WasmModule {
}
std::vector<TypeDefinition> types; // by type index
// TODO(7748): Unify the following two arrays.
// Maps each type index to a canonical index for purposes of call_indirect.
std::vector<uint32_t> per_module_canonical_type_ids;
// Maps each type index to its global (cross-module) canonical index as per
// isorecursive type canonicalization.
std::vector<uint32_t> isorecursive_canonical_type_ids;
// Canonicalizing map for signature indexes.
SignatureMap signature_map;
std::vector<WasmFunction> functions;
std::vector<WasmGlobal> globals;
std::vector<WasmDataSegment> data_segments;

View File

@ -462,24 +462,8 @@ void WasmTableObject::UpdateDispatchTables(Isolate* isolate,
Smi::cast(dispatch_tables.get(i + kDispatchTableIndexOffset)).value();
WasmInstanceObject instance = WasmInstanceObject::cast(
dispatch_tables.get(i + kDispatchTableInstanceOffset));
const WasmModule* module = instance.module();
int sig_id;
if (v8_flags.wasm_type_canonicalization) {
sig_id = target_instance.module()
->isorecursive_canonical_type_ids[original_sig_id];
} else {
// Try to avoid the signature map lookup by checking if the signature in
// {module} at {original_sig_id} matches {func->sig}.
if (module->has_signature(original_sig_id) &&
*module->signature(original_sig_id) == *func->sig) {
sig_id = module->per_module_canonical_type_ids[original_sig_id];
DCHECK_EQ(sig_id, module->signature_map.Find(*func->sig));
} else {
// Note that {SignatureMap::Find} may return {-1} if the signature is
// not found; it will simply never match any check.
sig_id = module->signature_map.Find(*func->sig);
}
}
int sig_id = target_instance.module()
->isorecursive_canonical_type_ids[original_sig_id];
WasmIndirectFunctionTable ift = WasmIndirectFunctionTable::cast(
instance.indirect_function_tables().get(table_index));
ift.Set(entry_index, sig_id, call_target, call_ref);
@ -565,15 +549,8 @@ void WasmTableObject::UpdateDispatchTables(
isolate->counters()->wasm_reloc_size()->Increment(
wasm_code->reloc_info().length());
}
// Note that {SignatureMap::Find} may return {-1} if the signature is
// not found; it will simply never match any check.
// It is safe to use this even when v8_flags.wasm_type_canonicalization, as
// the C API cannot refer to user-defined types.
auto sig_id = v8_flags.wasm_type_canonicalization
? canonical_type_index
: instance->module()->signature_map.Find(sig);
instance->GetIndirectFunctionTable(isolate, table_index)
->Set(entry_index, sig_id, wasm_code->instruction_start(),
->Set(entry_index, canonical_type_index, wasm_code->instruction_start(),
WasmCapiFunctionData::cast(
capi_function->shared().function_data(kAcquireLoad))
.internal()
@ -1439,16 +1416,25 @@ void WasmInstanceObject::ImportWasmJSFunctionIntoTable(
// not found; it will simply never match any check.
Zone zone(isolate->allocator(), ZONE_NAME);
const wasm::FunctionSig* sig = js_function->GetSignature(&zone);
// It is safe to look up the signature this way even if
// v8_flags.wasm_type_canonicalization: Signatures created in the JS API
// cannot contain user-defined (module-dependent) types.
auto sig_id = instance->module()->signature_map.Find(*sig);
// Get the function's canonical signature index. Note that the function's
// signature may not be present in the importing module.
uint32_t canonical_sig_index =
wasm::GetTypeCanonicalizer()->AddRecursiveGroup(sig);
// Compile a wrapper for the target callable.
Handle<JSReceiver> callable(js_function->GetCallable(), isolate);
wasm::WasmCodeRefScope code_ref_scope;
Address call_target = kNullAddress;
if (sig_id >= 0) {
auto module_canonical_ids =
instance->module()->isorecursive_canonical_type_ids;
// TODO(manoskouk): Consider adding a set of canonical indices to the module
// to avoid this linear search.
auto sig_in_module =
std::find(module_canonical_ids.begin(), module_canonical_ids.end(),
canonical_sig_index);
if (sig_in_module != module_canonical_ids.end()) {
wasm::NativeModule* native_module =
instance->module_object().native_module();
// TODO(wasm): Cache and reuse wrapper code, to avoid repeated compilation
@ -1490,14 +1476,10 @@ void WasmInstanceObject::ImportWasmJSFunctionIntoTable(
wasm::Suspend suspend = js_function->GetSuspend();
Handle<WasmApiFunctionRef> ref =
isolate->factory()->NewWasmApiFunctionRef(callable, suspend, instance);
uint32_t canonicalized_sig_id =
v8_flags.wasm_type_canonicalization && sig_id >= 0
? instance->module()->isorecursive_canonical_type_ids[sig_id]
: sig_id;
WasmIndirectFunctionTable::cast(
instance->indirect_function_tables().get(table_index))
.Set(entry_index, canonicalized_sig_id, call_target, *ref);
.Set(entry_index, canonical_sig_index, call_target, *ref);
}
// static

View File

@ -17,7 +17,6 @@ V8_INLINE bool EquivalentIndices(uint32_t index1, uint32_t index2,
const WasmModule* module1,
const WasmModule* module2) {
DCHECK(index1 != index2 || module1 != module2);
if (!v8_flags.wasm_type_canonicalization) return false;
return module1->isorecursive_canonical_type_ids[index1] ==
module2->isorecursive_canonical_type_ids[index2];
}
@ -289,19 +288,8 @@ V8_NOINLINE V8_EXPORT_PRIVATE bool IsHeapSubtypeOfImpl(
// The {IsSubtypeOf} entry point already has a fast path checking ValueType
// equality; here we catch (ref $x) being a subtype of (ref null $x).
if (sub_module == super_module && sub_index == super_index) return true;
if (v8_flags.wasm_type_canonicalization) {
return GetTypeCanonicalizer()->IsCanonicalSubtype(sub_index, super_index,
sub_module, super_module);
} else {
uint32_t explicit_super = sub_module->supertype(sub_index);
while (true) {
if (explicit_super == super_index) return true;
// Reached the end of the explicitly defined inheritance chain.
if (explicit_super == kNoSuperType) return false;
explicit_super = sub_module->supertype(explicit_super);
}
}
return GetTypeCanonicalizer()->IsCanonicalSubtype(sub_index, super_index,
sub_module, super_module);
}
V8_NOINLINE bool EquivalentTypes(ValueType type1, ValueType type2,

View File

@ -40,10 +40,6 @@ class WasmGCTester {
execution_tier == TestExecutionTier::kLiftoff),
flag_wasm_dynamic_tiering(&v8::internal::v8_flags.wasm_dynamic_tiering,
v8::internal::v8_flags.liftoff_only != true),
// Test both setups with canonicalization and without.
flag_canonicalization(
&v8::internal::v8_flags.wasm_type_canonicalization,
execution_tier == TestExecutionTier::kTurbofan),
flag_tierup(&v8::internal::v8_flags.wasm_tier_up, false),
zone_(&allocator, ZONE_NAME),
builder_(&zone_),
@ -200,7 +196,6 @@ class WasmGCTester {
const FlagScope<bool> flag_liftoff;
const FlagScope<bool> flag_liftoff_only;
const FlagScope<bool> flag_wasm_dynamic_tiering;
const FlagScope<bool> flag_canonicalization;
const FlagScope<bool> flag_tierup;
byte DefineFunctionImpl(WasmFunctionBuilder* fun,

View File

@ -565,7 +565,7 @@ void TestTableCopyElems(TestExecutionTier execution_tier, int table_dst,
WASM_LOCAL_GET(1), WASM_LOCAL_GET(2)),
kExprI32Const, 0);
r.builder().FreezeSignatureMapAndInitializeWrapperCache();
r.builder().InitializeWrapperCache();
auto table =
handle(WasmTableObject::cast(
@ -714,7 +714,7 @@ void TestTableCopyOobWrites(TestExecutionTier execution_tier, int table_dst,
WASM_LOCAL_GET(1), WASM_LOCAL_GET(2)),
kExprI32Const, 0);
r.builder().FreezeSignatureMapAndInitializeWrapperCache();
r.builder().InitializeWrapperCache();
auto table =
handle(WasmTableObject::cast(

View File

@ -116,42 +116,6 @@ WASM_COMPILED_EXEC_TEST(Run_CallJS_Add_jswrapped) {
r.CheckCallViaJS(-666666801, -666666900);
}
WASM_COMPILED_EXEC_TEST(Run_IndirectCallJSFunction) {
Isolate* isolate = CcTest::InitIsolateOnce();
HandleScope scope(isolate);
TestSignatures sigs;
const char* source = "(function(a, b, c) { if(c) return a; return b; })";
Handle<JSFunction> js_function =
Handle<JSFunction>::cast(v8::Utils::OpenHandle(
*v8::Local<v8::Function>::Cast(CompileRun(source))));
ManuallyImportedJSFunction import = {sigs.i_iii(), js_function};
WasmRunner<int32_t, int32_t> r(execution_tier, &import);
const uint32_t js_index = 0;
const int32_t left = -2;
const int32_t right = 3;
WasmFunctionCompiler& rc_fn = r.NewFunction(sigs.i_i(), "rc");
byte sig_index = r.builder().AddSignature(sigs.i_iii());
uint16_t indirect_function_table[] = {static_cast<uint16_t>(js_index)};
r.builder().AddIndirectFunctionTable(indirect_function_table,
arraysize(indirect_function_table));
BUILD(rc_fn, WASM_CALL_INDIRECT(sig_index, WASM_I32V(left), WASM_I32V(right),
WASM_LOCAL_GET(0), WASM_I32V(js_index)));
Handle<Object> args_left[] = {isolate->factory()->NewNumber(1)};
r.CheckCallApplyViaJS(left, rc_fn.function_index(), args_left, 1);
Handle<Object> args_right[] = {isolate->factory()->NewNumber(0)};
r.CheckCallApplyViaJS(right, rc_fn.function_index(), args_right, 1);
}
void RunJSSelectTest(TestExecutionTier tier, int which) {
const int kMaxParams = 8;
PredictableInputValues inputs(0x100);
@ -561,10 +525,6 @@ WASM_COMPILED_EXEC_TEST(Run_ReturnCallImportedFunction) {
RunPickerTest(execution_tier, false);
}
WASM_COMPILED_EXEC_TEST(Run_ReturnCallIndirectImportedFunction) {
RunPickerTest(execution_tier, true);
}
} // namespace wasm
} // namespace internal
} // namespace v8

View File

@ -185,9 +185,7 @@ uint32_t TestingModuleBuilder::AddFunction(const FunctionSig* sig,
return index;
}
void TestingModuleBuilder::FreezeSignatureMapAndInitializeWrapperCache() {
if (test_module_->signature_map.is_frozen()) return;
test_module_->signature_map.Freeze();
void TestingModuleBuilder::InitializeWrapperCache() {
size_t max_num_sigs = MaxNumExportWrappers(test_module_.get());
Handle<FixedArray> export_wrappers =
isolate_->factory()->NewFixedArray(static_cast<int>(max_num_sigs));
@ -196,7 +194,7 @@ void TestingModuleBuilder::FreezeSignatureMapAndInitializeWrapperCache() {
Handle<JSFunction> TestingModuleBuilder::WrapCode(uint32_t index) {
CHECK(!interpreter_);
FreezeSignatureMapAndInitializeWrapperCache();
InitializeWrapperCache();
return handle(
JSFunction::cast(WasmInstanceObject::GetOrCreateWasmInternalFunction(
isolate_, instance_object(), index)
@ -244,10 +242,7 @@ void TestingModuleBuilder::AddIndirectFunctionTable(
for (uint32_t i = 0; i < table_size; ++i) {
WasmFunction& function = test_module_->functions[function_indexes[i]];
int sig_id =
v8_flags.wasm_type_canonicalization
? test_module_
->isorecursive_canonical_type_ids[function.sig_index]
: test_module_->signature_map.Find(*function.sig);
test_module_->isorecursive_canonical_type_ids[function.sig_index];
FunctionTargetAndRef entry(instance, function.func_index);
instance->GetIndirectFunctionTable(isolate_, table_index)
->Set(i, sig_id, entry.call_target(), *entry.ref());

View File

@ -135,14 +135,10 @@ class TestingModuleBuilder {
}
byte AddSignature(const FunctionSig* sig) {
DCHECK_EQ(test_module_->types.size(),
test_module_->per_module_canonical_type_ids.size());
test_module_->add_signature(sig, kNoSuperType);
GetTypeCanonicalizer()->AddRecursiveGroup(test_module_.get(), 1);
if (v8_flags.wasm_type_canonicalization) {
instance_object_->set_isorecursive_canonical_types(
test_module_->isorecursive_canonical_type_ids.data());
}
instance_object_->set_isorecursive_canonical_types(
test_module_->isorecursive_canonical_type_ids.data());
size_t size = test_module_->types.size();
CHECK_GT(127, size);
return static_cast<byte>(size - 1);
@ -213,7 +209,7 @@ class TestingModuleBuilder {
// Freezes the signature map of the module and allocates the storage for
// export wrappers.
void FreezeSignatureMapAndInitializeWrapperCache();
void InitializeWrapperCache();
// Wrap the code so it can be called as a JS function.
Handle<JSFunction> WrapCode(uint32_t index);

View File

@ -4103,13 +4103,7 @@ class WasmInterpreterInternals {
uint32_t sig_index) {
HandleScope handle_scope(isolate_); // Avoid leaking handles.
uint32_t expected_sig_id;
if (v8_flags.wasm_type_canonicalization) {
expected_sig_id = module()->isorecursive_canonical_type_ids[sig_index];
} else {
expected_sig_id = module()->per_module_canonical_type_ids[sig_index];
DCHECK_EQ(static_cast<int>(expected_sig_id),
module()->signature_map.Find(*module()->signature(sig_index)));
}
expected_sig_id = module()->isorecursive_canonical_type_ids[sig_index];
Handle<WasmIndirectFunctionTable> table =
instance_object_->GetIndirectFunctionTable(isolate_, table_index);

View File

@ -7,6 +7,7 @@
d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js');
(function TestTableType() {
print(arguments.callee.name);
let table = new WebAssembly.Table({initial: 1, element: "externref"});
let type = table.type();
assertEquals(1, type.minimum);
@ -22,6 +23,7 @@ d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js');
})();
(function TestGlobalType() {
print(arguments.callee.name);
let global = new WebAssembly.Global({value: "externref", mutable: true});
let type = global.type();
assertEquals("externref", type.value);
@ -48,6 +50,7 @@ d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js');
})();
(function TestFunctionGlobalGetAndSet() {
print(arguments.callee.name);
let builder = new WasmModuleBuilder();
let fun1 = new WebAssembly.Function({parameters:[], results:["i32"]}, _ => 7);
let fun2 = new WebAssembly.Function({parameters:[], results:["i32"]}, _ => 9);
@ -80,6 +83,7 @@ d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js');
})();
(function TestFunctionMultiTableSetAndCall() {
print(arguments.callee.name);
let builder = new WasmModuleBuilder();
let v1 = 7; let v2 = 9; let v3 = 0.0;
let f1 = new WebAssembly.Function({parameters:[], results:["i32"]}, _ => v1);

View File

@ -7,6 +7,7 @@
d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js');
(function TestMemoryType() {
print(arguments.callee.name);
let mem = new WebAssembly.Memory({initial: 1});
let type = mem.type();
assertEquals(1, type.minimum);
@ -22,6 +23,7 @@ d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js');
})();
(function TestMemoryExports() {
print(arguments.callee.name);
let builder = new WasmModuleBuilder();
builder.addMemory(1).exportMemoryAs("a")
let module = new WebAssembly.Module(builder.toBuffer());
@ -44,6 +46,7 @@ d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js');
})();
(function TestMemoryImports() {
print(arguments.callee.name);
let builder = new WasmModuleBuilder();
builder.addImportedMemory("m", "a", 1);
let module = new WebAssembly.Module(builder.toBuffer());
@ -68,6 +71,7 @@ d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js');
})();
(function TestTableType() {
print(arguments.callee.name);
let table = new WebAssembly.Table({initial: 1, element: "funcref"});
let type = table.type();
assertEquals(1, type.minimum);
@ -98,6 +102,7 @@ d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js');
})();
(function TestTableExports() {
print(arguments.callee.name);
let builder = new WasmModuleBuilder();
builder.addTable(kWasmAnyFunc, 20).exportAs("a");
let module = new WebAssembly.Module(builder.toBuffer());
@ -122,6 +127,7 @@ d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js');
})();
(function TestTableImports() {
print(arguments.callee.name);
let builder = new WasmModuleBuilder();
builder.addImportedTable("m", "a", 20, undefined, kWasmAnyFunc);
let module = new WebAssembly.Module(builder.toBuffer());
@ -148,6 +154,7 @@ d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js');
})();
(function TestGlobalType() {
print(arguments.callee.name);
let global = new WebAssembly.Global({value: "i32", mutable: true});
let type = global.type();
assertEquals("i32", type.value);
@ -180,6 +187,7 @@ d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js');
})();
(function TestGlobalExports() {
print(arguments.callee.name);
let builder = new WasmModuleBuilder();
builder.addGlobal(kWasmI32).exportAs("a");
builder.addGlobal(kWasmF64, true).exportAs("b");
@ -198,6 +206,7 @@ d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js');
})();
(function TestGlobalImports() {
print(arguments.callee.name);
let builder = new WasmModuleBuilder();
builder.addImportedGlobal("m", "a", kWasmI32);
builder.addImportedGlobal("m", "b", kWasmF64, true);
@ -218,6 +227,7 @@ d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js');
})();
(function TestMemoryConstructorWithMinimum() {
print(arguments.callee.name);
let mem = new WebAssembly.Memory({minimum: 1});
assertTrue(mem instanceof WebAssembly.Memory);
let type = mem.type();
@ -252,6 +262,7 @@ d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js');
})();
(function TestTableConstructorWithMinimum() {
print(arguments.callee.name);
let table = new WebAssembly.Table({minimum: 1, element: 'funcref'});
assertTrue(table instanceof WebAssembly.Table);
let type = table.type();
@ -280,6 +291,7 @@ d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js');
})();
(function TestFunctionConstructor() {
print(arguments.callee.name);
let toolong = new Array(1000 + 1);
let desc = Object.getOwnPropertyDescriptor(WebAssembly, 'Function');
assertEquals(typeof desc.value, 'function');
@ -323,6 +335,7 @@ d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js');
})();
(function TestFunctionConstructorWithWasmExportedFunction() {
print(arguments.callee.name);
let builder = new WasmModuleBuilder();
builder.addFunction('func1', kSig_v_i).addBody([]).exportFunc();
@ -343,6 +356,7 @@ d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js');
})();
(function TestFunctionConstructorWithWasmJSFunction() {
print(arguments.callee.name);
const func = new WebAssembly.Function({parameters: [], results: []}, _ => 0);
assertDoesNotThrow(
@ -356,6 +370,7 @@ d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js');
})();
(function TestFunctionConstructorNonArray1() {
print(arguments.callee.name);
let log = []; // Populated with a log of accesses.
let two = { toString: () => "2" }; // Just a fancy "2".
let logger = new Proxy({ length: two, "0": "i32", "1": "f32"}, {
@ -368,6 +383,7 @@ d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js');
})();
(function TestFunctionConstructorNonArray2() {
print(arguments.callee.name);
let throw1 = { get length() { throw new Error("cannot see length"); }};
let throw2 = { length: { toString: _ => { throw new Error("no length") } } };
let throw3 = { length: "not a length value, this also throws" };
@ -392,6 +408,7 @@ d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js');
})();
(function TestFunctionConstructedFunction() {
print(arguments.callee.name);
let fun = new WebAssembly.Function({parameters:[], results:[]}, _ => 0);
assertTrue(fun instanceof WebAssembly.Function);
assertTrue(fun instanceof Function);
@ -405,6 +422,7 @@ d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js');
})();
(function TestFunctionExportedFunction() {
print(arguments.callee.name);
let builder = new WasmModuleBuilder();
builder.addFunction("fun", kSig_v_v).addBody([]).exportFunc();
let instance = builder.instantiate();
@ -421,6 +439,7 @@ d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js');
})();
(function TestFunctionTypeOfConstructedFunction() {
print(arguments.callee.name);
let testcases = [
{parameters:[], results:[]},
{parameters:["i32"], results:[]},
@ -436,6 +455,7 @@ d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js');
})();
(function TestFunctionTypeOfExportedFunction() {
print(arguments.callee.name);
let testcases = [
[kSig_v_v, {parameters:[], results:[]}],
[kSig_v_i, {parameters:["i32"], results:[]}],
@ -453,6 +473,7 @@ d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js');
})();
(function TestFunctionExports() {
print(arguments.callee.name);
let testcases = [
[kSig_v_v, {parameters:[], results:[]}],
[kSig_v_i, {parameters:["i32"], results:[]}],
@ -472,6 +493,7 @@ d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js');
})();
(function TestFunctionImports() {
print(arguments.callee.name);
let testcases = [
[kSig_v_v, {parameters:[], results:[]}],
[kSig_v_i, {parameters:["i32"], results:[]}],
@ -492,6 +514,7 @@ d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js');
})();
(function TestFunctionConstructedCoercions() {
print(arguments.callee.name);
let obj1 = { valueOf: _ => 123.45 };
let obj2 = { toString: _ => "456" };
let gcer = { valueOf: _ => gc() };
@ -529,6 +552,7 @@ d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js');
})();
(function TestFunctionTableSetI64() {
print(arguments.callee.name);
let builder = new WasmModuleBuilder();
let fun = new WebAssembly.Function({parameters:[], results:["i64"]}, _ => 0n);
let table = new WebAssembly.Table({element: "anyfunc", initial: 2});
@ -550,6 +574,7 @@ d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js');
})();
(function TestFunctionModuleImportMatchingSig() {
print(arguments.callee.name);
let builder = new WasmModuleBuilder();
let fun = new WebAssembly.Function({parameters:[], results:["i32"]}, _ => 7);
let fun_index = builder.addImport("m", "fun", kSig_i_v)
@ -563,6 +588,7 @@ d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js');
})();
(function TestFunctionModuleImportMismatchingSig() {
print(arguments.callee.name);
let builder = new WasmModuleBuilder();
let fun1 = new WebAssembly.Function({parameters:[], results:[]}, _ => 7);
let fun2 = new WebAssembly.Function({parameters:["i32"], results:[]}, _ => 8);
@ -585,6 +611,7 @@ d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js');
})();
(function TestFunctionModuleImportReExport () {
print(arguments.callee.name);
let builder = new WasmModuleBuilder();
let fun = new WebAssembly.Function({parameters:[], results:["i32"]}, _ => 7);
let fun_index = builder.addImport("m", "fun", kSig_i_v)
@ -594,3 +621,28 @@ d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js');
assertSame(instance.exports.fun1, instance.exports.fun2);
assertSame(fun, instance.exports.fun1);
})();
(function TestCallIndirectJSFunction() {
print(arguments.callee.name);
let imp = new WebAssembly.Function(
{parameters:["i32", "i32", "i32"], results:["i32"]},
function(a, b, c) { if (c) return a; return b; });
let builder = new WasmModuleBuilder();
let sig_index = builder.addType(kSig_i_iii);
let fun_index = builder.addImport("m", "imp", kSig_i_iii)
builder.addTable(kWasmFuncRef, 1, 1);
let table_index = 0;
let segment = builder.addActiveElementSegment(
table_index, wasmI32Const(0), [[kExprRefFunc, 0]], kWasmFuncRef);
let main = builder.addFunction("rc", kSig_i_i)
.addBody([...wasmI32Const(-2), kExprI32Const, 3, kExprLocalGet, 0,
kExprI32Const, 0, kExprCallIndirect, sig_index, table_index])
.exportFunc();
let instance = builder.instantiate({ m: { imp: imp }});
assertEquals(instance.exports.rc(1), -2);
assertEquals(instance.exports.rc(0), 3);
})();

View File

@ -9,7 +9,6 @@
#include "src/wasm/function-body-decoder-impl.h"
#include "src/wasm/leb-helper.h"
#include "src/wasm/local-decl-encoder.h"
#include "src/wasm/signature-map.h"
#include "src/wasm/wasm-limits.h"
#include "src/wasm/wasm-module.h"
#include "src/wasm/wasm-opcodes-inl.h"

View File

@ -1029,7 +1029,6 @@ TEST_F(WasmModuleVerifyTest, InvalidArrayTypeDef) {
TEST_F(WasmModuleVerifyTest, TypeCanonicalization) {
WASM_FEATURE_SCOPE(typed_funcref);
WASM_FEATURE_SCOPE(gc);
FLAG_SCOPE(wasm_type_canonicalization);
static const byte identical_group[] = {
SECTION(Type, // --
ENTRY_COUNT(2), // two identical rec. groups
@ -1070,7 +1069,6 @@ TEST_F(WasmModuleVerifyTest, TypeCanonicalization) {
TEST_F(WasmModuleVerifyTest, InvalidSupertypeInRecGroup) {
WASM_FEATURE_SCOPE(typed_funcref);
WASM_FEATURE_SCOPE(gc);
FLAG_SCOPE(wasm_type_canonicalization);
static const byte invalid_supertype[] = {
SECTION(Type, ENTRY_COUNT(1), // --
kWasmRecursiveTypeGroupCode, ENTRY_COUNT(2), // --
@ -1310,16 +1308,13 @@ TEST_F(WasmModuleVerifyTest, CanonicalTypeIds) {
const WasmModule* module = result.value().get();
EXPECT_EQ(5u, module->types.size());
EXPECT_EQ(5u, module->per_module_canonical_type_ids.size());
EXPECT_EQ(2u, module->signature_map.size());
EXPECT_EQ(5u, module->isorecursive_canonical_type_ids.size());
// No canonicalization for structs.
EXPECT_EQ(0u, module->per_module_canonical_type_ids[0]);
EXPECT_EQ(0u, module->per_module_canonical_type_ids[1]);
EXPECT_EQ(1u, module->per_module_canonical_type_ids[2]);
EXPECT_EQ(0u, module->per_module_canonical_type_ids[3]);
// No canonicalization for arrays.
EXPECT_EQ(0u, module->per_module_canonical_type_ids[4]);
EXPECT_EQ(0u, module->isorecursive_canonical_type_ids[0]);
EXPECT_EQ(1u, module->isorecursive_canonical_type_ids[1]);
EXPECT_EQ(2u, module->isorecursive_canonical_type_ids[2]);
EXPECT_EQ(1u, module->isorecursive_canonical_type_ids[3]);
EXPECT_EQ(3u, module->isorecursive_canonical_type_ids[4]);
}
TEST_F(WasmModuleVerifyTest, DataSegmentWithImmutableImportedGlobal) {

View File

@ -174,9 +174,7 @@ TEST_F(WasmSubtypingTest, Subtyping) {
TypeInModule(type_result, module_result))
for (WasmModule* module : {module1, module2}) {
// For cross module subtyping, we need to enable type canonicalization.
// Type judgements across modules should work the same as within one module.
FLAG_VALUE_SCOPE(wasm_type_canonicalization, module == module2);
// Value types are unrelated, except if they are equal.
for (ValueType subtype : numeric_types) {
@ -311,7 +309,6 @@ TEST_F(WasmSubtypingTest, Subtyping) {
{
// Canonicalization tests.
FLAG_SCOPE(wasm_type_canonicalization);
// Groups should only be canonicalized to identical groups.
IDENTICAL(18, 22);