Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 003f622

Browse filesBrowse files
backesCommit Bot
authored andcommitted
[wasm] Implement toString of exported functions
We currently print asm.js functions converted to wasm as "function foo() { [native code] }", even though without asm to wasm translation we get the proper source code. This is an observable difference that should not be, and also foozzie finds this frequently in different variations. This CL makes us remember the start position (position of the "function" token) and end position (right behind the closing "}") of each function we transform to wasm. These offsets, together with the Script that contained the function, allows us to reconstruct the source code of the function for the {toString()} method. R=jkummerow@chromium.org Bug: chromium:667678 Change-Id: If22471cad4cefdfc67f6d1b8fda85aa0eeb411bd Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2016582 Commit-Queue: Clemens Backes <clemensb@chromium.org> Reviewed-by: Jakob Kummerow <jkummerow@chromium.org> Cr-Commit-Position: refs/heads/master@{#65972}
1 parent 91c0ef3 commit 003f622
Copy full SHA for 003f622

10 files changed

+82-35Lines changed: 82 additions & 35 deletions

File tree

Expand file treeCollapse file tree
Open diff view settings
Filter options
Expand file treeCollapse file tree
Open diff view settings
Collapse file

‎src/asmjs/asm-parser.cc‎

Copy file name to clipboardExpand all lines: src/asmjs/asm-parser.cc
+12-1Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -728,6 +728,9 @@ void AsmJsParser::ValidateFunctionTable() {
728728

729729
// 6.4 ValidateFunction
730730
void AsmJsParser::ValidateFunction() {
731+
// Remember position of the 'function' token as start position.
732+
size_t function_start_position = scanner_.Position();
733+
731734
EXPECT_TOKEN(TOK(function));
732735
if (!scanner_.IsGlobal()) {
733736
FAIL("Expected function name");
@@ -753,7 +756,8 @@ void AsmJsParser::ValidateFunction() {
753756
return_type_ = nullptr;
754757

755758
// Record start of the function, used as position for the stack check.
756-
current_function_builder_->SetAsmFunctionStartPosition(scanner_.Position());
759+
current_function_builder_->SetAsmFunctionStartPosition(
760+
function_start_position);
757761

758762
CachedVector<AsmType*> params(&cached_asm_type_p_vectors_);
759763
ValidateFunctionParams(&params);
@@ -778,6 +782,9 @@ void AsmJsParser::ValidateFunction() {
778782
// clang-format on
779783
RECURSE(ValidateStatement());
780784
}
785+
786+
size_t function_end_position = scanner_.Position() + 1;
787+
781788
EXPECT_TOKEN('}');
782789

783790
if (!last_statement_is_return) {
@@ -809,6 +816,10 @@ void AsmJsParser::ValidateFunction() {
809816
// End function
810817
current_function_builder_->Emit(kExprEnd);
811818

819+
// Emit function end position as the last position for this function.
820+
current_function_builder_->AddAsmWasmOffset(function_end_position,
821+
function_end_position);
822+
812823
if (current_function_builder_->GetPosition() > kV8MaxWasmFunctionSize) {
813824
FAIL("Size of function body exceeds internal limit");
814825
}
Collapse file

‎src/objects/js-objects.cc‎

Copy file name to clipboardExpand all lines: src/objects/js-objects.cc
+17Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5540,6 +5540,23 @@ Handle<String> JSFunction::ToString(Handle<JSFunction> function) {
55405540
return NativeCodeFunctionSourceString(shared_info);
55415541
}
55425542

5543+
// If this function was compiled from asm.js, use the recorded offset
5544+
// information.
5545+
if (shared_info->HasWasmExportedFunctionData()) {
5546+
Handle<WasmExportedFunctionData> function_data(
5547+
shared_info->wasm_exported_function_data(), isolate);
5548+
const wasm::WasmModule* module = function_data->instance().module();
5549+
if (is_asmjs_module(module)) {
5550+
std::pair<int, int> offsets =
5551+
module->asm_js_offset_information->GetFunctionOffsets(
5552+
function_data->function_index());
5553+
Handle<String> source(
5554+
String::cast(Script::cast(shared_info->script()).source()), isolate);
5555+
return isolate->factory()->NewSubString(source, offsets.first,
5556+
offsets.second);
5557+
}
5558+
}
5559+
55435560
if (shared_info->function_token_position() == kNoSourcePosition) {
55445561
// If the function token position isn't valid, return [native code] to
55455562
// ensure calling eval on the returned source code throws rather than
Collapse file

‎src/wasm/module-decoder.cc‎

Copy file name to clipboardExpand all lines: src/wasm/module-decoder.cc
+12-4Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2059,6 +2059,7 @@ AsmJsOffsetsResult DecodeAsmJsOffsets(Vector<const uint8_t> encoded_offsets) {
20592059
const byte* table_end = decoder.pc() + size;
20602060
uint32_t locals_size = decoder.consume_u32v("locals size");
20612061
int function_start_position = decoder.consume_u32v("function start pos");
2062+
int function_end_position = function_start_position;
20622063
int last_byte_offset = locals_size;
20632064
int last_asm_position = function_start_position;
20642065
std::vector<AsmJsOffsetEntry> func_asm_offsets;
@@ -2074,12 +2075,19 @@ AsmJsOffsetsResult DecodeAsmJsOffsets(Vector<const uint8_t> encoded_offsets) {
20742075
int to_number_position =
20752076
call_position + decoder.consume_i32v("to_number position delta");
20762077
last_asm_position = to_number_position;
2077-
func_asm_offsets.push_back(
2078-
{last_byte_offset, call_position, to_number_position});
2078+
if (decoder.pc() == table_end) {
2079+
// The last entry is the function end marker.
2080+
DCHECK_EQ(call_position, to_number_position);
2081+
function_end_position = call_position;
2082+
} else {
2083+
func_asm_offsets.push_back(
2084+
{last_byte_offset, call_position, to_number_position});
2085+
}
20792086
}
20802087
DCHECK_EQ(decoder.pc(), table_end);
2081-
functions.emplace_back(
2082-
AsmJsOffsetFunctionEntries{std::move(func_asm_offsets)});
2088+
functions.emplace_back(AsmJsOffsetFunctionEntries{
2089+
function_start_position, function_end_position,
2090+
std::move(func_asm_offsets)});
20832091
}
20842092
DCHECK(decoder.ok());
20852093
DCHECK(!decoder.more());
Collapse file

‎src/wasm/module-decoder.h‎

Copy file name to clipboardExpand all lines: src/wasm/module-decoder.h
+2Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ struct AsmJsOffsetEntry {
4040
int source_position_number_conversion;
4141
};
4242
struct AsmJsOffsetFunctionEntries {
43+
int start_offset;
44+
int end_offset;
4345
std::vector<AsmJsOffsetEntry> entries;
4446
};
4547
struct AsmJsOffsets {
Collapse file

‎src/wasm/module-instantiate.cc‎

Copy file name to clipboardExpand all lines: src/wasm/module-instantiate.cc
+9-19Lines changed: 9 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1456,25 +1456,15 @@ void InstanceBuilder::ProcessExports(Handle<WasmInstanceObject> instance) {
14561456

14571457
Handle<JSObject> exports_object;
14581458
MaybeHandle<String> single_function_name;
1459-
bool is_asm_js = false;
1460-
switch (module_->origin) {
1461-
case kWasmOrigin: {
1462-
// Create the "exports" object.
1463-
exports_object = isolate_->factory()->NewJSObjectWithNullProto();
1464-
break;
1465-
}
1466-
case kAsmJsSloppyOrigin:
1467-
case kAsmJsStrictOrigin: {
1468-
Handle<JSFunction> object_function = Handle<JSFunction>(
1469-
isolate_->native_context()->object_function(), isolate_);
1470-
exports_object = isolate_->factory()->NewJSObject(object_function);
1471-
single_function_name = isolate_->factory()->InternalizeUtf8String(
1472-
AsmJs::kSingleFunctionName);
1473-
is_asm_js = true;
1474-
break;
1475-
}
1476-
default:
1477-
UNREACHABLE();
1459+
bool is_asm_js = is_asmjs_module(module_);
1460+
if (is_asm_js) {
1461+
Handle<JSFunction> object_function = Handle<JSFunction>(
1462+
isolate_->native_context()->object_function(), isolate_);
1463+
exports_object = isolate_->factory()->NewJSObject(object_function);
1464+
single_function_name =
1465+
isolate_->factory()->InternalizeUtf8String(AsmJs::kSingleFunctionName);
1466+
} else {
1467+
exports_object = isolate_->factory()->NewJSObjectWithNullProto();
14781468
}
14791469
instance->set_exports_object(*exports_object);
14801470

Collapse file

‎src/wasm/wasm-module.cc‎

Copy file name to clipboardExpand all lines: src/wasm/wasm-module.cc
+23-10Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -119,16 +119,7 @@ AsmJsOffsetInformation::~AsmJsOffsetInformation() = default;
119119

120120
int AsmJsOffsetInformation::GetSourcePosition(int func_index, int byte_offset,
121121
bool is_at_number_conversion) {
122-
base::MutexGuard lock(&mutex_);
123-
DCHECK_EQ(encoded_offsets_ == nullptr, decoded_offsets_ != nullptr);
124-
125-
if (!decoded_offsets_) {
126-
AsmJsOffsetsResult result =
127-
wasm::DecodeAsmJsOffsets(encoded_offsets_.as_vector());
128-
decoded_offsets_ =
129-
std::make_unique<AsmJsOffsets>(std::move(result).value());
130-
encoded_offsets_.ReleaseData();
131-
}
122+
EnsureDecodedOffsets();
132123

133124
DCHECK_LE(0, func_index);
134125
DCHECK_GT(decoded_offsets_->functions.size(), func_index);
@@ -150,6 +141,28 @@ int AsmJsOffsetInformation::GetSourcePosition(int func_index, int byte_offset,
150141
: it->source_position_call;
151142
}
152143

144+
std::pair<int, int> AsmJsOffsetInformation::GetFunctionOffsets(int func_index) {
145+
EnsureDecodedOffsets();
146+
147+
DCHECK_LE(0, func_index);
148+
DCHECK_GT(decoded_offsets_->functions.size(), func_index);
149+
AsmJsOffsetFunctionEntries& function_info =
150+
decoded_offsets_->functions[func_index];
151+
152+
return {function_info.start_offset, function_info.end_offset};
153+
}
154+
155+
void AsmJsOffsetInformation::EnsureDecodedOffsets() {
156+
base::MutexGuard mutex_guard(&mutex_);
157+
DCHECK_EQ(encoded_offsets_ == nullptr, decoded_offsets_ != nullptr);
158+
159+
if (decoded_offsets_) return;
160+
AsmJsOffsetsResult result =
161+
wasm::DecodeAsmJsOffsets(encoded_offsets_.as_vector());
162+
decoded_offsets_ = std::make_unique<AsmJsOffsets>(std::move(result).value());
163+
encoded_offsets_.ReleaseData();
164+
}
165+
153166
// Get a string stored in the module bytes representing a name.
154167
WasmName ModuleWireBytes::GetNameOrNull(WireBytesRef ref) const {
155168
if (!ref.is_set()) return {nullptr, 0}; // no name.
Collapse file

‎src/wasm/wasm-module.h‎

Copy file name to clipboardExpand all lines: src/wasm/wasm-module.h
+4Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,11 @@ class V8_EXPORT_PRIVATE AsmJsOffsetInformation {
203203
int GetSourcePosition(int func_index, int byte_offset,
204204
bool is_at_number_conversion);
205205

206+
std::pair<int, int> GetFunctionOffsets(int func_index);
207+
206208
private:
209+
void EnsureDecodedOffsets();
210+
207211
// The offset information table is decoded lazily, hence needs to be
208212
// protected against concurrent accesses.
209213
// Exactly one of the two fields below will be set at a time.
Collapse file

‎src/wasm/wasm-objects.cc‎

Copy file name to clipboardExpand all lines: src/wasm/wasm-objects.cc
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1800,6 +1800,7 @@ Handle<WasmExportedFunction> WasmExportedFunction::New(
18001800
DCHECK_EQ(is_asm_js_module, js_function->IsConstructor());
18011801
js_function->shared().set_length(arity);
18021802
js_function->shared().set_internal_formal_parameter_count(arity);
1803+
js_function->shared().set_script(instance->module_object().script());
18031804
return Handle<WasmExportedFunction>::cast(js_function);
18041805
}
18051806

Collapse file

‎test/mjsunit/wasm/asm-wasm-names.js‎

Copy file name to clipboardExpand all lines: test/mjsunit/wasm/asm-wasm-names.js
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,4 @@ function Module(stdlib, foreign, buffer) {
1313
var func = Module({}, {}, new ArrayBuffer(65536)).bar;
1414
assertEquals("Module", Module.name);
1515
assertEquals("foo", func.name);
16+
assertEquals("function foo() {}", func.toString());
Collapse file

‎test/mjsunit/wasm/asm-wasm-stack.js‎

Copy file name to clipboardExpand all lines: test/mjsunit/wasm/asm-wasm-stack.js
+1-1Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ function generateOverflowWasmFromAsmJs() {
148148
}
149149
assertInstanceof(e, RangeError, 'RangeError should have been thrown');
150150
checkTopFunctionsOnCallsites(e, [
151-
['f', 133, 13], // --
151+
['f', 133, 3], // --
152152
['f', 135, 12], // --
153153
['f', 135, 12], // --
154154
['f', 135, 12] // --

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.