[wasm] WAT-compatible naming for exported function
For exported functions that do not have a name yet, we use the field name (see <name> of WasmExport) of the first export entry. Doc: https://docs.google.com/document/d/1XoXWONLBgZWQ9dhtoMpQPvD0fnnWA50OorsuSXfME3g/edit#heading=h.6yuhg1v2w3q4 Bug: v8:10242 Change-Id: Icfa55fd50e5d1c4cf10581b7d322112e9f113388 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2112684 Commit-Queue: Z Nguyen-Huu <duongn@microsoft.com> Reviewed-by: Clemens Backes <clemensb@chromium.org> Reviewed-by: Kim-Anh Tran <kimanh@chromium.org> Cr-Commit-Position: refs/heads/master@{#66877}
This commit is contained in:
parent
dbda6c3d4f
commit
073c5d2dd6
@ -313,6 +313,8 @@ class ModuleDecoderImpl : public Decoder {
|
||||
error(start_, "end is less than start");
|
||||
end_ = start_;
|
||||
}
|
||||
module_start_ = module_start;
|
||||
module_end_ = module_end;
|
||||
}
|
||||
|
||||
void onFirstError() override {
|
||||
@ -933,7 +935,7 @@ class ModuleDecoderImpl : public Decoder {
|
||||
&module_->functions[index + module_->num_imported_functions];
|
||||
function->code = {offset, length};
|
||||
if (verify_functions) {
|
||||
ModuleWireBytes bytes(start_, end_);
|
||||
ModuleWireBytes bytes(module_start_, module_end_);
|
||||
VerifyFunctionBody(module_->signature_zone->allocator(),
|
||||
index + module_->num_imported_functions, bytes,
|
||||
module_.get(), function);
|
||||
@ -1296,6 +1298,8 @@ class ModuleDecoderImpl : public Decoder {
|
||||
private:
|
||||
const WasmFeatures enabled_features_;
|
||||
std::shared_ptr<WasmModule> module_;
|
||||
const byte* module_start_;
|
||||
const byte* module_end_;
|
||||
Counters* counters_ = nullptr;
|
||||
// The type section is the first section in a module.
|
||||
uint8_t next_ordered_section_ = kFirstSectionInModule;
|
||||
@ -2208,36 +2212,50 @@ bool FindNameSection(Decoder* decoder) {
|
||||
} // namespace
|
||||
|
||||
void DecodeFunctionNames(const byte* module_start, const byte* module_end,
|
||||
std::unordered_map<uint32_t, WireBytesRef>* names) {
|
||||
std::unordered_map<uint32_t, WireBytesRef>* names,
|
||||
const Vector<const WasmExport> export_table) {
|
||||
DCHECK_NOT_NULL(names);
|
||||
DCHECK(names->empty());
|
||||
|
||||
Decoder decoder(module_start, module_end);
|
||||
if (!FindNameSection(&decoder)) return;
|
||||
if (FindNameSection(&decoder)) {
|
||||
while (decoder.ok() && decoder.more()) {
|
||||
uint8_t name_type = decoder.consume_u8("name type");
|
||||
if (name_type & 0x80) break; // no varuint7
|
||||
|
||||
while (decoder.ok() && decoder.more()) {
|
||||
uint8_t name_type = decoder.consume_u8("name type");
|
||||
if (name_type & 0x80) break; // no varuint7
|
||||
uint32_t name_payload_len = decoder.consume_u32v("name payload length");
|
||||
if (!decoder.checkAvailable(name_payload_len)) break;
|
||||
|
||||
uint32_t name_payload_len = decoder.consume_u32v("name payload length");
|
||||
if (!decoder.checkAvailable(name_payload_len)) break;
|
||||
|
||||
if (name_type != NameSectionKindCode::kFunction) {
|
||||
decoder.consume_bytes(name_payload_len, "name subsection payload");
|
||||
continue;
|
||||
}
|
||||
uint32_t functions_count = decoder.consume_u32v("functions count");
|
||||
|
||||
for (; decoder.ok() && functions_count > 0; --functions_count) {
|
||||
uint32_t function_index = decoder.consume_u32v("function index");
|
||||
WireBytesRef name = consume_string(&decoder, false, "function name");
|
||||
|
||||
// Be lenient with errors in the name section: Ignore non-UTF8 names. You
|
||||
// can even assign to the same function multiple times (last valid one
|
||||
// wins).
|
||||
if (decoder.ok() && validate_utf8(&decoder, name)) {
|
||||
names->insert(std::make_pair(function_index, name));
|
||||
if (name_type != NameSectionKindCode::kFunction) {
|
||||
decoder.consume_bytes(name_payload_len, "name subsection payload");
|
||||
continue;
|
||||
}
|
||||
uint32_t functions_count = decoder.consume_u32v("functions count");
|
||||
|
||||
for (; decoder.ok() && functions_count > 0; --functions_count) {
|
||||
uint32_t function_index = decoder.consume_u32v("function index");
|
||||
WireBytesRef name = consume_string(&decoder, false, "function name");
|
||||
|
||||
// Be lenient with errors in the name section: Ignore non-UTF8 names.
|
||||
// You can even assign to the same function multiple times (last valid
|
||||
// one wins).
|
||||
if (decoder.ok() && validate_utf8(&decoder, name)) {
|
||||
names->insert(std::make_pair(function_index, name));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Extract from export table.
|
||||
for (const WasmExport& exp : export_table) {
|
||||
switch (exp.kind) {
|
||||
case kExternalFunction:
|
||||
if (names->count(exp.index) == 0) {
|
||||
names->insert(std::make_pair(exp.index, exp.name));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -160,11 +160,13 @@ V8_EXPORT_PRIVATE std::vector<CustomSectionOffset> DecodeCustomSections(
|
||||
// function.
|
||||
AsmJsOffsetsResult DecodeAsmJsOffsets(Vector<const uint8_t> encoded_offsets);
|
||||
|
||||
// Decode the function names from the name section.
|
||||
// Returns the result as an unordered map. Only names with valid utf8 encoding
|
||||
// are stored and conflicts are resolved by choosing the last name read.
|
||||
// Decode the function names from the name section and also look at export
|
||||
// table. Returns the result as an unordered map. Only names with valid utf8
|
||||
// encoding are stored and conflicts are resolved by choosing the last name
|
||||
// read.
|
||||
void DecodeFunctionNames(const byte* module_start, const byte* module_end,
|
||||
std::unordered_map<uint32_t, WireBytesRef>* names);
|
||||
std::unordered_map<uint32_t, WireBytesRef>* names,
|
||||
const Vector<const WasmExport> export_table);
|
||||
|
||||
// Decode the local names assignment from the name section.
|
||||
// The result will be empty if no name section is present. On encountering an
|
||||
|
@ -195,8 +195,8 @@ void WasmCode::LogCode(Isolate* isolate) const {
|
||||
if (IsAnonymous()) return;
|
||||
|
||||
ModuleWireBytes wire_bytes(native_module()->wire_bytes());
|
||||
WireBytesRef name_ref =
|
||||
native_module()->module()->function_names.Lookup(wire_bytes, index());
|
||||
WireBytesRef name_ref = native_module()->module()->function_names.Lookup(
|
||||
wire_bytes, index(), VectorOf(native_module()->module()->export_table));
|
||||
WasmName name = wire_bytes.GetNameOrNull(name_ref);
|
||||
|
||||
const std::string& source_map_url = native_module()->module()->source_map_url;
|
||||
|
@ -162,8 +162,8 @@ static bool VerifyEvaluatorInterface(const WasmModule* raw_module,
|
||||
const ModuleWireBytes& bytes,
|
||||
ErrorThrower* thrower) {
|
||||
for (const WasmFunction& F : raw_module->functions) {
|
||||
WireBytesRef name_ref =
|
||||
raw_module->function_names.Lookup(bytes, F.func_index);
|
||||
WireBytesRef name_ref = raw_module->function_names.Lookup(
|
||||
bytes, F.func_index, VectorOf(raw_module->export_table));
|
||||
std::string name(bytes.start() + name_ref.offset(),
|
||||
bytes.start() + name_ref.end_offset());
|
||||
if (F.exported && name == "wasm_format") {
|
||||
|
@ -30,13 +30,14 @@ namespace wasm {
|
||||
// static
|
||||
const uint32_t WasmElemSegment::kNullIndex;
|
||||
|
||||
WireBytesRef DecodedFunctionNames::Lookup(const ModuleWireBytes& wire_bytes,
|
||||
uint32_t function_index) const {
|
||||
WireBytesRef DecodedFunctionNames::Lookup(
|
||||
const ModuleWireBytes& wire_bytes, uint32_t function_index,
|
||||
Vector<const WasmExport> export_table) const {
|
||||
base::MutexGuard lock(&mutex_);
|
||||
if (!function_names_) {
|
||||
function_names_.reset(new std::unordered_map<uint32_t, WireBytesRef>());
|
||||
DecodeFunctionNames(wire_bytes.start(), wire_bytes.end(),
|
||||
function_names_.get());
|
||||
function_names_.get(), export_table);
|
||||
}
|
||||
auto it = function_names_->find(function_index);
|
||||
if (it == function_names_->end()) return WireBytesRef();
|
||||
@ -176,8 +177,8 @@ WasmName ModuleWireBytes::GetNameOrNull(WireBytesRef ref) const {
|
||||
// Get a string stored in the module bytes representing a function name.
|
||||
WasmName ModuleWireBytes::GetNameOrNull(const WasmFunction* function,
|
||||
const WasmModule* module) const {
|
||||
return GetNameOrNull(
|
||||
module->function_names.Lookup(*this, function->func_index));
|
||||
return GetNameOrNull(module->function_names.Lookup(
|
||||
*this, function->func_index, VectorOf(module->export_table)));
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const WasmFunctionName& name) {
|
||||
|
@ -194,7 +194,8 @@ struct ModuleWireBytes;
|
||||
class V8_EXPORT_PRIVATE DecodedFunctionNames {
|
||||
public:
|
||||
WireBytesRef Lookup(const ModuleWireBytes& wire_bytes,
|
||||
uint32_t function_index) const;
|
||||
uint32_t function_index,
|
||||
Vector<const WasmExport> export_table) const;
|
||||
void AddForTesting(int function_index, WireBytesRef name);
|
||||
|
||||
private:
|
||||
|
@ -243,7 +243,7 @@ MaybeHandle<String> WasmModuleObject::GetFunctionNameOrNull(
|
||||
DCHECK_LT(func_index, module_object->module()->functions.size());
|
||||
wasm::WireBytesRef name = module_object->module()->function_names.Lookup(
|
||||
wasm::ModuleWireBytes(module_object->native_module()->wire_bytes()),
|
||||
func_index);
|
||||
func_index, VectorOf(module_object->module()->export_table));
|
||||
if (!name.is_set()) return {};
|
||||
return ExtractUtf8StringFromModuleBytes(isolate, module_object, name,
|
||||
kNoInternalize);
|
||||
@ -267,8 +267,8 @@ Vector<const uint8_t> WasmModuleObject::GetRawFunctionName(
|
||||
uint32_t func_index) {
|
||||
DCHECK_GT(module()->functions.size(), func_index);
|
||||
wasm::ModuleWireBytes wire_bytes(native_module()->wire_bytes());
|
||||
wasm::WireBytesRef name_ref =
|
||||
module()->function_names.Lookup(wire_bytes, func_index);
|
||||
wasm::WireBytesRef name_ref = module()->function_names.Lookup(
|
||||
wire_bytes, func_index, VectorOf(module()->export_table));
|
||||
wasm::WasmName name = wire_bytes.GetNameOrNull(name_ref);
|
||||
return Vector<const uint8_t>::cast(name);
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ Paused on 'debugger;'
|
||||
Number of frames: 5
|
||||
- [0] call_debugger
|
||||
- [1] func1
|
||||
- [2] func2
|
||||
- [2] main
|
||||
- [3] testFunction
|
||||
- [4]
|
||||
Finished!
|
||||
|
@ -1,4 +1,4 @@
|
||||
wasm-function[0]:0x22: RuntimeError: unreachable
|
||||
RuntimeError: unreachable
|
||||
at test-module (<anonymous>:wasm-function[0]:0x22)
|
||||
at test-module.main (<anonymous>:wasm-function[0]:0x22)
|
||||
at *%(basename)s:{NUMBER}:31
|
||||
|
@ -1,4 +1,4 @@
|
||||
wasm-function[0]:0x22: RuntimeError: unreachable
|
||||
RuntimeError: unreachable
|
||||
at <anonymous>:wasm-function[0]:0x22
|
||||
at main (<anonymous>:wasm-function[0]:0x22)
|
||||
at *%(basename)s:{NUMBER}:31
|
||||
|
@ -1,4 +1,4 @@
|
||||
RuntimeError: unreachable
|
||||
at test-module (<anonymous>:wasm-function[0]:0x22)
|
||||
at test-module.main (<anonymous>:wasm-function[0]:0x22)
|
||||
at *%(basename)s:{NUMBER}:27
|
||||
at test/mjsunit/mjsunit.js:*
|
||||
|
@ -1,4 +1,4 @@
|
||||
RuntimeError: unreachable
|
||||
at test-module (<anonymous>:wasm-function[0]:0x22)
|
||||
at test-module.main (<anonymous>:wasm-function[0]:0x22)
|
||||
at test/message/wasm-module-name-async.js:{NUMBER}:27
|
||||
at test/mjsunit/mjsunit.js:*
|
||||
|
@ -1,4 +1,4 @@
|
||||
RuntimeError: unreachable
|
||||
at <anonymous>:wasm-function[0]:0x22
|
||||
at main (<anonymous>:wasm-function[0]:0x22)
|
||||
at *%(basename)s:{NUMBER}:27
|
||||
at test/mjsunit/mjsunit.js:*
|
||||
|
@ -1,4 +1,4 @@
|
||||
RuntimeError: unreachable
|
||||
at <anonymous>:wasm-function[0]:0x22
|
||||
at main (<anonymous>:wasm-function[0]:0x22)
|
||||
at test/message/wasm-no-name-async.js:{NUMBER}:27
|
||||
at test/mjsunit/mjsunit.js:*
|
||||
|
@ -28,6 +28,6 @@ kExprEnd, // @21
|
||||
builder.addExport('main', 0);
|
||||
assertThrows(
|
||||
() => {builder.toModule()}, WebAssembly.CompileError,
|
||||
'WebAssembly.Module(): Compiling function #0 failed: type error in ' +
|
||||
'merge[0] (expected <bot>, got i32) @+57');
|
||||
'WebAssembly.Module(): Compiling function #0:\"main\" failed: type ' +
|
||||
'error in merge[0] (expected <bot>, got i32) @+57');
|
||||
})();
|
||||
|
@ -119,7 +119,7 @@ Error.prepareStackTrace = function(error, frames) {
|
||||
assertContains("out of bounds", e.message);
|
||||
verifyStack(e.stack, [
|
||||
// isWasm function line pos file offset funcIndex
|
||||
[ true, null, 0, 3, null, '0x91', 3],
|
||||
[ true, "mem_out_of_bounds", 0, 3, null, '0x91', 3],
|
||||
[ true, "call_mem_out_of_bounds", 0, 1, null, '0x97', 4],
|
||||
[ false, "testWasmMemOutOfBounds", 116, 0, "stack.js"],
|
||||
[ false, null, 128, 0, "stack.js"]
|
||||
|
Loading…
Reference in New Issue
Block a user