[wasm] Remove raw byte pointers from WasmModule

These byte pointers (module_start and module_end) were only valid
during decoding. During instantiation or execution, they can get
invalidated by garbage collection.
This CL removes them from the WasmModule struct, and introduces a new
ModuleStorage struct as interface to the wasm wire bytes.
Since the storage is often needed together with the ModuleEnv, a new
ModuleStorageEnv struct holds both a ModuleEnv and a ModuleStorage.
The pointers in the ModuleStorage should never escape the live range of
this struct, as they might point into a SeqOneByteString or ArrayBuffer.
Therefore, the WasmInterpreter needs to create its own copy of the
whole module.
Runtime functions that previously used the raw pointers in WasmModule
(leading to memory errors) now have to use the SeqOneByteString in the
WasmCompiledModule.

R=titzer@chromium.org
BUG=chromium:669518

Review-Url: https://codereview.chromium.org/2540133002
Cr-Commit-Position: refs/heads/master@{#41388}
This commit is contained in:
clemensh 2016-11-30 07:02:40 -08:00 committed by Commit bot
parent 6d90507a7c
commit 6572b5622e
21 changed files with 272 additions and 240 deletions

View File

@ -3152,9 +3152,10 @@ static void RecordFunctionCompilation(CodeEventListener::LogEventsAndTags tag,
*script_str, 0, 0));
}
Handle<Code> CompileJSToWasmWrapper(Isolate* isolate, wasm::ModuleEnv* module,
Handle<Code> CompileJSToWasmWrapper(Isolate* isolate,
const wasm::WasmModule* module,
Handle<Code> wasm_code, uint32_t index) {
const wasm::WasmFunction* func = &module->module->functions[index];
const wasm::WasmFunction* func = &module->functions[index];
//----------------------------------------------------------------------------
// Create the Graph
@ -3168,10 +3169,11 @@ Handle<Code> CompileJSToWasmWrapper(Isolate* isolate, wasm::ModuleEnv* module,
Node* control = nullptr;
Node* effect = nullptr;
wasm::ModuleEnv module_env(module, nullptr);
WasmGraphBuilder builder(&zone, &jsgraph, func->sig);
builder.set_control_ptr(&control);
builder.set_effect_ptr(&effect);
builder.set_module(module);
builder.set_module(&module_env);
builder.BuildJSToWasmWrapper(wasm_code, func->sig);
//----------------------------------------------------------------------------
@ -3184,8 +3186,8 @@ Handle<Code> CompileJSToWasmWrapper(Isolate* isolate, wasm::ModuleEnv* module,
}
// Schedule and compile to machine code.
int params =
static_cast<int>(module->GetFunctionSignature(index)->parameter_count());
int params = static_cast<int>(
module_env.GetFunctionSignature(index)->parameter_count());
CallDescriptor* incoming = Linkage::GetJSCallDescriptor(
&zone, false, params + 1, CallDescriptor::kNoFlags);
Code::Flags flags = Code::ComputeFlags(Code::JS_TO_WASM_FUNCTION);
@ -3218,10 +3220,11 @@ Handle<Code> CompileJSToWasmWrapper(Isolate* isolate, wasm::ModuleEnv* module,
}
if (isolate->logger()->is_logging_code_events() || isolate->is_profiling()) {
RecordFunctionCompilation(
CodeEventListener::FUNCTION_TAG, isolate, code, "js-to-wasm", index,
wasm::WasmName("export"),
module->module->GetName(func->name_offset, func->name_length));
char func_name[32];
SNPrintF(ArrayVector(func_name), "js-to-wasm#%d", func->func_index);
RecordFunctionCompilation(CodeEventListener::FUNCTION_TAG, isolate, code,
"js-to-wasm", index, wasm::WasmName("export"),
CStrVector(func_name));
}
return code;
}
@ -3321,10 +3324,10 @@ SourcePositionTable* WasmCompilationUnit::BuildGraphForWasmFunction(
new (jsgraph_->zone()) SourcePositionTable(graph);
WasmGraphBuilder builder(jsgraph_->zone(), jsgraph_, function_->sig,
source_position_table);
wasm::FunctionBody body = {
module_env_, function_->sig, module_env_->module->module_start,
module_env_->module->module_start + function_->code_start_offset,
module_env_->module->module_start + function_->code_end_offset};
const byte* module_start = module_env_->module_bytes.start();
wasm::FunctionBody body = {module_env_, function_->sig, module_start,
module_start + function_->code_start_offset,
module_start + function_->code_end_offset};
graph_construction_result_ =
wasm::BuildTFGraph(isolate_->allocator(), &builder, body);
@ -3354,7 +3357,8 @@ SourcePositionTable* WasmCompilationUnit::BuildGraphForWasmFunction(
}
if (index >= FLAG_trace_wasm_text_start && index < FLAG_trace_wasm_text_end) {
OFStream os(stdout);
PrintWasmText(module_env_->module, function_->func_index, os, nullptr);
PrintWasmText(module_env_->module, *module_env_, function_->func_index, os,
nullptr);
}
if (FLAG_trace_wasm_decode_time) {
*decode_ms = decode_timer.Elapsed().InMillisecondsF();
@ -3364,13 +3368,13 @@ SourcePositionTable* WasmCompilationUnit::BuildGraphForWasmFunction(
WasmCompilationUnit::WasmCompilationUnit(wasm::ErrorThrower* thrower,
Isolate* isolate,
wasm::ModuleEnv* module_env,
wasm::ModuleBytesEnv* module_env,
const wasm::WasmFunction* function,
uint32_t index)
: thrower_(thrower),
isolate_(isolate),
module_env_(module_env),
function_(function),
function_(&module_env->module->functions[index]),
graph_zone_(new Zone(isolate->allocator(), ZONE_NAME)),
jsgraph_(new (graph_zone()) JSGraph(
isolate, new (graph_zone()) Graph(graph_zone()),
@ -3380,10 +3384,8 @@ WasmCompilationUnit::WasmCompilationUnit(wasm::ErrorThrower* thrower,
InstructionSelector::SupportedMachineOperatorFlags(),
InstructionSelector::AlignmentRequirements()))),
compilation_zone_(isolate->allocator(), ZONE_NAME),
info_(function->name_length != 0
? module_env->module->GetNameOrNull(function->name_offset,
function->name_length)
: ArrayVector("wasm"),
info_(function->name_length != 0 ? module_env->GetNameOrNull(function)
: ArrayVector("wasm"),
isolate, &compilation_zone_,
Code::ComputeFlags(Code::WASM_FUNCTION)),
job_(),
@ -3453,8 +3455,7 @@ Handle<Code> WasmCompilationUnit::FinishCompilation() {
if (graph_construction_result_.failed()) {
// Add the function as another context for the exception
ScopedVector<char> buffer(128);
wasm::WasmName name = module_env_->module->GetName(
function_->name_offset, function_->name_length);
wasm::WasmName name = module_env_->GetName(function_);
SNPrintF(buffer, "Compiling WASM function #%d:%.*s failed:",
function_->func_index, name.length(), name.start());
thrower_->CompileFailed(buffer.start(), graph_construction_result_);
@ -3474,11 +3475,10 @@ Handle<Code> WasmCompilationUnit::FinishCompilation() {
if (isolate_->logger()->is_logging_code_events() ||
isolate_->is_profiling()) {
RecordFunctionCompilation(
CodeEventListener::FUNCTION_TAG, isolate_, code, "WASM_function",
function_->func_index, wasm::WasmName("module"),
module_env_->module->GetName(function_->name_offset,
function_->name_length));
RecordFunctionCompilation(CodeEventListener::FUNCTION_TAG, isolate_, code,
"WASM_function", function_->func_index,
wasm::WasmName("module"),
module_env_->GetName(function_));
}
if (FLAG_trace_wasm_decode_time) {

View File

@ -29,8 +29,10 @@ class SourcePositionTable;
namespace wasm {
// Forward declarations for some WASM data structures.
struct ModuleBytesEnv;
struct ModuleEnv;
struct WasmFunction;
struct WasmModule;
class ErrorThrower;
struct DecodeStruct;
@ -43,7 +45,7 @@ namespace compiler {
class WasmCompilationUnit final {
public:
WasmCompilationUnit(wasm::ErrorThrower* thrower, Isolate* isolate,
wasm::ModuleEnv* module_env,
wasm::ModuleBytesEnv* module_env,
const wasm::WasmFunction* function, uint32_t index);
Zone* graph_zone() { return graph_zone_.get(); }
@ -54,7 +56,7 @@ class WasmCompilationUnit final {
static Handle<Code> CompileWasmFunction(wasm::ErrorThrower* thrower,
Isolate* isolate,
wasm::ModuleEnv* module_env,
wasm::ModuleBytesEnv* module_env,
const wasm::WasmFunction* function) {
WasmCompilationUnit unit(thrower, isolate, module_env, function, 0);
unit.ExecuteCompilation();
@ -66,7 +68,7 @@ class WasmCompilationUnit final {
wasm::ErrorThrower* thrower_;
Isolate* isolate_;
wasm::ModuleEnv* module_env_;
wasm::ModuleBytesEnv* module_env_;
const wasm::WasmFunction* function_;
// The graph zone is deallocated at the end of ExecuteCompilation.
std::unique_ptr<Zone> graph_zone_;
@ -88,7 +90,8 @@ Handle<Code> CompileWasmToJSWrapper(Isolate* isolate, Handle<JSReceiver> target,
MaybeHandle<String> import_name);
// Wraps a given wasm code object, producing a code object.
Handle<Code> CompileJSToWasmWrapper(Isolate* isolate, wasm::ModuleEnv* module,
Handle<Code> CompileJSToWasmWrapper(Isolate* isolate,
const wasm::WasmModule* module,
Handle<Code> wasm_code, uint32_t index);
// Abstracts details of building TurboFan graph nodes for WASM to separate

View File

@ -33,7 +33,7 @@ class Vector {
// Returns a vector using the same backing storage as this one,
// spanning from and including 'from', to but not including 'to'.
Vector<T> SubVector(int from, int to) {
Vector<T> SubVector(int from, int to) const {
DCHECK(0 <= from);
SLOW_DCHECK(from < to);
SLOW_DCHECK(static_cast<unsigned>(to) <= static_cast<unsigned>(length_));

View File

@ -31,13 +31,13 @@ namespace wasm {
#define TRACE(...)
#endif
#define CHECK_PROTOTYPE_OPCODE(flag) \
if (module_ && module_->origin == kAsmJsOrigin) { \
error("Opcode not supported for asmjs modules"); \
} \
if (!FLAG_##flag) { \
error("Invalid opcode (enable with --" #flag ")"); \
break; \
#define CHECK_PROTOTYPE_OPCODE(flag) \
if (module_ && module_->module->origin == kAsmJsOrigin) { \
error("Opcode not supported for asmjs modules"); \
} \
if (!FLAG_##flag) { \
error("Invalid opcode (enable with --" #flag ")"); \
break; \
}
// TODO(titzer): this is only for intermediate migration.
#define IMPLICIT_FUNCTION_END 1
@ -1118,7 +1118,7 @@ class WasmFullDecoder : public WasmDecoder {
break;
case kExprGrowMemory: {
MemoryIndexOperand operand(this, pc_);
if (module_->origin != kAsmJsOrigin) {
if (module_->module->origin != kAsmJsOrigin) {
Value val = Pop(0, kAstI32);
Push(kAstI32, BUILD(GrowMemory, val.node));
} else {
@ -1168,7 +1168,7 @@ class WasmFullDecoder : public WasmDecoder {
break;
}
case kAtomicPrefix: {
if (!module_ || module_->origin != kAsmJsOrigin) {
if (!module_ || module_->module->origin != kAsmJsOrigin) {
error("Atomics are allowed only in AsmJs modules");
break;
}
@ -1187,7 +1187,7 @@ class WasmFullDecoder : public WasmDecoder {
}
default: {
// Deal with special asmjs opcodes.
if (module_ && module_->origin == kAsmJsOrigin) {
if (module_ && module_->module->origin == kAsmJsOrigin) {
sig = WasmOpcodes::AsmjsSignature(opcode);
if (sig) {
BuildSimpleOperator(opcode, sig);

View File

@ -189,7 +189,7 @@ class ModuleDecoder : public Decoder {
pc_ = limit_; // On error, terminate section decoding loop.
}
static void DumpModule(WasmModule* module, const ModuleResult& result) {
void DumpModule(const ModuleResult& result) {
std::string path;
if (FLAG_dump_wasm_module_path) {
path = FLAG_dump_wasm_module_path;
@ -199,7 +199,7 @@ class ModuleDecoder : public Decoder {
}
}
// File are named `HASH.{ok,failed}.wasm`.
size_t hash = base::hash_range(module->module_start, module->module_end);
size_t hash = base::hash_range(start_, limit_);
char buf[32] = {'\0'};
#if V8_OS_WIN && _MSC_VER < 1900
#define snprintf sprintf_s
@ -208,17 +208,15 @@ class ModuleDecoder : public Decoder {
result.ok() ? "ok" : "failed");
std::string name(buf);
if (FILE* wasm_file = base::OS::FOpen((path + name).c_str(), "wb")) {
fwrite(module->module_start, module->module_end - module->module_start, 1,
wasm_file);
fwrite(start_, limit_ - start_, 1, wasm_file);
fclose(wasm_file);
}
}
// Decodes an entire module.
ModuleResult DecodeModule(WasmModule* module, bool verify_functions = true) {
ModuleResult DecodeModule(bool verify_functions = true) {
pc_ = start_;
module->module_start = start_;
module->module_end = limit_;
WasmModule* module = new WasmModule(module_zone);
module->min_mem_pages = 0;
module->max_mem_pages = 0;
module->mem_export = false;
@ -587,10 +585,8 @@ class ModuleDecoder : public Decoder {
function->code_start_offset = pc_offset();
function->code_end_offset = pc_offset() + size;
if (verify_functions) {
ModuleEnv module_env;
module_env.module = module;
module_env.origin = module->origin;
ModuleBytesEnv module_env(module, nullptr,
ModuleWireBytes(start_, limit_));
VerifyFunctionBody(i + module->num_imported_functions, &module_env,
function);
}
@ -656,7 +652,7 @@ class ModuleDecoder : public Decoder {
if (verify_functions && result.ok()) {
result.MoveFrom(result_); // Copy error code and location.
}
if (FLAG_dump_wasm_module) DumpModule(module, result);
if (FLAG_dump_wasm_module) DumpModule(result);
return result;
}
@ -667,7 +663,7 @@ class ModuleDecoder : public Decoder {
}
// Decodes a single anonymous function starting at {start_}.
FunctionResult DecodeSingleFunction(ModuleEnv* module_env,
FunctionResult DecodeSingleFunction(ModuleBytesEnv* module_env,
WasmFunction* function) {
pc_ = start_;
function->sig = consume_sig(); // read signature
@ -779,7 +775,7 @@ class ModuleDecoder : public Decoder {
}
// Verifies the body (code) of a given function.
void VerifyFunctionBody(uint32_t func_num, ModuleEnv* menv,
void VerifyFunctionBody(uint32_t func_num, ModuleBytesEnv* menv,
WasmFunction* function) {
if (FLAG_trace_wasm_decoder || FLAG_trace_wasm_decode_time) {
OFStream os(stdout);
@ -1120,9 +1116,8 @@ ModuleResult DecodeWasmModule(Isolate* isolate, const byte* module_start,
// Signatures are stored in zone memory, which have the same lifetime
// as the {module}.
Zone* zone = new Zone(isolate->allocator(), ZONE_NAME);
WasmModule* module = new WasmModule(zone, module_start);
ModuleDecoder decoder(zone, module_start, module_end, origin);
ModuleResult result = decoder.DecodeModule(module, verify_functions);
ModuleResult result = decoder.DecodeModule(verify_functions);
// TODO(bradnelson): Improve histogram handling of size_t.
// TODO(titzer): this isn't accurate, since it doesn't count the data
// allocated on the C++ heap.
@ -1146,7 +1141,7 @@ WasmInitExpr DecodeWasmInitExprForTesting(const byte* start, const byte* end) {
}
FunctionResult DecodeWasmFunction(Isolate* isolate, Zone* zone,
ModuleEnv* module_env,
ModuleBytesEnv* module_env,
const byte* function_start,
const byte* function_end) {
HistogramTimerScope wasm_decode_function_time_scope(

View File

@ -37,7 +37,8 @@ V8_EXPORT_PRIVATE FunctionSig* DecodeWasmSignatureForTesting(Zone* zone,
// Decodes the bytes of a WASM function between
// {function_start} and {function_end}.
V8_EXPORT_PRIVATE FunctionResult DecodeWasmFunction(Isolate* isolate,
Zone* zone, ModuleEnv* env,
Zone* zone,
ModuleBytesEnv* env,
const byte* function_start,
const byte* function_end);

View File

@ -721,8 +721,8 @@ class ControlTransfers : public ZoneObject {
public:
ControlTransferMap map_;
ControlTransfers(Zone* zone, ModuleEnv* env, AstLocalDecls* locals,
const byte* start, const byte* end)
ControlTransfers(Zone* zone, AstLocalDecls* locals, const byte* start,
const byte* end)
: map_(zone) {
// Represents a control flow label.
struct CLabel : public ZoneObject {
@ -890,14 +890,13 @@ class CodeMap {
const WasmModule* module_;
ZoneVector<InterpreterCode> interpreter_code_;
CodeMap(const WasmModule* module, Zone* zone)
CodeMap(const WasmModule* module, const uint8_t* module_start, Zone* zone)
: zone_(zone), module_(module), interpreter_code_(zone) {
if (module == nullptr) return;
for (size_t i = 0; i < module->functions.size(); ++i) {
const WasmFunction* function = &module->functions[i];
const byte* code_start =
module->module_start + function->code_start_offset;
const byte* code_end = module->module_start + function->code_end_offset;
const byte* code_start = module_start + function->code_start_offset;
const byte* code_end = module_start + function->code_end_offset;
AddFunction(function, code_start, code_end);
}
}
@ -930,9 +929,8 @@ class CodeMap {
if (code->targets == nullptr && code->start) {
// Compute the control targets map and the local declarations.
CHECK(DecodeLocalDecls(code->locals, code->start, code->end));
ModuleEnv env = {module_, nullptr, kWasmOrigin};
code->targets = new (zone_) ControlTransfers(
zone_, &env, &code->locals, code->orig_start, code->orig_end);
zone_, &code->locals, code->orig_start, code->orig_end);
}
return code;
}
@ -1760,14 +1758,19 @@ class ThreadImpl : public WasmInterpreter::Thread {
class WasmInterpreterInternals : public ZoneObject {
public:
WasmInstance* instance_;
// Create a copy of the module bytes for the interpreter, since the passed
// pointer might be invalidated after constructing the interpreter.
const ZoneVector<uint8_t> module_bytes_;
CodeMap codemap_;
ZoneVector<ThreadImpl*> threads_;
WasmInterpreterInternals(Zone* zone, WasmInstance* instance)
: instance_(instance),
codemap_(instance_ ? instance_->module : nullptr, zone),
WasmInterpreterInternals(Zone* zone, const ModuleBytesEnv& env)
: instance_(env.instance),
module_bytes_(env.module_bytes.start(), env.module_bytes.end(), zone),
codemap_(env.instance ? env.instance->module : nullptr,
module_bytes_.data(), zone),
threads_(zone) {
threads_.push_back(new ThreadImpl(zone, &codemap_, instance));
threads_.push_back(new ThreadImpl(zone, &codemap_, env.instance));
}
void Delete() {
@ -1780,10 +1783,10 @@ class WasmInterpreterInternals : public ZoneObject {
//============================================================================
// Implementation of the public interface of the interpreter.
//============================================================================
WasmInterpreter::WasmInterpreter(WasmInstance* instance,
WasmInterpreter::WasmInterpreter(const ModuleBytesEnv& env,
AccountingAllocator* allocator)
: zone_(allocator, ZONE_NAME),
internals_(new (&zone_) WasmInterpreterInternals(&zone_, instance)) {}
internals_(new (&zone_) WasmInterpreterInternals(&zone_, env)) {}
WasmInterpreter::~WasmInterpreter() { internals_->Delete(); }
@ -1885,7 +1888,7 @@ bool WasmInterpreter::SetFunctionCodeForTesting(const WasmFunction* function,
ControlTransferMap WasmInterpreter::ComputeControlTransfersForTesting(
Zone* zone, const byte* start, const byte* end) {
ControlTransfers targets(zone, nullptr, nullptr, start, end);
ControlTransfers targets(zone, nullptr, start, end);
return targets.map_;
}

View File

@ -17,8 +17,8 @@ namespace internal {
namespace wasm {
// forward declarations.
struct ModuleBytesEnv;
struct WasmFunction;
struct WasmInstance;
class WasmInterpreterInternals;
typedef size_t pc_t;
@ -135,7 +135,7 @@ class V8_EXPORT_PRIVATE WasmInterpreter {
bool GetBreakpoint(const WasmFunction* function, int pc);
};
WasmInterpreter(WasmInstance* instance, AccountingAllocator* allocator);
WasmInterpreter(const ModuleBytesEnv& env, AccountingAllocator* allocator);
~WasmInterpreter();
//==========================================================================

View File

@ -304,7 +304,7 @@ Address GetGlobalStartAddressFromCodeTemplate(Object* undefined,
void InitializeParallelCompilation(
Isolate* isolate, const std::vector<WasmFunction>& functions,
std::vector<compiler::WasmCompilationUnit*>& compilation_units,
ModuleEnv& module_env, ErrorThrower* thrower) {
ModuleBytesEnv& module_env, ErrorThrower* thrower) {
for (uint32_t i = FLAG_skip_compiling_wasm_funcs; i < functions.size(); ++i) {
const WasmFunction* func = &functions[i];
compilation_units[i] =
@ -368,9 +368,10 @@ void FinishCompilationUnits(
}
}
void CompileInParallel(Isolate* isolate, const WasmModule* module,
void CompileInParallel(Isolate* isolate, ModuleBytesEnv* module_env,
std::vector<Handle<Code>>& functions,
ErrorThrower* thrower, ModuleEnv* module_env) {
ErrorThrower* thrower) {
const WasmModule* module = module_env->module;
// Data structures for the parallel compilation.
std::vector<compiler::WasmCompilationUnit*> compilation_units(
module->functions.size());
@ -432,22 +433,23 @@ void CompileInParallel(Isolate* isolate, const WasmModule* module,
FinishCompilationUnits(executed_units, functions, result_mutex);
}
void CompileSequentially(Isolate* isolate, const WasmModule* module,
void CompileSequentially(Isolate* isolate, ModuleBytesEnv* module_env,
std::vector<Handle<Code>>& functions,
ErrorThrower* thrower, ModuleEnv* module_env) {
ErrorThrower* thrower) {
DCHECK(!thrower->error());
const WasmModule* module = module_env->module;
for (uint32_t i = FLAG_skip_compiling_wasm_funcs;
i < module->functions.size(); ++i) {
const WasmFunction& func = module->functions[i];
if (func.imported) continue; // Imports are compiled at instantiation time.
WasmName str = module->GetName(func.name_offset, func.name_length);
Handle<Code> code = Handle<Code>::null();
// Compile the function.
code = compiler::WasmCompilationUnit::CompileWasmFunction(
thrower, isolate, module_env, &func);
if (code.is_null()) {
WasmName str = module_env->GetName(&func);
thrower->CompileError("Compilation of #%d:%.*s failed.", i, str.length(),
str.start());
break;
@ -780,15 +782,12 @@ std::ostream& wasm::operator<<(std::ostream& os, const WasmFunction& function) {
return os;
}
std::ostream& wasm::operator<<(std::ostream& os, const WasmFunctionName& pair) {
os << "#" << pair.function_->func_index << ":";
if (pair.function_->name_offset > 0) {
if (pair.module_) {
WasmName name = pair.module_->GetName(pair.function_->name_offset,
pair.function_->name_length);
os.write(name.start(), name.length());
} else {
os << "+" << pair.function_->func_index;
std::ostream& wasm::operator<<(std::ostream& os, const WasmFunctionName& name) {
os << "#" << name.function_->func_index;
if (name.function_->name_offset > 0) {
if (name.name_.start()) {
os << ":";
os.write(name.name_.start(), name.name_.length());
}
} else {
os << "?";
@ -814,26 +813,24 @@ int wasm::GetFunctionCodeOffset(Handle<WasmCompiledModule> compiled_module,
return GetFunctionOffsetAndLength(compiled_module, func_index).first;
}
WasmModule::WasmModule(Zone* owned, const byte* module_start)
: owned_zone(owned),
module_start(module_start),
pending_tasks(new base::Semaphore(0)) {}
WasmModule::WasmModule(Zone* owned)
: owned_zone(owned), pending_tasks(new base::Semaphore(0)) {}
MaybeHandle<WasmCompiledModule> WasmModule::CompileFunctions(
Isolate* isolate, Handle<WasmModuleWrapper> module_wrapper,
ErrorThrower* thrower) const {
ErrorThrower* thrower, const ModuleWireBytes& wire_bytes) const {
Factory* factory = isolate->factory();
MaybeHandle<WasmCompiledModule> nothing;
WasmInstance temp_instance(this);
temp_instance.context = isolate->native_context();
temp_instance.mem_size = WasmModule::kPageSize * this->min_mem_pages;
temp_instance.mem_size = WasmModule::kPageSize * min_mem_pages;
temp_instance.mem_start = nullptr;
temp_instance.globals_start = nullptr;
// Initialize the indirect tables with placeholders.
int function_table_count = static_cast<int>(this->function_tables.size());
int function_table_count = static_cast<int>(function_tables.size());
Handle<FixedArray> function_tables =
factory->NewFixedArray(function_table_count);
for (int i = 0; i < function_table_count; ++i) {
@ -844,10 +841,7 @@ MaybeHandle<WasmCompiledModule> WasmModule::CompileFunctions(
HistogramTimerScope wasm_compile_module_time_scope(
isolate->counters()->wasm_compile_module_time());
ModuleEnv module_env;
module_env.module = this;
module_env.instance = &temp_instance;
module_env.origin = origin;
ModuleBytesEnv module_env(this, &temp_instance, wire_bytes);
// The {code_table} array contains import wrappers and functions (which
// are both included in {functions.size()}, and export wrappers.
@ -874,14 +868,14 @@ MaybeHandle<WasmCompiledModule> WasmModule::CompileFunctions(
for (size_t i = 0; i < temp_instance.function_code.size(); ++i) {
results.push_back(temp_instance.function_code[i]);
}
CompileInParallel(isolate, this, results, thrower, &module_env);
CompileInParallel(isolate, &module_env, results, thrower);
for (size_t i = 0; i < results.size(); ++i) {
temp_instance.function_code[i] = results[i];
}
} else {
CompileSequentially(isolate, this, temp_instance.function_code, thrower,
&module_env);
CompileSequentially(isolate, &module_env, temp_instance.function_code,
thrower);
}
if (thrower->error()) return nothing;
@ -924,8 +918,8 @@ MaybeHandle<WasmCompiledModule> WasmModule::CompileFunctions(
if (exp.kind != kExternalFunction) continue;
Handle<Code> wasm_code =
code_table->GetValueChecked<Code>(isolate, exp.index);
Handle<Code> wrapper_code = compiler::CompileJSToWasmWrapper(
isolate, &module_env, wasm_code, exp.index);
Handle<Code> wrapper_code =
compiler::CompileJSToWasmWrapper(isolate, this, wasm_code, exp.index);
int export_index = static_cast<int>(functions.size() + func_index);
code_table->set(export_index, *wrapper_code);
func_index++;
@ -934,12 +928,8 @@ MaybeHandle<WasmCompiledModule> WasmModule::CompileFunctions(
{
// TODO(wasm): only save the sections necessary to deserialize a
// {WasmModule}. E.g. function bodies could be omitted.
size_t module_bytes_len = module_end - module_start;
DCHECK_LE(module_bytes_len, static_cast<size_t>(kMaxInt));
Vector<const uint8_t> module_bytes_vec(module_start,
static_cast<int>(module_bytes_len));
Handle<String> module_bytes_string =
factory->NewStringFromOneByte(module_bytes_vec, TENURED)
factory->NewStringFromOneByte(wire_bytes.module_bytes, TENURED)
.ToHandleChecked();
DCHECK(module_bytes_string->IsSeqOneByteString());
ret->set_module_bytes(Handle<SeqOneByteString>::cast(module_bytes_string));
@ -1310,16 +1300,12 @@ class WasmInstanceBuilder {
//--------------------------------------------------------------------------
if (module_->start_function_index >= 0) {
HandleScope scope(isolate_);
ModuleEnv module_env;
module_env.module = module_;
module_env.instance = nullptr;
module_env.origin = module_->origin;
int start_index = module_->start_function_index;
Handle<Code> startup_code =
code_table->GetValueChecked<Code>(isolate_, start_index);
FunctionSig* sig = module_->functions[start_index].sig;
Handle<Code> wrapper_code = compiler::CompileJSToWasmWrapper(
isolate_, &module_env, startup_code, start_index);
isolate_, module_, startup_code, start_index);
Handle<WasmExportedFunction> startup_fct = WasmExportedFunction::New(
isolate_, instance, factory->InternalizeUtf8String("start"),
wrapper_code, static_cast<int>(sig->parameter_count()), start_index);
@ -1894,13 +1880,8 @@ class WasmInstanceBuilder {
temp_instance.mem_start = nullptr;
temp_instance.globals_start = nullptr;
ModuleEnv module_env;
module_env.module = module_;
module_env.instance = &temp_instance;
module_env.origin = module_->origin;
Handle<Code> wrapper_code = compiler::CompileJSToWasmWrapper(
isolate_, &module_env, wasm_code, func_index);
isolate_, module_, wasm_code, func_index);
Handle<WasmExportedFunction> js_function =
WasmExportedFunction::New(
isolate_, instance, isolate_->factory()->empty_string(),
@ -1986,19 +1967,27 @@ Handle<Script> wasm::GetScript(Handle<JSObject> instance) {
return compiled_module->script();
}
// TODO(clemensh): Make this a non-static method of WasmCompiledModule.
std::pair<std::string, std::vector<std::tuple<uint32_t, int, int>>>
wasm::DisassembleFunction(Handle<WasmCompiledModule> compiled_module,
int func_index) {
DisallowHeapAllocation no_gc;
if (func_index < 0 ||
static_cast<uint32_t>(func_index) >=
compiled_module->module()->functions.size())
return {};
SeqOneByteString* module_bytes_str = compiled_module->ptr_to_module_bytes();
Vector<const byte> module_bytes(module_bytes_str->GetChars(),
module_bytes_str->length());
std::ostringstream disassembly_os;
std::vector<std::tuple<uint32_t, int, int>> offset_table;
PrintWasmText(compiled_module->module(), static_cast<uint32_t>(func_index),
disassembly_os, &offset_table);
PrintWasmText(compiled_module->module(), module_bytes,
static_cast<uint32_t>(func_index), disassembly_os,
&offset_table);
return {disassembly_os.str(), std::move(offset_table)};
}
@ -2036,7 +2025,8 @@ MaybeHandle<WasmModuleObject> wasm::CreateModuleObjectFromBytes(
// Compile the functions of the module, producing a compiled module.
MaybeHandle<WasmCompiledModule> maybe_compiled_module =
result.val->CompileFunctions(isolate, module_wrapper, thrower);
result.val->CompileFunctions(isolate, module_wrapper, thrower,
ModuleWireBytes(start, end));
if (maybe_compiled_module.is_null()) return nothing;

View File

@ -177,6 +177,7 @@ struct WasmExport {
};
enum ModuleOrigin { kWasmOrigin, kAsmJsOrigin };
struct ModuleWireBytes;
// Static representation of a module.
struct V8_EXPORT_PRIVATE WasmModule {
@ -187,8 +188,6 @@ struct V8_EXPORT_PRIVATE WasmModule {
static const size_t kV8MaxTableSize = 16 * 1024 * 1024;
Zone* owned_zone;
const byte* module_start = nullptr; // starting address for the module bytes
const byte* module_end = nullptr; // end address for the module bytes
uint32_t min_mem_pages = 0; // minimum size of the memory in 64k pages
uint32_t max_mem_pages = 0; // maximum size of the memory in 64k pages
bool has_memory = false; // true if the memory was defined or imported
@ -220,46 +219,12 @@ struct V8_EXPORT_PRIVATE WasmModule {
// switch to libc-2.21 or higher.
std::unique_ptr<base::Semaphore> pending_tasks;
WasmModule() : WasmModule(nullptr, nullptr) {}
WasmModule(Zone* owned_zone, const byte* module_start);
WasmModule() : WasmModule(nullptr) {}
WasmModule(Zone* owned_zone);
~WasmModule() {
if (owned_zone) delete owned_zone;
}
// Get a string stored in the module bytes representing a name.
WasmName GetName(uint32_t offset, uint32_t length) const {
if (length == 0) return {"<?>", 3}; // no name.
CHECK(BoundsCheck(offset, offset + length));
DCHECK_GE(static_cast<int>(length), 0);
return {reinterpret_cast<const char*>(module_start + offset),
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 (offset == 0 && length == 0) return {NULL, 0}; // no name.
CHECK(BoundsCheck(offset, offset + length));
DCHECK_GE(static_cast<int>(length), 0);
return {reinterpret_cast<const char*>(module_start + offset),
static_cast<int>(length)};
}
// Get a string stored in the module bytes representing a function name.
WasmName GetNameOrNull(const 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;
return start <= size && end <= size;
}
// Creates a new instantiation of the module in the given isolate.
static MaybeHandle<WasmInstanceObject> Instantiate(
Isolate* isolate, ErrorThrower* thrower, Handle<JSObject> wasm_module,
@ -267,7 +232,7 @@ struct V8_EXPORT_PRIVATE WasmModule {
MaybeHandle<WasmCompiledModule> CompileFunctions(
Isolate* isolate, Handle<Managed<WasmModule>> module_wrapper,
ErrorThrower* thrower) const;
ErrorThrower* thrower, const ModuleWireBytes& wire_bytes) const;
};
typedef Managed<WasmModule> WasmModuleWrapper;
@ -294,12 +259,63 @@ struct WasmInstance {
function_code(m->functions.size()) {}
};
// Interface to the storage (wire bytes) of a wasm module.
// It is illegal for anyone receiving a ModuleWireBytes to store pointers based
// on module_bytes, as this storage is only guaranteed to be alive as long as
// this struct is alive.
struct V8_EXPORT_PRIVATE ModuleWireBytes {
ModuleWireBytes(Vector<const byte> module_bytes)
: module_bytes(module_bytes) {}
ModuleWireBytes(const byte* start, const byte* end)
: module_bytes(start, static_cast<int>(end - start)) {
DCHECK_GE(kMaxInt, end - start);
}
const Vector<const byte> module_bytes;
// Get a string stored in the module bytes representing a name.
WasmName GetName(uint32_t offset, uint32_t length) const {
if (length == 0) return {"<?>", 3}; // no name.
CHECK(BoundsCheck(offset, length));
DCHECK_GE(static_cast<int>(length), 0);
return Vector<const char>::cast(
module_bytes.SubVector(offset, offset + length));
}
// Get a string stored in the module bytes representing a function name.
WasmName GetName(const 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 (offset == 0 && length == 0) return {NULL, 0}; // no name.
CHECK(BoundsCheck(offset, length));
DCHECK_GE(static_cast<int>(length), 0);
return Vector<const char>::cast(
module_bytes.SubVector(offset, offset + length));
}
// Get a string stored in the module bytes representing a function name.
WasmName GetNameOrNull(const 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 offset, uint32_t length) const {
uint32_t size = static_cast<uint32_t>(module_bytes.length());
return offset <= size && length <= size - offset;
}
};
// Interface provided to the decoder/graph builder which contains only
// minimal information about the globals, functions, and function tables.
struct V8_EXPORT_PRIVATE ModuleEnv {
ModuleEnv(const WasmModule* module, WasmInstance* instance)
: module(module), instance(instance) {}
const WasmModule* module;
WasmInstance* instance;
ModuleOrigin origin;
bool IsValidGlobal(uint32_t index) const {
return module && index < module->globals.size();
@ -330,7 +346,7 @@ struct V8_EXPORT_PRIVATE ModuleEnv {
return &module->function_tables[index];
}
bool asm_js() { return origin == kAsmJsOrigin; }
bool asm_js() { return module->origin == kAsmJsOrigin; }
Handle<Code> GetFunctionCode(uint32_t index) {
DCHECK_NOT_NULL(instance);
@ -345,12 +361,23 @@ struct V8_EXPORT_PRIVATE ModuleEnv {
Zone* zone, compiler::CallDescriptor* descriptor);
};
// A ModuleEnv together with ModuleWireBytes.
struct ModuleBytesEnv : public ModuleEnv, public ModuleWireBytes {
ModuleBytesEnv(const WasmModule* module, WasmInstance* instance,
Vector<const byte> module_bytes)
: ModuleEnv(module, instance), ModuleWireBytes(module_bytes) {}
ModuleBytesEnv(const WasmModule* module, WasmInstance* instance,
const ModuleWireBytes& wire_bytes)
: ModuleEnv(module, instance), ModuleWireBytes(wire_bytes) {}
};
// A helper for printing out the names of functions.
struct WasmFunctionName {
WasmFunctionName(const WasmFunction* function, ModuleBytesEnv* module_env)
: function_(function), name_(module_env->GetNameOrNull(function)) {}
const WasmFunction* function_;
const WasmModule* module_;
WasmFunctionName(const WasmFunction* function, const ModuleEnv* menv)
: function_(function), module_(menv ? menv->module : nullptr) {}
WasmName name_;
};
std::ostream& operator<<(std::ostream& os, const WasmModule& module);

View File

@ -128,7 +128,8 @@ bool IsValidFunctionName(const Vector<const char> &name) {
} // namespace
void wasm::PrintWasmText(
const WasmModule *module, uint32_t func_index, std::ostream &os,
const WasmModule *module, const ModuleWireBytes &wire_bytes,
uint32_t func_index, std::ostream &os,
std::vector<std::tuple<uint32_t, int, int>> *offset_table) {
DCHECK_NOT_NULL(module);
DCHECK_GT(module->functions.size(), func_index);
@ -141,9 +142,7 @@ void wasm::PrintWasmText(
// Print the function signature.
os << "func";
Vector<const char> fun_name(
reinterpret_cast<const char *>(module->module_start + fun->name_offset),
fun->name_length);
WasmName fun_name = wire_bytes.GetNameOrNull(fun);
if (IsValidFunctionName(fun_name)) {
os << " $";
os.write(fun_name.start(), fun_name.length());
@ -167,10 +166,10 @@ void wasm::PrintWasmText(
// Print the local declarations.
AstLocalDecls decls(&zone);
const byte *code_start = module->module_start + fun->code_start_offset;
const byte *code_end = module->module_start + fun->code_end_offset;
BytecodeIterator i(code_start, code_end, &decls);
DCHECK_LT(code_start, i.pc());
Vector<const byte> func_bytes = wire_bytes.module_bytes.SubVector(
fun->code_start_offset, fun->code_end_offset);
BytecodeIterator i(func_bytes.begin(), func_bytes.end(), &decls);
DCHECK_LT(func_bytes.begin(), i.pc());
if (!decls.local_types.empty()) {
os << "(local";
for (auto p : decls.local_types) {

View File

@ -17,12 +17,13 @@ namespace wasm {
// Forward declaration.
struct WasmModule;
struct ModuleWireBytes;
// Generate disassembly according to official text format.
// Output disassembly to the given output stream, and optionally return an
// offset table of <byte offset, line, column> via the given pointer.
void PrintWasmText(const WasmModule *module, uint32_t func_index,
std::ostream &os,
void PrintWasmText(const WasmModule *module, const ModuleWireBytes &wire_bytes,
uint32_t func_index, std::ostream &os,
std::vector<std::tuple<uint32_t, int, int>> *offset_table);
} // namespace wasm

View File

@ -36,6 +36,13 @@ class ZoneVector : public std::vector<T, zone_allocator<T>> {
// having the value {def}.
ZoneVector(size_t size, T def, Zone* zone)
: std::vector<T, zone_allocator<T>>(size, def, zone_allocator<T>(zone)) {}
// Constructs a new vector and fills it with the contents of the range
// [first, last).
template <class InputIt>
ZoneVector(InputIt first, InputIt last, Zone* zone)
: std::vector<T, zone_allocator<T>>(first, last,
zone_allocator<T>(zone)) {}
};
// A wrapper subclass std::deque to make it easy to construct one

View File

@ -39,7 +39,7 @@ uint32_t GetMatchingRelocInfoCount(Handle<Code> code, RelocInfo::Mode rmode) {
WASM_EXEC_TEST(Int32AsmjsDivS) {
TestingModule module(execution_mode);
module.origin = kAsmJsOrigin;
module.ChangeOriginToAsmjs();
WasmRunner<int32_t> r(&module, MachineType::Int32(), MachineType::Int32());
BUILD(r, WASM_BINOP(kExprI32AsmjsDivS, WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)));
const int32_t kMin = std::numeric_limits<int32_t>::min();
@ -52,7 +52,7 @@ WASM_EXEC_TEST(Int32AsmjsDivS) {
WASM_EXEC_TEST(Int32AsmjsRemS) {
TestingModule module(execution_mode);
module.origin = kAsmJsOrigin;
module.ChangeOriginToAsmjs();
WasmRunner<int32_t> r(&module, MachineType::Int32(), MachineType::Int32());
BUILD(r, WASM_BINOP(kExprI32AsmjsRemS, WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)));
const int32_t kMin = std::numeric_limits<int32_t>::min();
@ -65,7 +65,7 @@ WASM_EXEC_TEST(Int32AsmjsRemS) {
WASM_EXEC_TEST(Int32AsmjsDivU) {
TestingModule module(execution_mode);
module.origin = kAsmJsOrigin;
module.ChangeOriginToAsmjs();
WasmRunner<int32_t> r(&module, MachineType::Int32(), MachineType::Int32());
BUILD(r, WASM_BINOP(kExprI32AsmjsDivU, WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)));
const int32_t kMin = std::numeric_limits<int32_t>::min();
@ -78,7 +78,7 @@ WASM_EXEC_TEST(Int32AsmjsDivU) {
WASM_EXEC_TEST(Int32AsmjsRemU) {
TestingModule module(execution_mode);
module.origin = kAsmJsOrigin;
module.ChangeOriginToAsmjs();
WasmRunner<int32_t> r(&module, MachineType::Int32(), MachineType::Int32());
BUILD(r, WASM_BINOP(kExprI32AsmjsRemU, WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)));
const int32_t kMin = std::numeric_limits<int32_t>::min();
@ -91,7 +91,7 @@ WASM_EXEC_TEST(Int32AsmjsRemU) {
WASM_EXEC_TEST(I32AsmjsSConvertF32) {
TestingModule module(execution_mode);
module.origin = kAsmJsOrigin;
module.ChangeOriginToAsmjs();
WasmRunner<int32_t> r(&module, MachineType::Float32());
BUILD(r, WASM_UNOP(kExprI32AsmjsSConvertF32, WASM_GET_LOCAL(0)));
@ -103,7 +103,7 @@ WASM_EXEC_TEST(I32AsmjsSConvertF32) {
WASM_EXEC_TEST(I32AsmjsSConvertF64) {
TestingModule module(execution_mode);
module.origin = kAsmJsOrigin;
module.ChangeOriginToAsmjs();
WasmRunner<int32_t> r(&module, MachineType::Float64());
BUILD(r, WASM_UNOP(kExprI32AsmjsSConvertF64, WASM_GET_LOCAL(0)));
@ -115,7 +115,7 @@ WASM_EXEC_TEST(I32AsmjsSConvertF64) {
WASM_EXEC_TEST(I32AsmjsUConvertF32) {
TestingModule module(execution_mode);
module.origin = kAsmJsOrigin;
module.ChangeOriginToAsmjs();
WasmRunner<uint32_t> r(&module, MachineType::Float32());
BUILD(r, WASM_UNOP(kExprI32AsmjsUConvertF32, WASM_GET_LOCAL(0)));
@ -127,7 +127,7 @@ WASM_EXEC_TEST(I32AsmjsUConvertF32) {
WASM_EXEC_TEST(I32AsmjsUConvertF64) {
TestingModule module(execution_mode);
module.origin = kAsmJsOrigin;
module.ChangeOriginToAsmjs();
WasmRunner<uint32_t> r(&module, MachineType::Float64());
BUILD(r, WASM_UNOP(kExprI32AsmjsUConvertF64, WASM_GET_LOCAL(0)));
@ -139,7 +139,7 @@ WASM_EXEC_TEST(I32AsmjsUConvertF64) {
WASM_EXEC_TEST(LoadMemI32_oob_asm) {
TestingModule module(execution_mode);
module.origin = kAsmJsOrigin;
module.ChangeOriginToAsmjs();
int32_t* memory = module.AddMemoryElems<int32_t>(8);
WasmRunner<int32_t> r(&module, MachineType::Uint32());
module.RandomizeMemory(1112);
@ -160,7 +160,7 @@ WASM_EXEC_TEST(LoadMemI32_oob_asm) {
WASM_EXEC_TEST(LoadMemF32_oob_asm) {
TestingModule module(execution_mode);
module.origin = kAsmJsOrigin;
module.ChangeOriginToAsmjs();
float* memory = module.AddMemoryElems<float>(8);
WasmRunner<float> r(&module, MachineType::Uint32());
module.RandomizeMemory(1112);
@ -181,7 +181,7 @@ WASM_EXEC_TEST(LoadMemF32_oob_asm) {
WASM_EXEC_TEST(LoadMemF64_oob_asm) {
TestingModule module(execution_mode);
module.origin = kAsmJsOrigin;
module.ChangeOriginToAsmjs();
double* memory = module.AddMemoryElems<double>(8);
WasmRunner<double> r(&module, MachineType::Uint32());
module.RandomizeMemory(1112);
@ -204,7 +204,7 @@ WASM_EXEC_TEST(LoadMemF64_oob_asm) {
WASM_EXEC_TEST(StoreMemI32_oob_asm) {
TestingModule module(execution_mode);
module.origin = kAsmJsOrigin;
module.ChangeOriginToAsmjs();
int32_t* memory = module.AddMemoryElems<int32_t>(8);
WasmRunner<int32_t> r(&module, MachineType::Uint32(), MachineType::Uint32());
module.RandomizeMemory(1112);
@ -240,7 +240,7 @@ WASM_EXEC_TEST(StoreMemI32_oob_asm) {
#define INT_LOAD_TEST(OP_TYPE) \
TEST(RunWasm_AsmCheckedRelocInfo##OP_TYPE) { \
TestingModule module(kExecuteCompiled); \
module.origin = kAsmJsOrigin; \
module.ChangeOriginToAsmjs(); \
WasmRunner<int32_t> r(&module, MachineType::Uint32()); \
BUILD(r, WASM_UNOP(OP_TYPE, WASM_GET_LOCAL(0))); \
CHECK_EQ(1u, GetMatchingRelocInfoCount(module.instance->function_code[0], \
@ -255,7 +255,7 @@ FOREACH_INT_CHECKED_LOAD_OP(INT_LOAD_TEST)
#define INT_STORE_TEST(OP_TYPE) \
TEST(RunWasm_AsmCheckedRelocInfo##OP_TYPE) { \
TestingModule module(kExecuteCompiled); \
module.origin = kAsmJsOrigin; \
module.ChangeOriginToAsmjs(); \
WasmRunner<int32_t> r(&module, MachineType::Uint32(), \
MachineType::Uint32()); \
BUILD(r, WASM_BINOP(OP_TYPE, WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))); \
@ -270,7 +270,7 @@ FOREACH_INT_CHECKED_STORE_OP(INT_STORE_TEST)
TEST(RunWasm_AsmCheckedLoadFloat32RelocInfo) {
TestingModule module(kExecuteCompiled);
module.origin = kAsmJsOrigin;
module.ChangeOriginToAsmjs();
WasmRunner<float> r(&module, MachineType::Uint32());
BUILD(r, WASM_UNOP(kExprF32AsmjsLoadMem, WASM_GET_LOCAL(0)));
@ -283,7 +283,7 @@ TEST(RunWasm_AsmCheckedLoadFloat32RelocInfo) {
TEST(RunWasm_AsmCheckedStoreFloat32RelocInfo) {
TestingModule module(kExecuteCompiled);
module.origin = kAsmJsOrigin;
module.ChangeOriginToAsmjs();
WasmRunner<float> r(&module, MachineType::Uint32(), MachineType::Float32());
BUILD(r, WASM_BINOP(kExprF32AsmjsStoreMem, WASM_GET_LOCAL(0),
WASM_GET_LOCAL(1)));
@ -297,7 +297,7 @@ TEST(RunWasm_AsmCheckedStoreFloat32RelocInfo) {
TEST(RunWasm_AsmCheckedLoadFloat64RelocInfo) {
TestingModule module(kExecuteCompiled);
module.origin = kAsmJsOrigin;
module.ChangeOriginToAsmjs();
WasmRunner<double> r(&module, MachineType::Uint32());
BUILD(r, WASM_UNOP(kExprF64AsmjsLoadMem, WASM_GET_LOCAL(0)));
@ -310,7 +310,7 @@ TEST(RunWasm_AsmCheckedLoadFloat64RelocInfo) {
TEST(RunWasm_AsmCheckedStoreFloat64RelocInfo) {
TestingModule module(kExecuteCompiled);
module.origin = kAsmJsOrigin;
module.ChangeOriginToAsmjs();
WasmRunner<double> r(&module, MachineType::Uint32(), MachineType::Float64());
BUILD(r, WASM_BINOP(kExprF64AsmjsStoreMem, WASM_GET_LOCAL(0),
WASM_GET_LOCAL(1)));

View File

@ -315,8 +315,9 @@ class WasmSerializationTest {
serialization_isolate, const_cast<WasmModule*>(decoding_result.val));
MaybeHandle<WasmCompiledModule> compiled_module =
decoding_result.val->CompileFunctions(serialization_isolate,
module_wrapper, &thrower);
decoding_result.val->CompileFunctions(
serialization_isolate, module_wrapper, &thrower,
ModuleWireBytes(buffer.begin(), buffer.end()));
CHECK(!compiled_module.is_null());
Handle<JSObject> module_obj = WasmModuleObject::New(
serialization_isolate, compiled_module.ToHandleChecked());

View File

@ -72,21 +72,22 @@ const uint32_t kMaxGlobalsSize = 128;
class TestingModule : public ModuleEnv {
public:
explicit TestingModule(WasmExecutionMode mode = kExecuteCompiled)
: execution_mode_(mode),
: ModuleEnv(&module_, &instance_),
execution_mode_(mode),
instance_(&module_),
isolate_(CcTest::InitIsolateOnce()),
global_offset(0),
interpreter_(mode == kExecuteInterpreted
? new WasmInterpreter(&instance_, &allocator_)
? new WasmInterpreter(
ModuleBytesEnv(&module_, &instance_,
Vector<const byte>::empty()),
&allocator_)
: nullptr) {
module = &module_;
instance = &instance_;
instance->module = &module_;
instance->globals_start = global_data;
module_.globals_size = kMaxGlobalsSize;
instance->mem_start = nullptr;
instance->mem_size = 0;
origin = kWasmOrigin;
memset(global_data, 0, sizeof(global_data));
}
@ -97,7 +98,7 @@ class TestingModule : public ModuleEnv {
if (interpreter_) delete interpreter_;
}
void ChangeOriginToAsmjs() { origin = kAsmJsOrigin; }
void ChangeOriginToAsmjs() { module_.origin = kAsmJsOrigin; }
byte* AddMemory(uint32_t size) {
CHECK_NULL(instance->mem_start);
@ -212,7 +213,7 @@ class TestingModule : public ModuleEnv {
Handle<Code> code = instance->function_code[index];
WasmJs::InstallWasmMapsIfNeeded(isolate_, isolate_->native_context());
Handle<Code> ret_code =
compiler::CompileJSToWasmWrapper(isolate_, this, code, index);
compiler::CompileJSToWasmWrapper(isolate_, &module_, code, index);
Handle<JSFunction> ret = WasmExportedFunction::New(
isolate_, instance_obj, name, ret_code,
static_cast<int>(this->module->functions[index].sig->parameter_count()),
@ -481,7 +482,8 @@ class WasmFunctionCompiler : public HandleAndZoneScope,
function_->func_index = 0;
function_->sig_index = 0;
if (mode == kExecuteInterpreted) {
interpreter_ = new WasmInterpreter(nullptr, zone()->allocator());
ModuleBytesEnv empty_env(nullptr, nullptr, Vector<const byte>::empty());
interpreter_ = new WasmInterpreter(empty_env, zone()->allocator());
int index = interpreter_->AddFunctionForTesting(function_);
CHECK_EQ(0, index);
}

View File

@ -46,9 +46,9 @@ const WasmModule* DecodeWasmModuleForTesting(
}
const Handle<WasmInstanceObject> InstantiateModuleForTesting(
Isolate* isolate, ErrorThrower* thrower, const WasmModule* module) {
CHECK(module != nullptr);
Isolate* isolate, ErrorThrower* thrower, const WasmModule* module,
const ModuleWireBytes& wire_bytes) {
DCHECK_NOT_NULL(module);
if (module->import_table.size() > 0) {
thrower->CompileError("Not supported: module has imports.");
}
@ -59,8 +59,9 @@ const Handle<WasmInstanceObject> InstantiateModuleForTesting(
// again through the normal pipeline.
// TODO(wasm): Use {module} instead of decoding the module bytes again.
MaybeHandle<WasmModuleObject> module_object = CreateModuleObjectFromBytes(
isolate, module->module_start, module->module_end, thrower,
ModuleOrigin::kWasmOrigin, Handle<Script>::null(), nullptr, nullptr);
isolate, wire_bytes.module_bytes.start(), wire_bytes.module_bytes.end(),
thrower, ModuleOrigin::kWasmOrigin, Handle<Script>::null(), nullptr,
nullptr);
if (module_object.is_null()) {
thrower->CompileError("Module pre-validation failed.");
return Handle<WasmInstanceObject>::null();
@ -85,7 +86,8 @@ const Handle<WasmInstanceObject> CompileInstantiateWasmModuleForTesting(
thrower->CompileError("Wasm module decoding failed");
return Handle<WasmInstanceObject>::null();
}
return InstantiateModuleForTesting(isolate, thrower, module.get());
return InstantiateModuleForTesting(isolate, thrower, module.get(),
ModuleWireBytes(module_start, module_end));
}
int32_t RunWasmModuleForTesting(Isolate* isolate, Handle<JSObject> instance,
@ -110,10 +112,11 @@ int32_t CompileAndRunWasmModule(Isolate* isolate, const byte* module_start,
}
int32_t InterpretWasmModule(Isolate* isolate, ErrorThrower* thrower,
const WasmModule* module, int function_index,
WasmVal* args, bool* possible_nondeterminism) {
CHECK(module != nullptr);
const WasmModule* module,
const ModuleWireBytes& wire_bytes,
int function_index, WasmVal* args,
bool* possible_nondeterminism) {
DCHECK_NOT_NULL(module);
Zone zone(isolate->allocator(), ZONE_NAME);
v8::internal::HandleScope scope(isolate);
@ -136,7 +139,8 @@ int32_t InterpretWasmModule(Isolate* isolate, ErrorThrower* thrower,
static_cast<byte*>(calloc(GetMinModuleMemSize(module), 1));
instance.globals_start = nullptr;
WasmInterpreter interpreter(&instance, isolate->allocator());
ModuleBytesEnv env(module, &instance, wire_bytes);
WasmInterpreter interpreter(env, isolate->allocator());
WasmInterpreter::Thread* thread = interpreter.GetThread(0);
thread->Reset();

View File

@ -26,7 +26,8 @@ const WasmModule* DecodeWasmModuleForTesting(
// Instantiates a module without any imports and exports.
const Handle<WasmInstanceObject> InstantiateModuleForTesting(
Isolate* isolate, ErrorThrower* thrower, const WasmModule* module);
Isolate* isolate, ErrorThrower* thrower, const WasmModule* module,
const ModuleWireBytes& wire_bytes);
int32_t CallWasmFunctionForTesting(Isolate* isolate, Handle<JSObject> instance,
ErrorThrower* thrower, const char* name,
@ -42,8 +43,10 @@ int32_t CompileAndRunWasmModule(Isolate* isolate, const byte* module_start,
// {function_index}. The return type of the function has to be int32. The module
// should not have any imports or exports
int32_t InterpretWasmModule(Isolate* isolate, ErrorThrower* thrower,
const WasmModule* module, int function_index,
WasmVal* args, bool* may_produced_nan);
const WasmModule* module,
const ModuleWireBytes& wire_bytes,
int function_index, WasmVal* args,
bool* may_produced_nan);
// Compiles WasmModule bytes and return an instance of the compiled module.
const Handle<WasmInstanceObject> CompileInstantiateWasmModuleForTesting(

View File

@ -141,18 +141,19 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
if (module == nullptr) {
return 0;
}
ModuleWireBytes wire_bytes(buffer.begin(), buffer.end());
int32_t result_interpreted;
bool possible_nondeterminism = false;
{
result_interpreted = testing::InterpretWasmModule(
i_isolate, &interpreter_thrower, module.get(), 0, interpreter_args,
&possible_nondeterminism);
i_isolate, &interpreter_thrower, module.get(), wire_bytes, 0,
interpreter_args, &possible_nondeterminism);
}
ErrorThrower compiler_thrower(i_isolate, "Compiler");
v8::internal::Handle<v8::internal::JSObject> instance =
testing::InstantiateModuleForTesting(i_isolate, &compiler_thrower,
module.get());
module.get(), wire_bytes);
if (!interpreter_thrower.error()) {
CHECK(!instance.is_null());

View File

@ -104,19 +104,20 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
os << "})();" << std::endl;
}
ModuleWireBytes wire_bytes(buffer.begin(), buffer.end());
int32_t result_interpreted;
bool possible_nondeterminism = false;
{
WasmVal args[] = {WasmVal(1), WasmVal(2), WasmVal(3)};
result_interpreted = testing::InterpretWasmModule(
i_isolate, &interpreter_thrower, module.get(), 0, args,
i_isolate, &interpreter_thrower, module.get(), wire_bytes, 0, args,
&possible_nondeterminism);
}
ErrorThrower compiler_thrower(i_isolate, "Compiler");
v8::internal::Handle<v8::internal::JSObject> instance =
testing::InstantiateModuleForTesting(i_isolate, &compiler_thrower,
module.get());
module.get(), wire_bytes);
// Restore the flag.
v8::internal::FLAG_wasm_code_fuzzer_gen_test = generate_test;
if (!interpreter_thrower.error()) {

View File

@ -1279,9 +1279,9 @@ namespace {
// globals.
class TestModuleEnv : public ModuleEnv {
public:
TestModuleEnv() {
instance = nullptr;
module = &mod;
explicit TestModuleEnv(ModuleOrigin origin = kWasmOrigin)
: ModuleEnv(&mod, nullptr) {
mod.origin = origin;
}
byte AddGlobal(LocalType type, bool mutability = true) {
mod.globals.push_back({type, mutability, WasmInitExpr(), 0, false, false});
@ -1654,7 +1654,6 @@ TEST_F(AstDecoderTest, AllSetGlobalCombinations) {
TEST_F(AstDecoderTest, WasmGrowMemory) {
TestModuleEnv module_env;
module = &module_env;
module->origin = kWasmOrigin;
byte code[] = {WASM_GET_LOCAL(0), kExprGrowMemory, 0};
EXPECT_VERIFIES_C(i_i, code);
@ -1662,9 +1661,8 @@ TEST_F(AstDecoderTest, WasmGrowMemory) {
}
TEST_F(AstDecoderTest, AsmJsGrowMemory) {
TestModuleEnv module_env;
TestModuleEnv module_env(kAsmJsOrigin);
module = &module_env;
module->origin = kAsmJsOrigin;
byte code[] = {WASM_GET_LOCAL(0), kExprGrowMemory, 0};
EXPECT_FAILURE_C(i_i, code);
@ -1694,9 +1692,8 @@ TEST_F(AstDecoderTest, AsmJsBinOpsCheckOrigin) {
};
{
TestModuleEnv module_env;
TestModuleEnv module_env(kAsmJsOrigin);
module = &module_env;
module->origin = kAsmJsOrigin;
for (size_t i = 0; i < arraysize(AsmJsBinOps); i++) {
TestBinop(AsmJsBinOps[i].op, AsmJsBinOps[i].sig);
}
@ -1705,7 +1702,6 @@ TEST_F(AstDecoderTest, AsmJsBinOpsCheckOrigin) {
{
TestModuleEnv module_env;
module = &module_env;
module->origin = kWasmOrigin;
for (size_t i = 0; i < arraysize(AsmJsBinOps); i++) {
byte code[] = {
WASM_BINOP(AsmJsBinOps[i].op, WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))};
@ -1742,9 +1738,8 @@ TEST_F(AstDecoderTest, AsmJsUnOpsCheckOrigin) {
{kExprI32AsmjsSConvertF64, sigs.i_d()},
{kExprI32AsmjsUConvertF64, sigs.i_d()}};
{
TestModuleEnv module_env;
TestModuleEnv module_env(kAsmJsOrigin);
module = &module_env;
module->origin = kAsmJsOrigin;
for (size_t i = 0; i < arraysize(AsmJsUnOps); i++) {
TestUnop(AsmJsUnOps[i].op, AsmJsUnOps[i].sig);
}
@ -1753,7 +1748,6 @@ TEST_F(AstDecoderTest, AsmJsUnOpsCheckOrigin) {
{
TestModuleEnv module_env;
module = &module_env;
module->origin = kWasmOrigin;
for (size_t i = 0; i < arraysize(AsmJsUnOps); i++) {
byte code[] = {WASM_UNOP(AsmJsUnOps[i].op, WASM_GET_LOCAL(0))};
EXPECT_FAILURE_SC(AsmJsUnOps[i].sig, code);