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 {
return fp() + ExitFrameConstants::kCallerSPOffset;
}
Object* WasmFrame::wasm_instance() const {
WasmInstanceObject* WasmFrame::wasm_instance() const {
Object* ret = wasm::GetOwningWasmInstance(LookupCode());
if (ret == nullptr) ret = isolate()->heap()->undefined_value();
return ret;
// This is a live stack frame, there must be a live wasm instance available.
DCHECK_NOT_NULL(ret);
return WasmInstanceObject::cast(ret);
}
uint32_t WasmFrame::function_index() const {
......@@ -1577,7 +1578,7 @@ Script* WasmFrame::script() const {
int WasmFrame::position() const {
int position = StandardFrame::position();
if (wasm::WasmIsAsmJs(wasm_instance(), isolate())) {
if (wasm_instance()->get_compiled_module()->is_asm_js()) {
Handle<WasmCompiledModule> compiled_module(
WasmInstanceObject::cast(wasm_instance())->get_compiled_module(),
isolate());
......
......@@ -29,9 +29,10 @@ int JSCallerSavedCode(int n);
// Forward declarations.
class ExternalCallbackScope;
class Isolate;
class StackFrameIteratorBase;
class ThreadLocalTop;
class Isolate;
class WasmInstanceObject;
class InnerPointerToCodeCache {
public:
......@@ -1109,7 +1110,7 @@ class WasmFrame : public StandardFrame {
Code* unchecked_code() const override;
// Accessors.
Object* wasm_instance() const;
WasmInstanceObject* wasm_instance() const;
uint32_t function_index() const;
Script* script() const override;
int position() const override;
......
......@@ -512,19 +512,15 @@ Handle<Object> Isolate::CaptureSimpleStackTrace(Handle<JSReceiver> error_object,
case StackFrame::WASM: {
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();
Code* code = wasm_frame->unchecked_code();
Handle<AbstractCode> abstract_code(AbstractCode::cast(code), this);
const int offset =
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;
if (wasm::WasmIsAsmJs(*instance, this)) {
if (instance->get_compiled_module()->is_asm_js()) {
flags |= FrameArray::kIsAsmJsWasmFrame;
if (wasm_frame->at_to_number_conversion()) {
flags |= FrameArray::kAsmJsAtNumberConversion;
......@@ -708,9 +704,10 @@ class CaptureStackTraceHelper {
factory()->NewJSObject(isolate_->object_function());
if (!function_key_.is_null()) {
Handle<String> name = wasm::GetWasmFunctionName(
isolate_, handle(frame->wasm_instance(), isolate_),
frame->function_index());
Handle<WasmCompiledModule> compiled_module(
frame->wasm_instance()->get_compiled_module(), isolate_);
Handle<String> name = WasmCompiledModule::GetFunctionName(
isolate_, compiled_module, frame->function_index());
JSObject::AddProperty(stack_frame, function_key_, name, NONE);
}
// Encode the function index as line number (1-based).
......
......@@ -659,7 +659,8 @@ Handle<Object> WasmStackFrame::GetFunctionName() {
Handle<WasmCompiledModule> compiled_module(
Handle<WasmInstanceObject>::cast(wasm_instance_)->get_compiled_module(),
isolate_);
if (!WasmCompiledModule::GetFunctionName(compiled_module, wasm_func_index_)
if (!WasmCompiledModule::GetFunctionNameOrNull(isolate_, compiled_module,
wasm_func_index_)
.ToHandle(&name)) {
name = isolate_->factory()->null_value();
}
......
......@@ -526,11 +526,11 @@ RUNTIME_FUNCTION(Runtime_GetFrameDetails) {
details->set(kFrameDetailsFrameIdIndex, *frame_id);
// Add the function name.
Handle<Object> wasm_instance_or_undef(it.wasm_frame()->wasm_instance(),
isolate);
Handle<WasmCompiledModule> compiled_module(
it.wasm_frame()->wasm_instance()->get_compiled_module(), isolate);
int func_index = it.wasm_frame()->function_index();
Handle<String> func_name =
wasm::GetWasmFunctionName(isolate, wasm_instance_or_undef, func_index);
Handle<String> func_name = WasmCompiledModule::GetFunctionName(
isolate, compiled_module, func_index);
details->set(kFrameDetailsFunctionIndex, *func_name);
// Add the script wrapper
......@@ -549,14 +549,10 @@ RUNTIME_FUNCTION(Runtime_GetFrameDetails) {
// position, such that together with the script it uniquely identifies the
// position.
Handle<Object> positionValue;
if (position != kNoSourcePosition &&
!wasm_instance_or_undef->IsUndefined(isolate)) {
if (position != kNoSourcePosition) {
int translated_position = position;
if (!wasm::WasmIsAsmJs(*wasm_instance_or_undef, isolate)) {
Handle<WasmCompiledModule> compiled_module(
WasmInstanceObject::cast(*wasm_instance_or_undef)
->get_compiled_module(),
isolate);
// No further translation needed for asm.js modules.
if (!compiled_module->is_asm_js()) {
translated_position +=
wasm::GetFunctionCodeOffset(compiled_module, func_index);
}
......
......@@ -119,6 +119,9 @@ class Vector {
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.
static Vector<T> empty() { return Vector<T>(NULL, 0); }
......
......@@ -47,20 +47,6 @@ byte* raw_buffer_ptr(MaybeHandle<JSArrayBuffer> buffer, int 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,
Handle<Object> new_ref) {
for (RelocIterator it(*code, 1 << RelocInfo::EMBEDDED_OBJECT); !it.done();
......@@ -802,7 +788,7 @@ WasmInstanceObject* wasm::GetOwningWasmInstance(Code* code) {
DCHECK_NOT_NULL(deopt_data);
DCHECK(deopt_data->length() == 2);
Object* weak_link = deopt_data->get(0);
if (!weak_link->IsWeakCell()) return nullptr;
DCHECK(weak_link->IsWeakCell());
WeakCell* cell = WeakCell::cast(weak_link);
if (!cell->value()) return nullptr;
return WasmInstanceObject::cast(cell->value());
......@@ -1521,15 +1507,17 @@ class WasmInstanceBuilder {
WasmImport& import = module_->import_table[index];
Handle<String> module_name;
MaybeHandle<String> maybe_module_name = ExtractStringFromModuleBytes(
isolate_, compiled_module_, import.module_name_offset,
import.module_name_length);
MaybeHandle<String> maybe_module_name =
WasmCompiledModule::ExtractUtf8StringFromModuleBytes(
isolate_, compiled_module_, import.module_name_offset,
import.module_name_length);
if (!maybe_module_name.ToHandle(&module_name)) return -1;
Handle<String> import_name;
MaybeHandle<String> maybe_import_name = ExtractStringFromModuleBytes(
isolate_, compiled_module_, import.field_name_offset,
import.field_name_length);
MaybeHandle<String> maybe_import_name =
WasmCompiledModule::ExtractUtf8StringFromModuleBytes(
isolate_, compiled_module_, import.field_name_offset,
import.field_name_length);
if (!maybe_import_name.ToHandle(&import_name)) return -1;
MaybeHandle<Object> result =
......@@ -1752,8 +1740,8 @@ class WasmInstanceBuilder {
// can skip duplicates).
for (auto exp : base::Reversed(module_->export_table)) {
Handle<String> name =
ExtractStringFromModuleBytes(isolate_, compiled_module_,
exp.name_offset, exp.name_length)
WasmCompiledModule::ExtractUtf8StringFromModuleBytes(
isolate_, compiled_module_, exp.name_offset, exp.name_length)
.ToHandleChecked();
switch (exp.kind) {
case kExternalFunction: {
......@@ -1769,7 +1757,7 @@ class WasmInstanceBuilder {
MaybeHandle<String> func_name;
if (module_->origin == kAsmJsOrigin) {
// For modules arising from asm.js, honor the names section.
func_name = ExtractStringFromModuleBytes(
func_name = WasmCompiledModule::ExtractUtf8StringFromModuleBytes(
isolate_, compiled_module_, function.name_offset,
function.name_length)
.ToHandleChecked();
......@@ -1936,10 +1924,11 @@ class WasmInstanceBuilder {
MaybeHandle<String> func_name;
if (module_->origin == kAsmJsOrigin) {
// For modules arising from asm.js, honor the names section.
func_name = ExtractStringFromModuleBytes(
isolate_, compiled_module_,
function->name_offset, function->name_length)
.ToHandleChecked();
func_name =
WasmCompiledModule::ExtractUtf8StringFromModuleBytes(
isolate_, compiled_module_, function->name_offset,
function->name_length)
.ToHandleChecked();
}
Handle<WasmExportedFunction> js_function =
WasmExportedFunction::New(
......@@ -1990,34 +1979,10 @@ MaybeHandle<WasmInstanceObject> WasmModule::Instantiate(
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) {
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) {
WasmCompiledModule* compiled_module =
WasmInstanceObject::cast(*instance)->get_compiled_module();
......@@ -2350,44 +2315,3 @@ void testing::ValidateOrphanedInstance(Isolate* isolate,
CHECK(compiled_module->has_weak_wasm_module());
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);
std::ostream& operator<<(std::ostream& os, const WasmFunction& function);
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.
// If no debug info exists yet, it is created automatically.
Handle<WasmDebugInfo> GetDebugInfo(Handle<JSObject> wasm);
......@@ -391,9 +384,6 @@ Handle<WasmDebugInfo> GetDebugInfo(Handle<JSObject> wasm);
// else.
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
// returned Script will be a JavaScript Script of Script::TYPE_NORMAL, otherwise
// it's of type TYPE_WASM.
......
......@@ -360,6 +360,22 @@ void WasmCompiledModule::InitId() {
#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) {
if (!obj->IsFixedArray()) return false;
FixedArray* arr = FixedArray::cast(obj);
......@@ -395,6 +411,36 @@ void WasmCompiledModule::PrintInstancesChain() {
#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 {
return has_memory() ? memory()->byte_length()->Number() : default_mem_size();
}
......@@ -403,6 +449,24 @@ uint32_t WasmCompiledModule::default_mem_size() const {
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(
uint32_t func_index) {
DCHECK_GT(module()->functions.size(), func_index);
......
......@@ -254,6 +254,9 @@ class WasmCompiledModule : public FixedArray {
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();
static void RecreateModuleWrapper(Isolate* isolate,
......@@ -262,8 +265,16 @@ class WasmCompiledModule : public FixedArray {
// 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
// UTF-8 string.
static MaybeHandle<String> GetFunctionName(
Handle<WasmCompiledModule> compiled_module, uint32_t func_index);
static MaybeHandle<String> GetFunctionNameOrNull(
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
// given index.
......@@ -299,6 +310,13 @@ class WasmCompiledModule : public FixedArray {
// Returns an empty string and empty vector if the function index is invalid.
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:
void InitId();
......
......@@ -87,7 +87,7 @@ TEST(CollectDetailedWasmStack_ExplicitThrowFromJs) {
BUILD(r, WASM_NOP, WASM_CALL_FUNCTION0(js_throwing_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));
uint32_t wasm_index_2 = f2.function_index();
......@@ -109,11 +109,11 @@ TEST(CollectDetailedWasmStack_ExplicitThrowFromJs) {
// Line and column are 1-based, so add 1 for the expected wasm output.
ExceptionInfo expected_exceptions[] = {
{"a", 3, 8}, // -
{"js", 4, 2}, // -
{"<WASM UNNAMED>", static_cast<int>(wasm_index_1) + 1, 3}, // -
{"<WASM UNNAMED>", static_cast<int>(wasm_index_2) + 1, 2}, // -
{"callFn", 1, 24} // -
{"a", 3, 8}, // -
{"js", 4, 2}, // -
{"main", static_cast<int>(wasm_index_1) + 1, 3}, // -
{"call_main", static_cast<int>(wasm_index_2) + 1, 2}, // -
{"callFn", 1, 24} // -
};
CheckExceptionInfos(maybe_exc.ToHandleChecked(), expected_exceptions);
}
......@@ -128,7 +128,7 @@ TEST(CollectDetailedWasmStack_WasmError) {
BUILD(r, WASM_UNREACHABLE);
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));
uint32_t wasm_index_2 = f2.function_index();
......@@ -150,9 +150,9 @@ TEST(CollectDetailedWasmStack_WasmError) {
// Line and column are 1-based, so add 1 for the expected wasm output.
ExceptionInfo expected_exceptions[] = {
{"<WASM UNNAMED>", static_cast<int>(wasm_index_1) + 1, 2}, // -
{"<WASM UNNAMED>", static_cast<int>(wasm_index_2) + 1, 2}, // -
{"callFn", 1, 24} //-
{"main", static_cast<int>(wasm_index_1) + 1, 2}, // -
{"call_main", static_cast<int>(wasm_index_2) + 1, 2}, // -
{"callFn", 1, 24} //-
};
CheckExceptionInfos(maybe_exc.ToHandleChecked(), expected_exceptions);
}
......@@ -88,8 +88,8 @@ TEST(Unreachable) {
// Line and column are 1-based, so add 1 for the expected wasm output.
ExceptionInfo expected_exceptions[] = {
{"<WASM UNNAMED>", static_cast<int>(wasm_index) + 1, 2}, // --
{"callFn", 1, 24} // --
{"main", static_cast<int>(wasm_index) + 1, 2}, // --
{"callFn", 1, 24} // --
};
CheckExceptionInfos(maybe_exc.ToHandleChecked(), expected_exceptions);
}
......@@ -106,7 +106,7 @@ TEST(IllegalLoad) {
WASM_DROP)));
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.
BUILD(f2, WASM_NOP, WASM_CALL_FUNCTION0(wasm_index_1));
uint32_t wasm_index_2 = f2.function_index();
......@@ -129,9 +129,9 @@ TEST(IllegalLoad) {
// Line and column are 1-based, so add 1 for the expected wasm output.
ExceptionInfo expected_exceptions[] = {
{"<WASM UNNAMED>", static_cast<int>(wasm_index_1) + 1, 8}, // --
{"<WASM UNNAMED>", static_cast<int>(wasm_index_2) + 1, 3}, // --
{"callFn", 1, 24} // --
{"main", static_cast<int>(wasm_index_1) + 1, 8}, // --
{"call_main", static_cast<int>(wasm_index_2) + 1, 3}, // --
{"callFn", 1, 24} // --
};
CheckExceptionInfos(maybe_exc.ToHandleChecked(), expected_exceptions);
}
......@@ -91,6 +91,7 @@ class TestingModule : public ModuleEnv {
instance->mem_start = nullptr;
instance->mem_size = 0;
memset(global_data, 0, sizeof(global_data));
instance_object_ = InitInstanceObject();
}
~TestingModule() {
......@@ -180,7 +181,7 @@ class TestingModule : public ModuleEnv {
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) {
// TODO(titzer): Reserving space here to avoid the underlying WasmFunction
// structs from moving.
......@@ -188,6 +189,11 @@ class TestingModule : public ModuleEnv {
}
uint32_t index = static_cast<uint32_t>(module->functions.size());
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);
if (interpreter_) {
const WasmFunction* function = &module->functions.back();
......@@ -201,7 +207,7 @@ class TestingModule : public ModuleEnv {
uint32_t AddJsFunction(FunctionSig* sig, const char* source) {
Handle<JSFunction> jsfunc = Handle<JSFunction>::cast(v8::Utils::OpenHandle(
*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(
isolate_, jsfunc, sig, index, Handle<String>::null(),
Handle<String>::null(), module->origin);
......@@ -265,6 +271,7 @@ class TestingModule : public ModuleEnv {
WasmInterpreter* interpreter() { return interpreter_; }
WasmExecutionMode execution_mode() { return execution_mode_; }
Isolate* isolate() { return isolate_; }
Handle<WasmInstanceObject> instance_object() { return instance_object_; }
private:
WasmExecutionMode execution_mode_;
......@@ -274,6 +281,7 @@ class TestingModule : public ModuleEnv {
uint32_t global_offset;
V8_ALIGNED(8) byte global_data[kMaxGlobalsSize]; // preallocated global data.
WasmInterpreter* interpreter_;
Handle<WasmInstanceObject> instance_object_;
const WasmGlobal* AddGlobal(LocalType type) {
byte size = WasmOpcodes::MemSize(WasmOpcodes::MachineTypeFor(type));
......@@ -285,6 +293,36 @@ class TestingModule : public ModuleEnv {
CHECK_LT(global_offset, kMaxGlobalsSize);
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,
......@@ -486,7 +524,7 @@ class WasmFunctionCompiler : private GraphAndBuilders {
friend class WasmRunnerBase;
explicit WasmFunctionCompiler(Zone* zone, FunctionSig* sig,
TestingModule* module)
TestingModule* module, const char* name)
: GraphAndBuilders(zone),
jsgraph(module->isolate(), this->graph(), this->common(), nullptr,
nullptr, this->machine()),
......@@ -497,7 +535,7 @@ class WasmFunctionCompiler : private GraphAndBuilders {
source_position_table_(this->graph()),
interpreter_(module->interpreter()) {
// 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);
}
......@@ -516,12 +554,14 @@ class WasmFunctionCompiler : private GraphAndBuilders {
Handle<Code> code = info.code();
// Length is always 2, since usually <wasm_obj, func_index> is stored in
// the deopt data. Here, we only store the function index.
// Deopt data holds <WeakCell<wasm_instance>, func_index>.
DCHECK(code->deoptimization_data() == nullptr ||
code->deoptimization_data()->length() == 0);
Handle<FixedArray> deopt_data =
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_length(2);
code->set_deoptimization_data(*deopt_data);
......@@ -569,15 +609,17 @@ class WasmRunnerBase : public HandleAndZoneScope {
// Resets the state for building the next function.
// The main function called will always be the first function.
template <typename ReturnType, typename... ParamTypes>
WasmFunctionCompiler& NewFunction() {
return NewFunction(CreateSig<ReturnType, ParamTypes...>());
WasmFunctionCompiler& NewFunction(const char* name = nullptr) {
return NewFunction(CreateSig<ReturnType, ParamTypes...>(), name);
}
// Resets the state for building the next function.
// The main function called will be the last generated function.
// Returns the index of the previously built function.
WasmFunctionCompiler& NewFunction(FunctionSig* sig) {
functions_.emplace_back(new WasmFunctionCompiler(&zone_, sig, &module_));
WasmFunctionCompiler& NewFunction(FunctionSig* sig,
const char* name = nullptr) {
functions_.emplace_back(
new WasmFunctionCompiler(&zone_, sig, &module_, name));
return *functions_.back();
}
......@@ -651,9 +693,10 @@ class WasmRunnerBase : public HandleAndZoneScope {
template <typename ReturnType, typename... ParamTypes>
class WasmRunner : public WasmRunnerBase {
public:
explicit WasmRunner(WasmExecutionMode execution_mode)
explicit WasmRunner(WasmExecutionMode execution_mode,
const char* main_fn_name = "main")
: WasmRunnerBase(execution_mode, sizeof...(ParamTypes)) {
NewFunction<ReturnType, ParamTypes...>();
NewFunction<ReturnType, ParamTypes...>(main_fn_name);
if (!interpret()) {
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