[wasm] Store function names in the wasm object

We now store the wasm object and the function index in the
deoptimization data of the wasm Code object, and store an array with
function names in the wasm object.

This will make both the wasm module as well as the respective function
name available from the code object.

Tests will follow in https://codereview.chromium.org/1916403002.

R=titzer@chromium.org, mstarzinger@chromium.org, machenbach@chromium.org

Review-Url: https://codereview.chromium.org/1912103002
Cr-Commit-Position: refs/heads/master@{#35905}
This commit is contained in:
clemensh 2016-04-29 05:24:58 -07:00 committed by Commit bot
parent 5749d710bc
commit 9fd2650ae0
10 changed files with 209 additions and 14 deletions

View File

@ -1425,6 +1425,8 @@ source_set("v8_base") {
"src/wasm/switch-logic.h",
"src/wasm/wasm-external-refs.cc",
"src/wasm/wasm-external-refs.h",
"src/wasm/wasm-function-name-table.cc",
"src/wasm/wasm-function-name-table.h",
"src/wasm/wasm-js.cc",
"src/wasm/wasm-js.h",
"src/wasm/wasm-macro-gen.h",

View File

@ -2977,7 +2977,24 @@ Handle<Code> CompileWasmFunction(wasm::ErrorThrower* thrower, Isolate* isolate,
}
buffer.Dispose();
if (!code.is_null()) {
DCHECK(code->deoptimization_data() == nullptr ||
code->deoptimization_data()->length() == 0);
Handle<FixedArray> deopt_data =
isolate->factory()->NewFixedArray(2, TENURED);
if (!module_env->instance->js_object.is_null()) {
deopt_data->set(0, *module_env->instance->js_object);
deopt_data->set(1, Smi::FromInt(function->func_index));
} else if (func_name.start() != nullptr) {
MaybeHandle<String> maybe_name =
isolate->factory()->NewStringFromUtf8(func_name);
if (!maybe_name.is_null())
deopt_data->set(0, *maybe_name.ToHandleChecked());
}
deopt_data->set_length(2);
code->set_deoptimization_data(*deopt_data);
RecordFunctionCompilation(
Logger::FUNCTION_TAG, &info, "WASM_function", function->func_index,
module_env->module->GetName(function->name_offset,

View File

@ -3906,7 +3906,6 @@ void StringCharacterStream::VisitTwoByteString(
int ByteArray::Size() { return RoundUp(length() + kHeaderSize, kPointerSize); }
byte ByteArray::get(int index) {
DCHECK(index >= 0 && index < this->length());
return READ_BYTE_FIELD(this, kHeaderSize + index * kCharSize);
@ -3918,12 +3917,29 @@ void ByteArray::set(int index, byte value) {
WRITE_BYTE_FIELD(this, kHeaderSize + index * kCharSize, value);
}
void ByteArray::copy_in(int index, const byte* buffer, int length) {
DCHECK(index >= 0 && length >= 0 && index + length >= index &&
index + length <= this->length());
byte* dst_addr = FIELD_ADDR(this, kHeaderSize + index * kCharSize);
memcpy(dst_addr, buffer, length);
}
void ByteArray::copy_out(int index, byte* buffer, int length) {
DCHECK(index >= 0 && length >= 0 && index + length >= index &&
index + length <= this->length());
const byte* src_addr = FIELD_ADDR(this, kHeaderSize + index * kCharSize);
memcpy(buffer, src_addr, length);
}
int ByteArray::get_int(int index) {
DCHECK(index >= 0 && (index * kIntSize) < this->length());
DCHECK(index >= 0 && index < this->length() / kIntSize);
return READ_INT_FIELD(this, kHeaderSize + index * kIntSize);
}
void ByteArray::set_int(int index, int value) {
DCHECK(index >= 0 && index < this->length() / kIntSize);
WRITE_INT_FIELD(this, kHeaderSize + index * kIntSize, value);
}
ByteArray* ByteArray::FromDataStartAddress(Address address) {
DCHECK_TAG_ALIGNED(address);

View File

@ -4394,8 +4394,13 @@ class ByteArray: public FixedArrayBase {
inline byte get(int index);
inline void set(int index, byte value);
// Copy in / copy out whole byte slices.
inline void copy_out(int index, byte* buffer, int length);
inline void copy_in(int index, const byte* buffer, int length);
// Treat contents as an int array.
inline int get_int(int index);
inline void set_int(int index, int value);
static int SizeFor(int length) {
return OBJECT_POINTER_ALIGN(kHeaderSize + length);

View File

@ -1137,8 +1137,6 @@
'version.h',
'vm-state-inl.h',
'vm-state.h',
'wasm/switch-logic.h',
'wasm/switch-logic.cc',
'wasm/asm-wasm-builder.cc',
'wasm/asm-wasm-builder.h',
'wasm/ast-decoder.cc',
@ -1146,11 +1144,15 @@
'wasm/decoder.h',
'wasm/encoder.cc',
'wasm/encoder.h',
'wasm/wasm-external-refs.cc',
'wasm/wasm-external-refs.h',
'wasm/leb-helper.h',
'wasm/module-decoder.cc',
'wasm/module-decoder.h',
'wasm/switch-logic.h',
'wasm/switch-logic.cc',
'wasm/wasm-external-refs.cc',
'wasm/wasm-external-refs.h',
'wasm/wasm-function-name-table.cc',
'wasm/wasm-function-name-table.h',
'wasm/wasm-js.cc',
'wasm/wasm-js.h',
'wasm/wasm-macro-gen.h',

View File

@ -0,0 +1,71 @@
// 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/wasm-function-name-table.h"
#include "src/wasm/wasm-module.h"
namespace v8 {
namespace internal {
namespace wasm {
// Build an array with all function names. If there are N functions in the
// module, then the first (kIntSize * (N+1)) bytes are integer entries.
// The first integer entry encodes the number of functions in the module.
// The entries 1 to N contain offsets into the second part of this array.
// After these N+1 integer entries, the second part begins, which holds a
// concatenation of all function names.
//
// Returns undefined if the array length would not fit in an integer value
Handle<Object> BuildFunctionNamesTable(Isolate* isolate, WasmModule* module) {
uint64_t func_names_length = 0;
for (auto& func : module->functions) func_names_length += func.name_length;
int num_funcs_int = static_cast<int>(module->functions.size());
int current_offset = (num_funcs_int + 1) * kIntSize;
uint64_t total_array_length = current_offset + func_names_length;
int total_array_length_int = static_cast<int>(total_array_length);
// Check for overflow. Just skip function names if it happens.
if (total_array_length_int != total_array_length || num_funcs_int < 0 ||
num_funcs_int != module->functions.size())
return isolate->factory()->undefined_value();
Handle<ByteArray> func_names_array =
isolate->factory()->NewByteArray(total_array_length_int, TENURED);
if (func_names_array.is_null()) return isolate->factory()->undefined_value();
func_names_array->set_int(0, num_funcs_int);
int func_index = 0;
for (WasmFunction& fun : module->functions) {
WasmName name = module->GetNameOrNull(&fun);
func_names_array->copy_in(current_offset,
reinterpret_cast<const byte*>(name.start()),
name.length());
func_names_array->set_int(func_index + 1, current_offset);
current_offset += name.length();
++func_index;
}
return func_names_array;
}
Handle<Object> GetWasmFunctionNameFromTable(Handle<ByteArray> func_names_array,
uint32_t func_index) {
uint32_t num_funcs = static_cast<uint32_t>(func_names_array->get_int(0));
DCHECK(static_cast<int>(num_funcs) >= 0);
auto undefined = [&func_names_array]() -> Handle<Object> {
return func_names_array->GetIsolate()->factory()->undefined_value();
};
if (func_index >= num_funcs) return undefined();
int offset = func_names_array->get_int(func_index + 1);
int next_offset = func_index == num_funcs - 1
? func_names_array->length()
: func_names_array->get_int(func_index + 2);
ScopedVector<byte> buffer(next_offset - offset);
func_names_array->copy_out(offset, buffer.start(), next_offset - offset);
MaybeHandle<Object> maybe_name =
func_names_array->GetIsolate()->factory()->NewStringFromUtf8(
Vector<const char>::cast(buffer));
return maybe_name.is_null() ? undefined() : maybe_name.ToHandleChecked();
}
} // namespace wasm
} // namespace internal
} // namespace v8

View File

@ -0,0 +1,30 @@
// 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.
#ifndef V8_WASM_FUNCTION_NAME_TABLE_H_
#define V8_WASM_FUNCTION_NAME_TABLE_H_
#include "src/handles.h"
#include "src/objects.h"
namespace v8 {
namespace internal {
namespace wasm {
// Forward declarations for some WASM data structures.
struct WasmModule;
// Encode all function names of the WasmModule into one ByteArray.
Handle<Object> BuildFunctionNamesTable(Isolate* isolate, WasmModule* module);
// Extract the function name for the given func_index from the wasm module.
// Returns undefined if the function index is invalid.
Handle<Object> GetWasmFunctionNameFromTable(Handle<ByteArray> wasm_names_table,
uint32_t func_index);
} // namespace wasm
} // namespace internal
} // namespace v8
#endif // V8_WASM_FUNCTION_NAME_TABLE_H_

View File

@ -11,6 +11,7 @@
#include "src/wasm/ast-decoder.h"
#include "src/wasm/module-decoder.h"
#include "src/wasm/wasm-function-name-table.h"
#include "src/wasm/wasm-module.h"
#include "src/wasm/wasm-result.h"
@ -201,11 +202,12 @@ class WasmLinker {
namespace {
// Internal constants for the layout of the module object.
const int kWasmModuleInternalFieldCount = 4;
const int kWasmModuleInternalFieldCount = 5;
const int kWasmModuleFunctionTable = 0;
const int kWasmModuleCodeTable = 1;
const int kWasmMemArrayBuffer = 2;
const int kWasmGlobalsArrayBuffer = 3;
const int kWasmFunctionNamesArray = 4;
size_t AllocateGlobalsOffsets(std::vector<WasmGlobal>& globals) {
uint32_t offset = 0;
@ -630,6 +632,15 @@ MaybeHandle<JSObject> WasmModule::Instantiate(Isolate* isolate,
}
}
//-------------------------------------------------------------------------
// Attach an array with function names and an array with offsets into that
// first array.
//-------------------------------------------------------------------------
{
Handle<Object> arr = BuildFunctionNamesTable(isolate, module_env.module);
instance.js_object->SetInternalField(kWasmFunctionNamesArray, *arr);
}
if (FLAG_print_wasm_code_size)
printf("Total generated wasm code: %u bytes\n", total_code_size);
@ -783,6 +794,16 @@ int32_t CompileAndRunWasmModule(Isolate* isolate, WasmModule* module) {
thrower.Error("WASM.compileRun() failed: Return value should be number");
return -1;
}
Handle<Object> GetWasmFunctionName(Handle<JSObject> wasm, uint32_t func_index) {
Handle<Object> func_names_arr_obj = handle(
wasm->GetInternalField(kWasmFunctionNamesArray), wasm->GetIsolate());
if (func_names_arr_obj->IsUndefined())
return func_names_arr_obj; // Return undefined.
return GetWasmFunctionNameFromTable(
Handle<ByteArray>::cast(func_names_arr_obj), func_index);
}
} // namespace wasm
} // namespace internal
} // namespace v8

View File

@ -195,6 +195,11 @@ struct WasmModule {
static_cast<int>(length)};
}
// Get a string stored in the module bytes representing a function name.
WasmName GetName(WasmFunction* function) const {
return GetName(function->name_offset, function->name_length);
}
// Get a string stored in the module bytes representing a name.
WasmName GetNameOrNull(uint32_t offset, uint32_t length) const {
if (length == 0) return {NULL, 0}; // no name.
@ -204,6 +209,11 @@ struct WasmModule {
static_cast<int>(length)};
}
// Get a string stored in the module bytes representing a function name.
WasmName GetNameOrNull(WasmFunction* function) const {
return GetNameOrNull(function->name_offset, function->name_length);
}
// Checks the given offset range is contained within the module bytes.
bool BoundsCheck(uint32_t start, uint32_t end) const {
size_t size = module_end - module_start;
@ -321,6 +331,11 @@ int32_t CompileAndRunWasmModule(Isolate* isolate, const byte* module_start,
// given decoded module.
int32_t CompileAndRunWasmModule(Isolate* isolate, WasmModule* module);
// Extract a function name from the given wasm object.
// Returns undefined if the function is unnamed or the function index is
// invalid.
Handle<Object> GetWasmFunctionName(Handle<JSObject> wasm, uint32_t func_index);
} // namespace wasm
} // namespace internal
} // namespace v8

View File

@ -487,13 +487,29 @@ class WasmFunctionCompiler : public HandleAndZoneScope,
Code::ComputeFlags(Code::WASM_FUNCTION));
v8::base::SmartPointer<CompilationJob> job(Pipeline::NewWasmCompilationJob(
&info, graph(), desc, &source_position_table_));
Handle<Code> code = Handle<Code>::null();
if (job->OptimizeGraph() == CompilationJob::SUCCEEDED &&
job->GenerateCode() == CompilationJob::SUCCEEDED) {
code = info.code();
if (job->OptimizeGraph() != CompilationJob::SUCCEEDED ||
job->GenerateCode() != CompilationJob::SUCCEEDED)
return Handle<Code>::null();
Handle<Code> code = info.code();
// Length is always 2, since usually <wasm_obj, func_index> is stored in the
// deopt data. Here, we store <func_name, undef> instead.
DCHECK(code->deoptimization_data() == nullptr ||
code->deoptimization_data()->length() == 0);
Handle<FixedArray> deopt_data =
isolate()->factory()->NewFixedArray(2, TENURED);
if (debug_name_.start() != nullptr) {
MaybeHandle<String> maybe_name =
isolate()->factory()->NewStringFromUtf8(debug_name_, TENURED);
if (!maybe_name.is_null())
deopt_data->set(0, *maybe_name.ToHandleChecked());
}
deopt_data->set_length(2);
code->set_deoptimization_data(*deopt_data);
#ifdef ENABLE_DISASSEMBLER
if (!code.is_null() && FLAG_print_opt_code) {
if (FLAG_print_opt_code) {
OFStream os(stdout);
code->Disassemble("wasm code", os);
}