Commit 21a85c4a authored by clemensh's avatar clemensh Committed by Commit bot

[wasm] Always provide a wasm instance object at runtime

When executing wasm code for testing, we did not create a
WasmInstanceObject and link it to the generated code. This required
some special handling at runtime (mainly for stack trace generation).
This CL always provides the WasmInstanceObject, such that e.g. function
names can be resolved the usual way.
The module bytes referenced by the WasmCompiledModule linked with the
WasmInstanceObject do not hold a valid wasm module yet. Instead, we
just add the bytes we need, and make the objects in WasmModule point to
those bytes (currently only used for function names). Those bytes will
not be parsed at runtime anyway.

R=titzer@chromium.org
CC=jgruber@chromium.org
BUG=v8:5620

Review-Url: https://codereview.chromium.org/2551053002
Cr-Commit-Position: refs/heads/master@{#41809}
parent 34d2402a
...@@ -1558,10 +1558,11 @@ Address WasmFrame::GetCallerStackPointer() const { ...@@ -1558,10 +1558,11 @@ Address WasmFrame::GetCallerStackPointer() const {
return fp() + ExitFrameConstants::kCallerSPOffset; return fp() + ExitFrameConstants::kCallerSPOffset;
} }
Object* WasmFrame::wasm_instance() const { WasmInstanceObject* WasmFrame::wasm_instance() const {
Object* ret = wasm::GetOwningWasmInstance(LookupCode()); Object* ret = wasm::GetOwningWasmInstance(LookupCode());
if (ret == nullptr) ret = isolate()->heap()->undefined_value(); // This is a live stack frame, there must be a live wasm instance available.
return ret; DCHECK_NOT_NULL(ret);
return WasmInstanceObject::cast(ret);
} }
uint32_t WasmFrame::function_index() const { uint32_t WasmFrame::function_index() const {
...@@ -1577,7 +1578,7 @@ Script* WasmFrame::script() const { ...@@ -1577,7 +1578,7 @@ Script* WasmFrame::script() const {
int WasmFrame::position() const { int WasmFrame::position() const {
int position = StandardFrame::position(); int position = StandardFrame::position();
if (wasm::WasmIsAsmJs(wasm_instance(), isolate())) { if (wasm_instance()->get_compiled_module()->is_asm_js()) {
Handle<WasmCompiledModule> compiled_module( Handle<WasmCompiledModule> compiled_module(
WasmInstanceObject::cast(wasm_instance())->get_compiled_module(), WasmInstanceObject::cast(wasm_instance())->get_compiled_module(),
isolate()); isolate());
......
...@@ -29,9 +29,10 @@ int JSCallerSavedCode(int n); ...@@ -29,9 +29,10 @@ int JSCallerSavedCode(int n);
// Forward declarations. // Forward declarations.
class ExternalCallbackScope; class ExternalCallbackScope;
class Isolate;
class StackFrameIteratorBase; class StackFrameIteratorBase;
class ThreadLocalTop; class ThreadLocalTop;
class Isolate; class WasmInstanceObject;
class InnerPointerToCodeCache { class InnerPointerToCodeCache {
public: public:
...@@ -1109,7 +1110,7 @@ class WasmFrame : public StandardFrame { ...@@ -1109,7 +1110,7 @@ class WasmFrame : public StandardFrame {
Code* unchecked_code() const override; Code* unchecked_code() const override;
// Accessors. // Accessors.
Object* wasm_instance() const; WasmInstanceObject* wasm_instance() const;
uint32_t function_index() const; uint32_t function_index() const;
Script* script() const override; Script* script() const override;
int position() const override; int position() const override;
......
...@@ -512,19 +512,15 @@ Handle<Object> Isolate::CaptureSimpleStackTrace(Handle<JSReceiver> error_object, ...@@ -512,19 +512,15 @@ Handle<Object> Isolate::CaptureSimpleStackTrace(Handle<JSReceiver> error_object,
case StackFrame::WASM: { case StackFrame::WASM: {
WasmFrame* wasm_frame = WasmFrame::cast(frame); WasmFrame* wasm_frame = WasmFrame::cast(frame);
Handle<Object> instance(wasm_frame->wasm_instance(), this); Handle<WasmInstanceObject> instance(wasm_frame->wasm_instance(), this);
const int wasm_function_index = wasm_frame->function_index(); const int wasm_function_index = wasm_frame->function_index();
Code* code = wasm_frame->unchecked_code(); Code* code = wasm_frame->unchecked_code();
Handle<AbstractCode> abstract_code(AbstractCode::cast(code), this); Handle<AbstractCode> abstract_code(AbstractCode::cast(code), this);
const int offset = const int offset =
static_cast<int>(wasm_frame->pc() - code->instruction_start()); static_cast<int>(wasm_frame->pc() - code->instruction_start());
// TODO(wasm): The wasm object returned by the WasmFrame should always
// be a wasm object.
DCHECK(wasm::IsWasmInstance(*instance) || instance->IsUndefined(this));
int flags = 0; int flags = 0;
if (wasm::WasmIsAsmJs(*instance, this)) { if (instance->get_compiled_module()->is_asm_js()) {
flags |= FrameArray::kIsAsmJsWasmFrame; flags |= FrameArray::kIsAsmJsWasmFrame;
if (wasm_frame->at_to_number_conversion()) { if (wasm_frame->at_to_number_conversion()) {
flags |= FrameArray::kAsmJsAtNumberConversion; flags |= FrameArray::kAsmJsAtNumberConversion;
...@@ -708,9 +704,10 @@ class CaptureStackTraceHelper { ...@@ -708,9 +704,10 @@ class CaptureStackTraceHelper {
factory()->NewJSObject(isolate_->object_function()); factory()->NewJSObject(isolate_->object_function());
if (!function_key_.is_null()) { if (!function_key_.is_null()) {
Handle<String> name = wasm::GetWasmFunctionName( Handle<WasmCompiledModule> compiled_module(
isolate_, handle(frame->wasm_instance(), isolate_), frame->wasm_instance()->get_compiled_module(), isolate_);
frame->function_index()); Handle<String> name = WasmCompiledModule::GetFunctionName(
isolate_, compiled_module, frame->function_index());
JSObject::AddProperty(stack_frame, function_key_, name, NONE); JSObject::AddProperty(stack_frame, function_key_, name, NONE);
} }
// Encode the function index as line number (1-based). // Encode the function index as line number (1-based).
......
...@@ -659,7 +659,8 @@ Handle<Object> WasmStackFrame::GetFunctionName() { ...@@ -659,7 +659,8 @@ Handle<Object> WasmStackFrame::GetFunctionName() {
Handle<WasmCompiledModule> compiled_module( Handle<WasmCompiledModule> compiled_module(
Handle<WasmInstanceObject>::cast(wasm_instance_)->get_compiled_module(), Handle<WasmInstanceObject>::cast(wasm_instance_)->get_compiled_module(),
isolate_); isolate_);
if (!WasmCompiledModule::GetFunctionName(compiled_module, wasm_func_index_) if (!WasmCompiledModule::GetFunctionNameOrNull(isolate_, compiled_module,
wasm_func_index_)
.ToHandle(&name)) { .ToHandle(&name)) {
name = isolate_->factory()->null_value(); name = isolate_->factory()->null_value();
} }
......
...@@ -526,11 +526,11 @@ RUNTIME_FUNCTION(Runtime_GetFrameDetails) { ...@@ -526,11 +526,11 @@ RUNTIME_FUNCTION(Runtime_GetFrameDetails) {
details->set(kFrameDetailsFrameIdIndex, *frame_id); details->set(kFrameDetailsFrameIdIndex, *frame_id);
// Add the function name. // Add the function name.
Handle<Object> wasm_instance_or_undef(it.wasm_frame()->wasm_instance(), Handle<WasmCompiledModule> compiled_module(
isolate); it.wasm_frame()->wasm_instance()->get_compiled_module(), isolate);
int func_index = it.wasm_frame()->function_index(); int func_index = it.wasm_frame()->function_index();
Handle<String> func_name = Handle<String> func_name = WasmCompiledModule::GetFunctionName(
wasm::GetWasmFunctionName(isolate, wasm_instance_or_undef, func_index); isolate, compiled_module, func_index);
details->set(kFrameDetailsFunctionIndex, *func_name); details->set(kFrameDetailsFunctionIndex, *func_name);
// Add the script wrapper // Add the script wrapper
...@@ -549,14 +549,10 @@ RUNTIME_FUNCTION(Runtime_GetFrameDetails) { ...@@ -549,14 +549,10 @@ RUNTIME_FUNCTION(Runtime_GetFrameDetails) {
// position, such that together with the script it uniquely identifies the // position, such that together with the script it uniquely identifies the
// position. // position.
Handle<Object> positionValue; Handle<Object> positionValue;
if (position != kNoSourcePosition && if (position != kNoSourcePosition) {
!wasm_instance_or_undef->IsUndefined(isolate)) {
int translated_position = position; int translated_position = position;
if (!wasm::WasmIsAsmJs(*wasm_instance_or_undef, isolate)) { // No further translation needed for asm.js modules.
Handle<WasmCompiledModule> compiled_module( if (!compiled_module->is_asm_js()) {
WasmInstanceObject::cast(*wasm_instance_or_undef)
->get_compiled_module(),
isolate);
translated_position += translated_position +=
wasm::GetFunctionCodeOffset(compiled_module, func_index); wasm::GetFunctionCodeOffset(compiled_module, func_index);
} }
......
...@@ -119,6 +119,9 @@ class Vector { ...@@ -119,6 +119,9 @@ class Vector {
return Vector<T>(start_ + offset, length_ - offset); return Vector<T>(start_ + offset, length_ - offset);
} }
// Implicit conversion from Vector<T> to Vector<const T>.
inline operator Vector<const T>() { return Vector<const T>::cast(*this); }
// Factory method for creating empty vectors. // Factory method for creating empty vectors.
static Vector<T> empty() { return Vector<T>(NULL, 0); } static Vector<T> empty() { return Vector<T>(NULL, 0); }
......
...@@ -47,20 +47,6 @@ byte* raw_buffer_ptr(MaybeHandle<JSArrayBuffer> buffer, int offset) { ...@@ -47,20 +47,6 @@ byte* raw_buffer_ptr(MaybeHandle<JSArrayBuffer> buffer, int offset) {
return static_cast<byte*>(buffer.ToHandleChecked()->backing_store()) + offset; return static_cast<byte*>(buffer.ToHandleChecked()->backing_store()) + offset;
} }
MaybeHandle<String> ExtractStringFromModuleBytes(
Isolate* isolate, Handle<WasmCompiledModule> compiled_module,
uint32_t offset, uint32_t size) {
// TODO(wasm): cache strings from modules if it's a performance win.
Handle<SeqOneByteString> module_bytes = compiled_module->module_bytes();
DCHECK_GE(module_bytes->length(), offset);
DCHECK_GE(module_bytes->length() - offset, size);
Address raw = module_bytes->GetCharsAddress() + offset;
if (!unibrow::Utf8::Validate(reinterpret_cast<const byte*>(raw), size))
return {}; // UTF8 decoding error for name.
return isolate->factory()->NewStringFromUtf8SubString(
module_bytes, static_cast<int>(offset), static_cast<int>(size));
}
void ReplaceReferenceInCode(Handle<Code> code, Handle<Object> old_ref, void ReplaceReferenceInCode(Handle<Code> code, Handle<Object> old_ref,
Handle<Object> new_ref) { Handle<Object> new_ref) {
for (RelocIterator it(*code, 1 << RelocInfo::EMBEDDED_OBJECT); !it.done(); for (RelocIterator it(*code, 1 << RelocInfo::EMBEDDED_OBJECT); !it.done();
...@@ -802,7 +788,7 @@ WasmInstanceObject* wasm::GetOwningWasmInstance(Code* code) { ...@@ -802,7 +788,7 @@ WasmInstanceObject* wasm::GetOwningWasmInstance(Code* code) {
DCHECK_NOT_NULL(deopt_data); DCHECK_NOT_NULL(deopt_data);
DCHECK(deopt_data->length() == 2); DCHECK(deopt_data->length() == 2);
Object* weak_link = deopt_data->get(0); Object* weak_link = deopt_data->get(0);
if (!weak_link->IsWeakCell()) return nullptr; DCHECK(weak_link->IsWeakCell());
WeakCell* cell = WeakCell::cast(weak_link); WeakCell* cell = WeakCell::cast(weak_link);
if (!cell->value()) return nullptr; if (!cell->value()) return nullptr;
return WasmInstanceObject::cast(cell->value()); return WasmInstanceObject::cast(cell->value());
...@@ -1521,15 +1507,17 @@ class WasmInstanceBuilder { ...@@ -1521,15 +1507,17 @@ class WasmInstanceBuilder {
WasmImport& import = module_->import_table[index]; WasmImport& import = module_->import_table[index];
Handle<String> module_name; Handle<String> module_name;
MaybeHandle<String> maybe_module_name = ExtractStringFromModuleBytes( MaybeHandle<String> maybe_module_name =
isolate_, compiled_module_, import.module_name_offset, WasmCompiledModule::ExtractUtf8StringFromModuleBytes(
import.module_name_length); isolate_, compiled_module_, import.module_name_offset,
import.module_name_length);
if (!maybe_module_name.ToHandle(&module_name)) return -1; if (!maybe_module_name.ToHandle(&module_name)) return -1;
Handle<String> import_name; Handle<String> import_name;
MaybeHandle<String> maybe_import_name = ExtractStringFromModuleBytes( MaybeHandle<String> maybe_import_name =
isolate_, compiled_module_, import.field_name_offset, WasmCompiledModule::ExtractUtf8StringFromModuleBytes(
import.field_name_length); isolate_, compiled_module_, import.field_name_offset,
import.field_name_length);
if (!maybe_import_name.ToHandle(&import_name)) return -1; if (!maybe_import_name.ToHandle(&import_name)) return -1;
MaybeHandle<Object> result = MaybeHandle<Object> result =
...@@ -1752,8 +1740,8 @@ class WasmInstanceBuilder { ...@@ -1752,8 +1740,8 @@ class WasmInstanceBuilder {
// can skip duplicates). // can skip duplicates).
for (auto exp : base::Reversed(module_->export_table)) { for (auto exp : base::Reversed(module_->export_table)) {
Handle<String> name = Handle<String> name =
ExtractStringFromModuleBytes(isolate_, compiled_module_, WasmCompiledModule::ExtractUtf8StringFromModuleBytes(
exp.name_offset, exp.name_length) isolate_, compiled_module_, exp.name_offset, exp.name_length)
.ToHandleChecked(); .ToHandleChecked();
switch (exp.kind) { switch (exp.kind) {
case kExternalFunction: { case kExternalFunction: {
...@@ -1769,7 +1757,7 @@ class WasmInstanceBuilder { ...@@ -1769,7 +1757,7 @@ class WasmInstanceBuilder {
MaybeHandle<String> func_name; MaybeHandle<String> func_name;
if (module_->origin == kAsmJsOrigin) { if (module_->origin == kAsmJsOrigin) {
// For modules arising from asm.js, honor the names section. // For modules arising from asm.js, honor the names section.
func_name = ExtractStringFromModuleBytes( func_name = WasmCompiledModule::ExtractUtf8StringFromModuleBytes(
isolate_, compiled_module_, function.name_offset, isolate_, compiled_module_, function.name_offset,
function.name_length) function.name_length)
.ToHandleChecked(); .ToHandleChecked();
...@@ -1936,10 +1924,11 @@ class WasmInstanceBuilder { ...@@ -1936,10 +1924,11 @@ class WasmInstanceBuilder {
MaybeHandle<String> func_name; MaybeHandle<String> func_name;
if (module_->origin == kAsmJsOrigin) { if (module_->origin == kAsmJsOrigin) {
// For modules arising from asm.js, honor the names section. // For modules arising from asm.js, honor the names section.
func_name = ExtractStringFromModuleBytes( func_name =
isolate_, compiled_module_, WasmCompiledModule::ExtractUtf8StringFromModuleBytes(
function->name_offset, function->name_length) isolate_, compiled_module_, function->name_offset,
.ToHandleChecked(); function->name_length)
.ToHandleChecked();
} }
Handle<WasmExportedFunction> js_function = Handle<WasmExportedFunction> js_function =
WasmExportedFunction::New( WasmExportedFunction::New(
...@@ -1990,34 +1979,10 @@ MaybeHandle<WasmInstanceObject> WasmModule::Instantiate( ...@@ -1990,34 +1979,10 @@ MaybeHandle<WasmInstanceObject> WasmModule::Instantiate(
return builder.Build(); return builder.Build();
} }
Handle<String> wasm::GetWasmFunctionName(Isolate* isolate,
Handle<Object> instance_or_undef,
uint32_t func_index) {
if (!instance_or_undef->IsUndefined(isolate)) {
Handle<WasmCompiledModule> compiled_module(
Handle<WasmInstanceObject>::cast(instance_or_undef)
->get_compiled_module());
MaybeHandle<String> maybe_name =
WasmCompiledModule::GetFunctionName(compiled_module, func_index);
if (!maybe_name.is_null()) return maybe_name.ToHandleChecked();
}
return isolate->factory()->NewStringFromStaticChars("<WASM UNNAMED>");
}
bool wasm::IsWasmInstance(Object* object) { bool wasm::IsWasmInstance(Object* object) {
return WasmInstanceObject::IsWasmInstanceObject(object); return WasmInstanceObject::IsWasmInstanceObject(object);
} }
bool wasm::WasmIsAsmJs(Object* instance, Isolate* isolate) {
if (instance->IsUndefined(isolate)) return false;
DCHECK(IsWasmInstance(instance));
WasmCompiledModule* compiled_module =
WasmInstanceObject::cast(instance)->get_compiled_module();
DCHECK_EQ(compiled_module->has_asm_js_offset_table(),
compiled_module->script()->type() == Script::TYPE_NORMAL);
return compiled_module->has_asm_js_offset_table();
}
Handle<Script> wasm::GetScript(Handle<JSObject> instance) { Handle<Script> wasm::GetScript(Handle<JSObject> instance) {
WasmCompiledModule* compiled_module = WasmCompiledModule* compiled_module =
WasmInstanceObject::cast(*instance)->get_compiled_module(); WasmInstanceObject::cast(*instance)->get_compiled_module();
...@@ -2350,44 +2315,3 @@ void testing::ValidateOrphanedInstance(Isolate* isolate, ...@@ -2350,44 +2315,3 @@ void testing::ValidateOrphanedInstance(Isolate* isolate,
CHECK(compiled_module->has_weak_wasm_module()); CHECK(compiled_module->has_weak_wasm_module());
CHECK(compiled_module->ptr_to_weak_wasm_module()->cleared()); CHECK(compiled_module->ptr_to_weak_wasm_module()->cleared());
} }
void WasmCompiledModule::RecreateModuleWrapper(Isolate* isolate,
Handle<FixedArray> array) {
Handle<WasmCompiledModule> compiled_module(
reinterpret_cast<WasmCompiledModule*>(*array), isolate);
WasmModule* module = nullptr;
{
Handle<SeqOneByteString> module_bytes = compiled_module->module_bytes();
// We parse the module again directly from the module bytes, so
// the underlying storage must not be moved meanwhile.
DisallowHeapAllocation no_allocation;
const byte* start =
reinterpret_cast<const byte*>(module_bytes->GetCharsAddress());
const byte* end = start + module_bytes->length();
// TODO(titzer): remember the module origin in the compiled_module
// For now, we assume serialized modules did not originate from asm.js.
ModuleResult result =
DecodeWasmModule(isolate, start, end, false, kWasmOrigin);
CHECK(result.ok());
CHECK_NOT_NULL(result.val);
module = const_cast<WasmModule*>(result.val);
}
Handle<WasmModuleWrapper> module_wrapper =
WasmModuleWrapper::New(isolate, module);
compiled_module->set_module_wrapper(module_wrapper);
DCHECK(WasmCompiledModule::IsWasmCompiledModule(*compiled_module));
}
MaybeHandle<String> WasmCompiledModule::GetFunctionName(
Handle<WasmCompiledModule> compiled_module, uint32_t func_index) {
DCHECK_LT(func_index, compiled_module->module()->functions.size());
WasmFunction& function = compiled_module->module()->functions[func_index];
Isolate* isolate = compiled_module->GetIsolate();
MaybeHandle<String> string = ExtractStringFromModuleBytes(
isolate, compiled_module, function.name_offset, function.name_length);
if (!string.is_null()) return string.ToHandleChecked();
return {};
}
...@@ -373,13 +373,6 @@ std::ostream& operator<<(std::ostream& os, const WasmModule& module); ...@@ -373,13 +373,6 @@ std::ostream& operator<<(std::ostream& os, const WasmModule& module);
std::ostream& operator<<(std::ostream& os, const WasmFunction& function); std::ostream& operator<<(std::ostream& os, const WasmFunction& function);
std::ostream& operator<<(std::ostream& os, const WasmFunctionName& name); std::ostream& operator<<(std::ostream& os, const WasmFunctionName& name);
// Extract a function name from the given wasm instance.
// Returns "<WASM UNNAMED>" if no instance is passed, the function is unnamed or
// the name is not a valid UTF-8 string.
// TODO(5620): Refactor once we always get a wasm instance.
Handle<String> GetWasmFunctionName(Isolate* isolate, Handle<Object> instance,
uint32_t func_index);
// Get the debug info associated with the given wasm object. // Get the debug info associated with the given wasm object.
// If no debug info exists yet, it is created automatically. // If no debug info exists yet, it is created automatically.
Handle<WasmDebugInfo> GetDebugInfo(Handle<JSObject> wasm); Handle<WasmDebugInfo> GetDebugInfo(Handle<JSObject> wasm);
...@@ -391,9 +384,6 @@ Handle<WasmDebugInfo> GetDebugInfo(Handle<JSObject> wasm); ...@@ -391,9 +384,6 @@ Handle<WasmDebugInfo> GetDebugInfo(Handle<JSObject> wasm);
// else. // else.
bool IsWasmInstance(Object* instance); bool IsWasmInstance(Object* instance);
// Check whether the wasm module was generated from asm.js code.
bool WasmIsAsmJs(Object* instance, Isolate* isolate);
// Get the script of the wasm module. If the origin of the module is asm.js, the // Get the script of the wasm module. If the origin of the module is asm.js, the
// returned Script will be a JavaScript Script of Script::TYPE_NORMAL, otherwise // returned Script will be a JavaScript Script of Script::TYPE_NORMAL, otherwise
// it's of type TYPE_WASM. // it's of type TYPE_WASM.
......
...@@ -360,6 +360,22 @@ void WasmCompiledModule::InitId() { ...@@ -360,6 +360,22 @@ void WasmCompiledModule::InitId() {
#endif #endif
} }
MaybeHandle<String> WasmCompiledModule::ExtractUtf8StringFromModuleBytes(
Isolate* isolate, Handle<WasmCompiledModule> compiled_module,
uint32_t offset, uint32_t size) {
// TODO(wasm): cache strings from modules if it's a performance win.
Handle<SeqOneByteString> module_bytes = compiled_module->module_bytes();
DCHECK_GE(module_bytes->length(), offset);
DCHECK_GE(module_bytes->length() - offset, size);
Address raw = module_bytes->GetCharsAddress() + offset;
if (!unibrow::Utf8::Validate(reinterpret_cast<const byte*>(raw), size))
return {}; // UTF8 decoding error for name.
DCHECK_GE(kMaxInt, offset);
DCHECK_GE(kMaxInt, size);
return isolate->factory()->NewStringFromUtf8SubString(
module_bytes, static_cast<int>(offset), static_cast<int>(size));
}
bool WasmCompiledModule::IsWasmCompiledModule(Object* obj) { bool WasmCompiledModule::IsWasmCompiledModule(Object* obj) {
if (!obj->IsFixedArray()) return false; if (!obj->IsFixedArray()) return false;
FixedArray* arr = FixedArray::cast(obj); FixedArray* arr = FixedArray::cast(obj);
...@@ -395,6 +411,36 @@ void WasmCompiledModule::PrintInstancesChain() { ...@@ -395,6 +411,36 @@ void WasmCompiledModule::PrintInstancesChain() {
#endif #endif
} }
void WasmCompiledModule::RecreateModuleWrapper(Isolate* isolate,
Handle<FixedArray> array) {
Handle<WasmCompiledModule> compiled_module(
reinterpret_cast<WasmCompiledModule*>(*array), isolate);
WasmModule* module = nullptr;
{
Handle<SeqOneByteString> module_bytes = compiled_module->module_bytes();
// We parse the module again directly from the module bytes, so
// the underlying storage must not be moved meanwhile.
DisallowHeapAllocation no_allocation;
const byte* start =
reinterpret_cast<const byte*>(module_bytes->GetCharsAddress());
const byte* end = start + module_bytes->length();
// TODO(titzer): remember the module origin in the compiled_module
// For now, we assume serialized modules did not originate from asm.js.
ModuleResult result =
DecodeWasmModule(isolate, start, end, false, kWasmOrigin);
CHECK(result.ok());
CHECK_NOT_NULL(result.val);
module = const_cast<WasmModule*>(result.val);
}
Handle<WasmModuleWrapper> module_wrapper =
WasmModuleWrapper::New(isolate, module);
compiled_module->set_module_wrapper(module_wrapper);
DCHECK(WasmCompiledModule::IsWasmCompiledModule(*compiled_module));
}
uint32_t WasmCompiledModule::mem_size() const { uint32_t WasmCompiledModule::mem_size() const {
return has_memory() ? memory()->byte_length()->Number() : default_mem_size(); return has_memory() ? memory()->byte_length()->Number() : default_mem_size();
} }
...@@ -403,6 +449,24 @@ uint32_t WasmCompiledModule::default_mem_size() const { ...@@ -403,6 +449,24 @@ uint32_t WasmCompiledModule::default_mem_size() const {
return min_mem_pages() * WasmModule::kPageSize; return min_mem_pages() * WasmModule::kPageSize;
} }
MaybeHandle<String> WasmCompiledModule::GetFunctionNameOrNull(
Isolate* isolate, Handle<WasmCompiledModule> compiled_module,
uint32_t func_index) {
DCHECK_LT(func_index, compiled_module->module()->functions.size());
WasmFunction& function = compiled_module->module()->functions[func_index];
return WasmCompiledModule::ExtractUtf8StringFromModuleBytes(
isolate, compiled_module, function.name_offset, function.name_length);
}
Handle<String> WasmCompiledModule::GetFunctionName(
Isolate* isolate, Handle<WasmCompiledModule> compiled_module,
uint32_t func_index) {
MaybeHandle<String> name =
GetFunctionNameOrNull(isolate, compiled_module, func_index);
if (!name.is_null()) return name.ToHandleChecked();
return isolate->factory()->NewStringFromStaticChars("<WASM UNNAMED>");
}
Vector<const uint8_t> WasmCompiledModule::GetRawFunctionName( Vector<const uint8_t> WasmCompiledModule::GetRawFunctionName(
uint32_t func_index) { uint32_t func_index) {
DCHECK_GT(module()->functions.size(), func_index); DCHECK_GT(module()->functions.size(), func_index);
......
...@@ -254,6 +254,9 @@ class WasmCompiledModule : public FixedArray { ...@@ -254,6 +254,9 @@ class WasmCompiledModule : public FixedArray {
static bool IsWasmCompiledModule(Object* obj); static bool IsWasmCompiledModule(Object* obj);
// Check whether this module wasm generated from asm.js source.
bool is_asm_js() const { return has_asm_js_offset_table(); }
void PrintInstancesChain(); void PrintInstancesChain();
static void RecreateModuleWrapper(Isolate* isolate, static void RecreateModuleWrapper(Isolate* isolate,
...@@ -262,8 +265,16 @@ class WasmCompiledModule : public FixedArray { ...@@ -262,8 +265,16 @@ class WasmCompiledModule : public FixedArray {
// Get the function name of the function identified by the given index. // Get the function name of the function identified by the given index.
// Returns a null handle if the function is unnamed or the name is not a valid // Returns a null handle if the function is unnamed or the name is not a valid
// UTF-8 string. // UTF-8 string.
static MaybeHandle<String> GetFunctionName( static MaybeHandle<String> GetFunctionNameOrNull(
Handle<WasmCompiledModule> compiled_module, uint32_t func_index); Isolate* isolate, Handle<WasmCompiledModule> compiled_module,
uint32_t func_index);
// Get the function name of the function identified by the given index.
// Returns "<WASM UNNAMED>" if the function is unnamed or the name is not a
// valid UTF-8 string.
static Handle<String> GetFunctionName(
Isolate* isolate, Handle<WasmCompiledModule> compiled_module,
uint32_t func_index);
// Get the raw bytes of the function name of the function identified by the // Get the raw bytes of the function name of the function identified by the
// given index. // given index.
...@@ -299,6 +310,13 @@ class WasmCompiledModule : public FixedArray { ...@@ -299,6 +310,13 @@ class WasmCompiledModule : public FixedArray {
// Returns an empty string and empty vector if the function index is invalid. // Returns an empty string and empty vector if the function index is invalid.
debug::WasmDisassembly DisassembleFunction(int func_index); debug::WasmDisassembly DisassembleFunction(int func_index);
// Extract a portion of the wire bytes as UTF-8 string.
// Returns a null handle if the respective bytes do not form a valid UTF-8
// string.
static MaybeHandle<String> ExtractUtf8StringFromModuleBytes(
Isolate* isolate, Handle<WasmCompiledModule> compiled_module,
uint32_t offset, uint32_t size);
private: private:
void InitId(); void InitId();
......
...@@ -87,7 +87,7 @@ TEST(CollectDetailedWasmStack_ExplicitThrowFromJs) { ...@@ -87,7 +87,7 @@ TEST(CollectDetailedWasmStack_ExplicitThrowFromJs) {
BUILD(r, WASM_NOP, WASM_CALL_FUNCTION0(js_throwing_index)); BUILD(r, WASM_NOP, WASM_CALL_FUNCTION0(js_throwing_index));
uint32_t wasm_index_1 = r.function()->func_index; uint32_t wasm_index_1 = r.function()->func_index;
WasmFunctionCompiler& f2 = r.NewFunction<void>(); WasmFunctionCompiler& f2 = r.NewFunction<void>("call_main");
BUILD(f2, WASM_CALL_FUNCTION0(wasm_index_1)); BUILD(f2, WASM_CALL_FUNCTION0(wasm_index_1));
uint32_t wasm_index_2 = f2.function_index(); uint32_t wasm_index_2 = f2.function_index();
...@@ -109,11 +109,11 @@ TEST(CollectDetailedWasmStack_ExplicitThrowFromJs) { ...@@ -109,11 +109,11 @@ TEST(CollectDetailedWasmStack_ExplicitThrowFromJs) {
// Line and column are 1-based, so add 1 for the expected wasm output. // Line and column are 1-based, so add 1 for the expected wasm output.
ExceptionInfo expected_exceptions[] = { ExceptionInfo expected_exceptions[] = {
{"a", 3, 8}, // - {"a", 3, 8}, // -
{"js", 4, 2}, // - {"js", 4, 2}, // -
{"<WASM UNNAMED>", static_cast<int>(wasm_index_1) + 1, 3}, // - {"main", static_cast<int>(wasm_index_1) + 1, 3}, // -
{"<WASM UNNAMED>", static_cast<int>(wasm_index_2) + 1, 2}, // - {"call_main", static_cast<int>(wasm_index_2) + 1, 2}, // -
{"callFn", 1, 24} // - {"callFn", 1, 24} // -
}; };
CheckExceptionInfos(maybe_exc.ToHandleChecked(), expected_exceptions); CheckExceptionInfos(maybe_exc.ToHandleChecked(), expected_exceptions);
} }
...@@ -128,7 +128,7 @@ TEST(CollectDetailedWasmStack_WasmError) { ...@@ -128,7 +128,7 @@ TEST(CollectDetailedWasmStack_WasmError) {
BUILD(r, WASM_UNREACHABLE); BUILD(r, WASM_UNREACHABLE);
uint32_t wasm_index_1 = r.function()->func_index; uint32_t wasm_index_1 = r.function()->func_index;
WasmFunctionCompiler& f2 = r.NewFunction<int>(); WasmFunctionCompiler& f2 = r.NewFunction<int>("call_main");
BUILD(f2, WASM_CALL_FUNCTION0(0)); BUILD(f2, WASM_CALL_FUNCTION0(0));
uint32_t wasm_index_2 = f2.function_index(); uint32_t wasm_index_2 = f2.function_index();
...@@ -150,9 +150,9 @@ TEST(CollectDetailedWasmStack_WasmError) { ...@@ -150,9 +150,9 @@ TEST(CollectDetailedWasmStack_WasmError) {
// Line and column are 1-based, so add 1 for the expected wasm output. // Line and column are 1-based, so add 1 for the expected wasm output.
ExceptionInfo expected_exceptions[] = { ExceptionInfo expected_exceptions[] = {
{"<WASM UNNAMED>", static_cast<int>(wasm_index_1) + 1, 2}, // - {"main", static_cast<int>(wasm_index_1) + 1, 2}, // -
{"<WASM UNNAMED>", static_cast<int>(wasm_index_2) + 1, 2}, // - {"call_main", static_cast<int>(wasm_index_2) + 1, 2}, // -
{"callFn", 1, 24} //- {"callFn", 1, 24} //-
}; };
CheckExceptionInfos(maybe_exc.ToHandleChecked(), expected_exceptions); CheckExceptionInfos(maybe_exc.ToHandleChecked(), expected_exceptions);
} }
...@@ -88,8 +88,8 @@ TEST(Unreachable) { ...@@ -88,8 +88,8 @@ TEST(Unreachable) {
// Line and column are 1-based, so add 1 for the expected wasm output. // Line and column are 1-based, so add 1 for the expected wasm output.
ExceptionInfo expected_exceptions[] = { ExceptionInfo expected_exceptions[] = {
{"<WASM UNNAMED>", static_cast<int>(wasm_index) + 1, 2}, // -- {"main", static_cast<int>(wasm_index) + 1, 2}, // --
{"callFn", 1, 24} // -- {"callFn", 1, 24} // --
}; };
CheckExceptionInfos(maybe_exc.ToHandleChecked(), expected_exceptions); CheckExceptionInfos(maybe_exc.ToHandleChecked(), expected_exceptions);
} }
...@@ -106,7 +106,7 @@ TEST(IllegalLoad) { ...@@ -106,7 +106,7 @@ TEST(IllegalLoad) {
WASM_DROP))); WASM_DROP)));
uint32_t wasm_index_1 = r.function()->func_index; uint32_t wasm_index_1 = r.function()->func_index;
WasmFunctionCompiler& f2 = r.NewFunction<void>(); WasmFunctionCompiler& f2 = r.NewFunction<void>("call_main");
// Insert a NOP such that the position of the call is not one. // Insert a NOP such that the position of the call is not one.
BUILD(f2, WASM_NOP, WASM_CALL_FUNCTION0(wasm_index_1)); BUILD(f2, WASM_NOP, WASM_CALL_FUNCTION0(wasm_index_1));
uint32_t wasm_index_2 = f2.function_index(); uint32_t wasm_index_2 = f2.function_index();
...@@ -129,9 +129,9 @@ TEST(IllegalLoad) { ...@@ -129,9 +129,9 @@ TEST(IllegalLoad) {
// Line and column are 1-based, so add 1 for the expected wasm output. // Line and column are 1-based, so add 1 for the expected wasm output.
ExceptionInfo expected_exceptions[] = { ExceptionInfo expected_exceptions[] = {
{"<WASM UNNAMED>", static_cast<int>(wasm_index_1) + 1, 8}, // -- {"main", static_cast<int>(wasm_index_1) + 1, 8}, // --
{"<WASM UNNAMED>", static_cast<int>(wasm_index_2) + 1, 3}, // -- {"call_main", static_cast<int>(wasm_index_2) + 1, 3}, // --
{"callFn", 1, 24} // -- {"callFn", 1, 24} // --
}; };
CheckExceptionInfos(maybe_exc.ToHandleChecked(), expected_exceptions); CheckExceptionInfos(maybe_exc.ToHandleChecked(), expected_exceptions);
} }
...@@ -91,6 +91,7 @@ class TestingModule : public ModuleEnv { ...@@ -91,6 +91,7 @@ class TestingModule : public ModuleEnv {
instance->mem_start = nullptr; instance->mem_start = nullptr;
instance->mem_size = 0; instance->mem_size = 0;
memset(global_data, 0, sizeof(global_data)); memset(global_data, 0, sizeof(global_data));
instance_object_ = InitInstanceObject();
} }
~TestingModule() { ~TestingModule() {
...@@ -180,7 +181,7 @@ class TestingModule : public ModuleEnv { ...@@ -180,7 +181,7 @@ class TestingModule : public ModuleEnv {
rng.NextBytes(raw, end - raw); rng.NextBytes(raw, end - raw);
} }
uint32_t AddFunction(FunctionSig* sig, Handle<Code> code) { uint32_t AddFunction(FunctionSig* sig, Handle<Code> code, const char* name) {
if (module->functions.size() == 0) { if (module->functions.size() == 0) {
// TODO(titzer): Reserving space here to avoid the underlying WasmFunction // TODO(titzer): Reserving space here to avoid the underlying WasmFunction
// structs from moving. // structs from moving.
...@@ -188,6 +189,11 @@ class TestingModule : public ModuleEnv { ...@@ -188,6 +189,11 @@ class TestingModule : public ModuleEnv {
} }
uint32_t index = static_cast<uint32_t>(module->functions.size()); uint32_t index = static_cast<uint32_t>(module->functions.size());
module_.functions.push_back({sig, index, 0, 0, 0, 0, 0, false, false}); module_.functions.push_back({sig, index, 0, 0, 0, 0, 0, false, false});
if (name) {
Vector<const byte> name_vec = Vector<const byte>::cast(CStrVector(name));
module_.functions.back().name_offset = AddBytes(name_vec);
module_.functions.back().name_length = name_vec.length();
}
instance->function_code.push_back(code); instance->function_code.push_back(code);
if (interpreter_) { if (interpreter_) {
const WasmFunction* function = &module->functions.back(); const WasmFunction* function = &module->functions.back();
...@@ -201,7 +207,7 @@ class TestingModule : public ModuleEnv { ...@@ -201,7 +207,7 @@ class TestingModule : public ModuleEnv {
uint32_t AddJsFunction(FunctionSig* sig, const char* source) { uint32_t AddJsFunction(FunctionSig* sig, const char* source) {
Handle<JSFunction> jsfunc = Handle<JSFunction>::cast(v8::Utils::OpenHandle( Handle<JSFunction> jsfunc = Handle<JSFunction>::cast(v8::Utils::OpenHandle(
*v8::Local<v8::Function>::Cast(CompileRun(source)))); *v8::Local<v8::Function>::Cast(CompileRun(source))));
uint32_t index = AddFunction(sig, Handle<Code>::null()); uint32_t index = AddFunction(sig, Handle<Code>::null(), nullptr);
Handle<Code> code = CompileWasmToJSWrapper( Handle<Code> code = CompileWasmToJSWrapper(
isolate_, jsfunc, sig, index, Handle<String>::null(), isolate_, jsfunc, sig, index, Handle<String>::null(),
Handle<String>::null(), module->origin); Handle<String>::null(), module->origin);
...@@ -265,6 +271,7 @@ class TestingModule : public ModuleEnv { ...@@ -265,6 +271,7 @@ class TestingModule : public ModuleEnv {
WasmInterpreter* interpreter() { return interpreter_; } WasmInterpreter* interpreter() { return interpreter_; }
WasmExecutionMode execution_mode() { return execution_mode_; } WasmExecutionMode execution_mode() { return execution_mode_; }
Isolate* isolate() { return isolate_; } Isolate* isolate() { return isolate_; }
Handle<WasmInstanceObject> instance_object() { return instance_object_; }
private: private:
WasmExecutionMode execution_mode_; WasmExecutionMode execution_mode_;
...@@ -274,6 +281,7 @@ class TestingModule : public ModuleEnv { ...@@ -274,6 +281,7 @@ class TestingModule : public ModuleEnv {
uint32_t global_offset; uint32_t global_offset;
V8_ALIGNED(8) byte global_data[kMaxGlobalsSize]; // preallocated global data. V8_ALIGNED(8) byte global_data[kMaxGlobalsSize]; // preallocated global data.
WasmInterpreter* interpreter_; WasmInterpreter* interpreter_;
Handle<WasmInstanceObject> instance_object_;
const WasmGlobal* AddGlobal(LocalType type) { const WasmGlobal* AddGlobal(LocalType type) {
byte size = WasmOpcodes::MemSize(WasmOpcodes::MachineTypeFor(type)); byte size = WasmOpcodes::MemSize(WasmOpcodes::MachineTypeFor(type));
...@@ -285,6 +293,36 @@ class TestingModule : public ModuleEnv { ...@@ -285,6 +293,36 @@ class TestingModule : public ModuleEnv {
CHECK_LT(global_offset, kMaxGlobalsSize); CHECK_LT(global_offset, kMaxGlobalsSize);
return &module->globals.back(); return &module->globals.back();
} }
uint32_t AddBytes(Vector<const byte> bytes) {
Handle<SeqOneByteString> old_bytes =
instance_object_->get_compiled_module()->module_bytes();
uint32_t old_size = static_cast<uint32_t>(old_bytes->length());
ScopedVector<byte> new_bytes(old_size + bytes.length());
memcpy(new_bytes.start(), old_bytes->GetChars(), old_size);
memcpy(new_bytes.start() + old_size, bytes.start(), bytes.length());
Handle<SeqOneByteString> new_bytes_str = Handle<SeqOneByteString>::cast(
isolate_->factory()->NewStringFromOneByte(new_bytes).ToHandleChecked());
instance_object_->get_compiled_module()->set_module_bytes(new_bytes_str);
return old_size;
}
Handle<WasmInstanceObject> InitInstanceObject() {
Handle<Managed<wasm::WasmModule>> module_wrapper =
Managed<wasm::WasmModule>::New(isolate_, &module_, false);
Handle<WasmCompiledModule> compiled_module =
WasmCompiledModule::New(isolate_, module_wrapper);
// Minimally initialize the compiled module such that IsWasmCompiledModule
// passes.
// If tests need more (correct) information, add it later.
compiled_module->set_min_mem_pages(0);
compiled_module->set_max_mem_pages(Smi::kMaxValue);
Handle<SeqOneByteString> empty_string = Handle<SeqOneByteString>::cast(
isolate_->factory()->NewStringFromOneByte({}).ToHandleChecked());
compiled_module->set_module_bytes(empty_string);
DCHECK(WasmCompiledModule::IsWasmCompiledModule(*compiled_module));
return WasmInstanceObject::New(isolate_, compiled_module);
}
}; };
inline void TestBuildingGraph(Zone* zone, JSGraph* jsgraph, ModuleEnv* module, inline void TestBuildingGraph(Zone* zone, JSGraph* jsgraph, ModuleEnv* module,
...@@ -486,7 +524,7 @@ class WasmFunctionCompiler : private GraphAndBuilders { ...@@ -486,7 +524,7 @@ class WasmFunctionCompiler : private GraphAndBuilders {
friend class WasmRunnerBase; friend class WasmRunnerBase;
explicit WasmFunctionCompiler(Zone* zone, FunctionSig* sig, explicit WasmFunctionCompiler(Zone* zone, FunctionSig* sig,
TestingModule* module) TestingModule* module, const char* name)
: GraphAndBuilders(zone), : GraphAndBuilders(zone),
jsgraph(module->isolate(), this->graph(), this->common(), nullptr, jsgraph(module->isolate(), this->graph(), this->common(), nullptr,
nullptr, this->machine()), nullptr, this->machine()),
...@@ -497,7 +535,7 @@ class WasmFunctionCompiler : private GraphAndBuilders { ...@@ -497,7 +535,7 @@ class WasmFunctionCompiler : private GraphAndBuilders {
source_position_table_(this->graph()), source_position_table_(this->graph()),
interpreter_(module->interpreter()) { interpreter_(module->interpreter()) {
// Get a new function from the testing module. // Get a new function from the testing module.
int index = module->AddFunction(sig, Handle<Code>::null()); int index = module->AddFunction(sig, Handle<Code>::null(), name);
function_ = testing_module_->GetFunctionAt(index); function_ = testing_module_->GetFunctionAt(index);
} }
...@@ -516,12 +554,14 @@ class WasmFunctionCompiler : private GraphAndBuilders { ...@@ -516,12 +554,14 @@ class WasmFunctionCompiler : private GraphAndBuilders {
Handle<Code> code = info.code(); Handle<Code> code = info.code();
// Length is always 2, since usually <wasm_obj, func_index> is stored in // Deopt data holds <WeakCell<wasm_instance>, func_index>.
// the deopt data. Here, we only store the function index.
DCHECK(code->deoptimization_data() == nullptr || DCHECK(code->deoptimization_data() == nullptr ||
code->deoptimization_data()->length() == 0); code->deoptimization_data()->length() == 0);
Handle<FixedArray> deopt_data = Handle<FixedArray> deopt_data =
isolate()->factory()->NewFixedArray(2, TENURED); isolate()->factory()->NewFixedArray(2, TENURED);
Handle<Object> weak_instance =
isolate()->factory()->NewWeakCell(testing_module_->instance_object());
deopt_data->set(0, *weak_instance);
deopt_data->set(1, Smi::FromInt(static_cast<int>(function_index()))); deopt_data->set(1, Smi::FromInt(static_cast<int>(function_index())));
deopt_data->set_length(2); deopt_data->set_length(2);
code->set_deoptimization_data(*deopt_data); code->set_deoptimization_data(*deopt_data);
...@@ -569,15 +609,17 @@ class WasmRunnerBase : public HandleAndZoneScope { ...@@ -569,15 +609,17 @@ class WasmRunnerBase : public HandleAndZoneScope {
// Resets the state for building the next function. // Resets the state for building the next function.
// The main function called will always be the first function. // The main function called will always be the first function.
template <typename ReturnType, typename... ParamTypes> template <typename ReturnType, typename... ParamTypes>
WasmFunctionCompiler& NewFunction() { WasmFunctionCompiler& NewFunction(const char* name = nullptr) {
return NewFunction(CreateSig<ReturnType, ParamTypes...>()); return NewFunction(CreateSig<ReturnType, ParamTypes...>(), name);
} }
// Resets the state for building the next function. // Resets the state for building the next function.
// The main function called will be the last generated function. // The main function called will be the last generated function.
// Returns the index of the previously built function. // Returns the index of the previously built function.
WasmFunctionCompiler& NewFunction(FunctionSig* sig) { WasmFunctionCompiler& NewFunction(FunctionSig* sig,
functions_.emplace_back(new WasmFunctionCompiler(&zone_, sig, &module_)); const char* name = nullptr) {
functions_.emplace_back(
new WasmFunctionCompiler(&zone_, sig, &module_, name));
return *functions_.back(); return *functions_.back();
} }
...@@ -651,9 +693,10 @@ class WasmRunnerBase : public HandleAndZoneScope { ...@@ -651,9 +693,10 @@ class WasmRunnerBase : public HandleAndZoneScope {
template <typename ReturnType, typename... ParamTypes> template <typename ReturnType, typename... ParamTypes>
class WasmRunner : public WasmRunnerBase { class WasmRunner : public WasmRunnerBase {
public: public:
explicit WasmRunner(WasmExecutionMode execution_mode) explicit WasmRunner(WasmExecutionMode execution_mode,
const char* main_fn_name = "main")
: WasmRunnerBase(execution_mode, sizeof...(ParamTypes)) { : WasmRunnerBase(execution_mode, sizeof...(ParamTypes)) {
NewFunction<ReturnType, ParamTypes...>(); NewFunction<ReturnType, ParamTypes...>(main_fn_name);
if (!interpret()) { if (!interpret()) {
wrapper_.Init<ReturnType, ParamTypes...>(functions_[0]->descriptor()); wrapper_.Init<ReturnType, ParamTypes...>(functions_[0]->descriptor());
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment