[wasm] Declare functions in globals and exports

Due to recent spec changes, We do not have to check if ref.func
instructions in global declarations only refer to declared functions.
Additionally functions referenced in exports and globals are now
considered declared.

R=ecmziegler@chromium.org

Bug: v8:10556
Change-Id: I79856c7d68155a04eb36769ceed8a58fe62a9f9f
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2228653
Commit-Queue: Andreas Haas <ahaas@chromium.org>
Reviewed-by: Emanuel Ziegler <ecmziegler@chromium.org>
Cr-Commit-Position: refs/heads/master@{#68190}
This commit is contained in:
Andreas Haas 2020-06-05 07:14:32 +02:00 committed by Commit Bot
parent 3ba25f0ad9
commit c6c0090532
4 changed files with 10 additions and 76 deletions

View File

@ -408,7 +408,6 @@ class ModuleDecoderImpl : public Decoder {
void DecodeSection(SectionCode section_code, Vector<const uint8_t> bytes,
uint32_t offset, bool verify_functions = true) {
VerifyFunctionDeclarations(section_code);
if (failed()) return;
Reset(bytes, offset);
TRACE("Section: %s\n", SectionName(section_code));
@ -814,8 +813,14 @@ class ModuleDecoderImpl : public Decoder {
WasmFunction* func = nullptr;
exp->index =
consume_func_index(module_.get(), &func, "export function index");
if (failed()) break;
DCHECK_NOT_NULL(func);
module_->num_exported_functions++;
if (func) func->exported = true;
func->exported = true;
// Exported functions are considered "declared".
func->declared = true;
break;
}
case kExternalTable: {
@ -1224,41 +1229,7 @@ class ModuleDecoderImpl : public Decoder {
return true;
}
void VerifyFunctionDeclarations(SectionCode section_code) {
// Since we will only know if a function was properly declared after all the
// element sections have been parsed, but we need to verify the proper use
// within global initialization, we are deferring those checks.
if (deferred_funcref_error_offsets_.empty()) {
// No verifications to do be done.
return;
}
if (!ok()) {
// Previous errors exist.
return;
}
// TODO(ecmziegler): Adjust logic if module order changes (e.g. event
// section).
if (section_code <= kElementSectionCode &&
section_code != kUnknownSectionCode) {
// Before the element section and not at end of decoding.
return;
}
for (auto& func_offset : deferred_funcref_error_offsets_) {
DCHECK_LT(func_offset.first, module_->functions.size());
if (!module_->functions[func_offset.first].declared) {
errorf(func_offset.second, "undeclared reference to function #%u",
func_offset.first);
break;
}
}
deferred_funcref_error_offsets_.clear();
}
ModuleResult FinishDecoding(bool verify_functions = true) {
// Ensure that function verifications were done even if no section followed
// the global section.
VerifyFunctionDeclarations(kUnknownSectionCode);
if (ok() && CheckMismatchedCounts()) {
CalculateGlobalOffsets(module_.get());
}
@ -1378,10 +1349,6 @@ class ModuleDecoderImpl : public Decoder {
kLastKnownModuleSection,
"not enough bits");
WasmError intermediate_error_;
// Map from function index to wire byte offset of first funcref initialization
// in global section. Used for deferred checking and proper error reporting if
// these were not properly declared in the element section.
std::unordered_map<uint32_t, int> deferred_funcref_error_offsets_;
// Set of type offsets discovered in field types during type section decoding.
// Since struct types may be recursive, this is used for checking and error
// reporting once the whole type section is parsed.
@ -1719,10 +1686,10 @@ class ModuleDecoderImpl : public Decoder {
errorf(pc() - 1, "invalid function index: %u", imm.index);
break;
}
// Defer check for declaration of function reference.
deferred_funcref_error_offsets_.emplace(imm.index, pc_offset());
expr.kind = WasmInitExpr::kRefFuncConst;
expr.val.function_index = imm.index;
// Functions referenced in the globals section count as "declared".
module->functions[imm.index].declared = true;
len = imm.length;
break;
}

View File

@ -559,18 +559,6 @@ function dummy_func() {
instance.exports.get_anyfunc_global());
})();
(function TestRefFuncGlobalInitUndeclared() {
print(arguments.callee.name);
let builder = new WasmModuleBuilder();
const global_func = builder.addGlobal(kWasmAnyFunc, true);
const func = builder.addFunction('get_anyfunc_global', kSig_v_v).addBody([]);
global_func.function_index = func.index;
assertThrows(
() => builder.toModule(), WebAssembly.CompileError,
/undeclared reference to function/);
})();
(function TestRefFuncGlobalInitWithImport() {
print(arguments.callee.name);
let builder = new WasmModuleBuilder();

View File

@ -2565,25 +2565,6 @@ TEST_F(WasmModuleVerifyTest, DeclarativeElementSegmentWithInvalidIndex) {
EXPECT_FAILURE_WITH_MSG(data, "element function index 1 out of bounds");
}
TEST_F(WasmModuleVerifyTest, DeclarativeElementSegmentMissingForGlobal) {
WASM_FEATURE_SCOPE(bulk_memory);
WASM_FEATURE_SCOPE(anyref);
static const byte data[] = {
// sig#0 -----------------------------------------------------------------
SIGNATURES_SECTION_VOID_VOID,
// funcs -----------------------------------------------------------------
ONE_EMPTY_FUNCTION(SIG_INDEX(0)),
// global definitions ----------------------------------------------------
SECTION(Global, // section name
ENTRY_COUNT(1), // entry count
kLocalFuncRef, // local type
0, // immutable
WASM_INIT_EXPR_REF_FUNC(0)), // init
// code ------------------------------------------------------------------
ONE_EMPTY_BODY};
EXPECT_FAILURE_WITH_MSG(data, "undeclared reference to function");
}
TEST_F(WasmModuleVerifyTest, DataCountSectionCorrectPlacement) {
static const byte data[] = {SECTION(Element, ENTRY_COUNT(0)),
SECTION(DataCount, ENTRY_COUNT(0)),

View File

@ -20,11 +20,9 @@
'proposals/js-types/globals': [FAIL],
'proposals/js-types/linking': [FAIL],
# TODO(v8:10556): Remove sub-typing in the reference-types implementation
# This test requires the anyref flag to be disabled.
'proposals/bulk-memory-operations/imports': [FAIL],
'proposals/reference-types/ref_func': [FAIL],
# TODO(wasm): This test declares a table larger than allowed by the spec.
'table': [FAIL],
'proposals/reference-types/table': [FAIL],