Chromium Code Reviews| Index: src/wasm/wasm-module.cc |
| diff --git a/src/wasm/wasm-module.cc b/src/wasm/wasm-module.cc |
| index e15b8d1f55318c7dcc8a51ad1746c06b4b8c3fc6..a2df5ee3df3f88d573bfd3554292e86e985bf7cc 100644 |
| --- a/src/wasm/wasm-module.cc |
| +++ b/src/wasm/wasm-module.cc |
| @@ -200,11 +200,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; |
| @@ -246,6 +247,57 @@ Handle<FixedArray> BuildFunctionTable(Isolate* isolate, WasmModule* module) { |
| return fixed; |
| } |
| +// 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 seconds part of this array. |
|
titzer
2016/04/22 13:21:08
s/seconds/second/
|
| +// After these N+1 integer entries, the second part begins, which holds a |
| +// concatenation of all function names. If a function is unnamed (not to be |
| +// confused with an empty name), then the corresponding integer entry contains |
| +// the negative distance to the next entry with a name. It points behind the |
| +// last integer entry if there are no more entries with names. |
| +// This allows to easily determine for each function the start of the next |
| +// function name, and hence the length of the function name. |
| +Handle<Object> BuildFunctionNamesArray(Isolate* isolate, WasmModule* module) { |
|
titzer
2016/04/22 13:21:08
Can we factor out the encoding and decoding logic
Clemens Hammacher
2016/04/22 14:38:40
OK, will work on that on Monday and then update th
|
| + 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_arr = |
| + isolate->factory()->NewByteArray(total_array_length_int, TENURED); |
| + func_names_arr->set_int(0, num_funcs_int); |
| + for (int func_index = 0; func_index != num_funcs_int; ++func_index) { |
|
titzer
2016/04/22 13:21:08
Would prefer a C++ foreach-loop with a separate in
Clemens Hammacher
2016/04/22 14:38:40
C++ foreach does not work, since we increase func_
|
| + WasmName name = module->GetNameOrNull(&module->functions[func_index]); |
| + if (name.name == nullptr) { |
| + // Find next function with a name, and store the negative distance to that |
| + // function. On the way, we also set all the entries inbetween. |
| + int next_func_with_name = func_index + 1; |
| + while ( |
| + next_func_with_name != num_funcs_int && |
| + module->GetNameOrNull(&module->functions[next_func_with_name]).name == |
| + nullptr) |
| + ++next_func_with_name; |
| + for (; func_index < next_func_with_name; ++func_index) |
| + func_names_arr->set_int(func_index + 1, |
| + func_index - next_func_with_name); |
| + --func_index; |
| + } else { |
| + func_names_arr->set(current_offset, |
| + reinterpret_cast<const byte*>(name.name), |
| + name.length); |
| + func_names_arr->set_int(func_index + 1, current_offset); |
| + current_offset += name.length; |
| + } |
| + } |
| + return func_names_arr; |
| +} |
| + |
| Handle<JSArrayBuffer> NewArrayBuffer(Isolate* isolate, size_t size, |
| byte** backing_store) { |
| if (size > (WasmModule::kMaxMemPages * WasmModule::kPageSize)) { |
| @@ -415,7 +467,7 @@ MaybeHandle<JSObject> WasmModule::Instantiate(Isolate* isolate, |
| // Allocate the instance and its JS counterpart. |
| //------------------------------------------------------------------------- |
| Handle<Map> map = factory->NewMap( |
| - JS_OBJECT_TYPE, |
| + JS_WASM_TYPE, |
| JSObject::kHeaderSize + kWasmModuleInternalFieldCount * kPointerSize); |
| WasmModuleInstance instance(this); |
| instance.context = isolate->native_context(); |
| @@ -582,6 +634,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 = BuildFunctionNamesArray(isolate, module_env.module); |
| + instance.js_object->SetInternalField(kWasmFunctionNamesArray, *arr); |
| + } |
| + |
| // Run the start function if one was specified. |
| if (this->start_function_index >= 0) { |
| HandleScope scope(isolate); |
| @@ -732,6 +793,42 @@ 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) { |
| + DCHECK(wasm->map()->instance_type() == JS_WASM_TYPE); |
| + 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. |
| + Handle<ByteArray> func_names_arr = |
| + Handle<ByteArray>::cast(func_names_arr_obj); |
| + uint32_t num_funcs = static_cast<uint32_t>(func_names_arr->get_int(0)); |
| + DCHECK(static_cast<int>(num_funcs) >= 0); |
| + if (func_index >= num_funcs) |
| + return wasm->GetIsolate()->factory()->undefined_value(); |
| + int offset = func_names_arr->get_int(func_index + 1); |
| + if (offset < 0) return wasm->GetIsolate()->factory()->undefined_value(); |
| + int next_offset = func_index == num_funcs - 1 |
| + ? func_names_arr->length() |
| + : func_names_arr->get_int(func_index + 2); |
| + if (next_offset < 0) { |
| + uint32_t next_func_index = func_index + 1 - next_offset; |
| + next_offset = next_func_index == num_funcs |
| + ? func_names_arr->length() |
| + : func_names_arr->get_int(next_func_index + 1); |
| + } |
| + DCHECK(next_offset >= 0 && next_offset <= func_names_arr->length()); |
| + DCHECK(next_offset >= offset); |
| + ScopedVector<byte> buffer(next_offset - offset); |
| + func_names_arr->get(offset, buffer.start(), next_offset - offset); |
| + MaybeHandle<Object> maybe_name = |
| + wasm->GetIsolate()->factory()->NewStringFromUtf8( |
| + Vector<const char>::cast(buffer)); |
| + if (maybe_name.is_null()) |
| + return wasm->GetIsolate()->factory()->undefined_value(); |
| + return maybe_name.ToHandleChecked(); |
| +} |
| + |
| } // namespace wasm |
| } // namespace internal |
| } // namespace v8 |