[wasm] Move the ModuleEnv to compiler and make it immutable.
This CL (finally) makes the contract between the compiler and the module environment clear. In order to compile a function, the caller must provide an instance of the compiler::ModuleEnv struct, which contains references to code, function and signature tables, memory start, etc. R=mtrofin@chromium.org,ahaas@chromium.org Bug: Change-Id: I68e44d5da2c5ad44dad402029c2e57f2d5d25b4f Reviewed-on: https://chromium-review.googlesource.com/613880 Reviewed-by: Mircea Trofin <mtrofin@chromium.org> Reviewed-by: Andreas Haas <ahaas@chromium.org> Commit-Queue: Ben Titzer <titzer@chromium.org> Cr-Commit-Position: refs/heads/master@{#47418}
This commit is contained in:
parent
af4f152063
commit
d04660db3f
@ -67,13 +67,13 @@ void MergeControlToEnd(JSGraph* jsgraph, Node* node) {
|
||||
} // namespace
|
||||
|
||||
WasmGraphBuilder::WasmGraphBuilder(
|
||||
const wasm::ModuleEnv* module_env, Zone* zone, JSGraph* jsgraph,
|
||||
Handle<Code> centry_stub, wasm::FunctionSig* sig,
|
||||
ModuleEnv* env, Zone* zone, JSGraph* jsgraph, Handle<Code> centry_stub,
|
||||
wasm::FunctionSig* sig,
|
||||
compiler::SourcePositionTable* source_position_table)
|
||||
: zone_(zone),
|
||||
jsgraph_(jsgraph),
|
||||
centry_stub_node_(jsgraph_->HeapConstant(centry_stub)),
|
||||
module_env_(module_env),
|
||||
env_(env),
|
||||
signature_tables_(zone),
|
||||
function_tables_(zone),
|
||||
function_table_sizes_(zone),
|
||||
@ -192,10 +192,9 @@ Node* WasmGraphBuilder::Int64Constant(int64_t value) {
|
||||
|
||||
void WasmGraphBuilder::StackCheck(wasm::WasmCodePosition position,
|
||||
Node** effect, Node** control) {
|
||||
// TODO(mtrofin): "!module_" happens when we generate a wrapper.
|
||||
// TODO(mtrofin): "!env_" happens when we generate a wrapper.
|
||||
// We should factor wrappers separately from wasm codegen.
|
||||
if (FLAG_wasm_no_stack_checks || !module_env_ ||
|
||||
!has_runtime_exception_support_) {
|
||||
if (FLAG_wasm_no_stack_checks || !env_ || !has_runtime_exception_support_) {
|
||||
return;
|
||||
}
|
||||
if (effect == nullptr) effect = effect_;
|
||||
@ -2226,12 +2225,13 @@ Node* WasmGraphBuilder::CallDirect(uint32_t index, Node** args, Node*** rets,
|
||||
DCHECK_NULL(args[0]);
|
||||
|
||||
// Add code object as constant.
|
||||
// TODO(wasm): Always use the illegal builtin, except for testing.
|
||||
Handle<Code> code = module_env_->GetFunctionCode(index);
|
||||
Handle<Code> code = index < env_->function_code.size()
|
||||
? env_->function_code[index]
|
||||
: env_->default_function_code;
|
||||
|
||||
DCHECK(!code.is_null());
|
||||
args[0] = HeapConstant(code);
|
||||
wasm::FunctionSig* sig = module_env_->GetFunctionSignature(index);
|
||||
wasm::FunctionSig* sig = env_->module->functions[index].sig;
|
||||
|
||||
return BuildWasmCall(sig, args, rets, position);
|
||||
}
|
||||
@ -2240,13 +2240,11 @@ Node* WasmGraphBuilder::CallIndirect(uint32_t sig_index, Node** args,
|
||||
Node*** rets,
|
||||
wasm::WasmCodePosition position) {
|
||||
DCHECK_NOT_NULL(args[0]);
|
||||
DCHECK_NOT_NULL(module_env_);
|
||||
DCHECK_NOT_NULL(env_);
|
||||
|
||||
// Assume only one table for now.
|
||||
uint32_t table_index = 0;
|
||||
wasm::FunctionSig* sig = module_env_->GetSignature(sig_index);
|
||||
|
||||
DCHECK(module_env_->IsValidTable(table_index));
|
||||
wasm::FunctionSig* sig = env_->module->signatures[sig_index];
|
||||
|
||||
EnsureFunctionTableNodes();
|
||||
MachineOperatorBuilder* machine = jsgraph()->machine();
|
||||
@ -2272,10 +2270,10 @@ Node* WasmGraphBuilder::CallIndirect(uint32_t sig_index, Node** args,
|
||||
Int32Constant(kPointerSizeLog2)),
|
||||
Int32Constant(fixed_offset)),
|
||||
*effect_, *control_);
|
||||
auto& map = module_env_->module()->function_tables[0].map;
|
||||
auto map = env_->signature_maps[table_index];
|
||||
Node* sig_match = graph()->NewNode(
|
||||
machine->WordEqual(), load_sig,
|
||||
jsgraph()->SmiConstant(static_cast<int>(map.FindOrInsert(sig))));
|
||||
jsgraph()->SmiConstant(static_cast<int>(map->FindOrInsert(sig))));
|
||||
TrapIfFalse(wasm::kTrapFuncSigMismatch, sig_match, position);
|
||||
}
|
||||
|
||||
@ -2953,8 +2951,8 @@ void WasmGraphBuilder::BuildCWasmEntry() {
|
||||
}
|
||||
|
||||
Node* WasmGraphBuilder::MemBuffer(uint32_t offset) {
|
||||
DCHECK_NOT_NULL(module_env_);
|
||||
uintptr_t mem_start = reinterpret_cast<uintptr_t>(module_env_->mem_start());
|
||||
DCHECK_NOT_NULL(env_);
|
||||
uintptr_t mem_start = reinterpret_cast<uintptr_t>(env_->mem_start);
|
||||
if (offset == 0) {
|
||||
if (!mem_buffer_) {
|
||||
mem_buffer_ = jsgraph()->RelocatableIntPtrConstant(
|
||||
@ -2970,7 +2968,7 @@ Node* WasmGraphBuilder::MemBuffer(uint32_t offset) {
|
||||
|
||||
Node* WasmGraphBuilder::CurrentMemoryPages() {
|
||||
// CurrentMemoryPages can not be called from asm.js.
|
||||
DCHECK_EQ(wasm::kWasmOrigin, module_env_->module()->origin());
|
||||
DCHECK_EQ(wasm::kWasmOrigin, env_->module->origin());
|
||||
SetNeedsStackCheck();
|
||||
Node* call = BuildCallToRuntime(Runtime::kWasmMemorySize, nullptr, 0);
|
||||
Node* result = BuildChangeSmiToInt32(call);
|
||||
@ -2978,9 +2976,9 @@ Node* WasmGraphBuilder::CurrentMemoryPages() {
|
||||
}
|
||||
|
||||
Node* WasmGraphBuilder::MemSize() {
|
||||
DCHECK_NOT_NULL(module_env_);
|
||||
DCHECK_NOT_NULL(env_);
|
||||
if (mem_size_) return mem_size_;
|
||||
uint32_t size = module_env_->mem_size();
|
||||
uint32_t size = env_->mem_size;
|
||||
mem_size_ = jsgraph()->RelocatableInt32Constant(
|
||||
size, RelocInfo::WASM_MEMORY_SIZE_REFERENCE);
|
||||
return mem_size_;
|
||||
@ -2988,17 +2986,13 @@ Node* WasmGraphBuilder::MemSize() {
|
||||
|
||||
void WasmGraphBuilder::EnsureFunctionTableNodes() {
|
||||
if (function_tables_.size() > 0) return;
|
||||
size_t tables_size = module_env_->module()->function_tables.size();
|
||||
DCHECK_EQ(tables_size, module_env_->function_tables().size());
|
||||
DCHECK_EQ(tables_size, module_env_->signature_tables().size());
|
||||
|
||||
size_t tables_size = env_->function_tables.size();
|
||||
for (size_t i = 0; i < tables_size; ++i) {
|
||||
auto function_handle = module_env_->function_tables()[i];
|
||||
auto signature_handle = module_env_->signature_tables()[i];
|
||||
auto function_handle = env_->function_tables[i];
|
||||
auto signature_handle = env_->signature_tables[i];
|
||||
function_tables_.push_back(HeapConstant(function_handle));
|
||||
signature_tables_.push_back(HeapConstant(signature_handle));
|
||||
uint32_t table_size =
|
||||
module_env_->module()->function_tables[i].initial_size;
|
||||
uint32_t table_size = env_->module->function_tables[i].initial_size;
|
||||
function_table_sizes_.push_back(jsgraph()->RelocatableInt32Constant(
|
||||
static_cast<uint32_t>(table_size),
|
||||
RelocInfo::WASM_FUNCTION_TABLE_SIZE_REFERENCE));
|
||||
@ -3096,10 +3090,9 @@ Node* WasmGraphBuilder::BuildCallToRuntime(Runtime::FunctionId f,
|
||||
|
||||
Node* WasmGraphBuilder::GetGlobal(uint32_t index) {
|
||||
MachineType mem_type =
|
||||
wasm::WasmOpcodes::MachineTypeFor(module_env_->GetGlobalType(index));
|
||||
byte* globals_start = module_env_->globals_start();
|
||||
uintptr_t global_addr = reinterpret_cast<uintptr_t>(
|
||||
globals_start + module_env_->module()->globals[index].offset);
|
||||
wasm::WasmOpcodes::MachineTypeFor(env_->module->globals[index].type);
|
||||
uintptr_t global_addr =
|
||||
env_->globals_start + env_->module->globals[index].offset;
|
||||
Node* addr = jsgraph()->RelocatableIntPtrConstant(
|
||||
global_addr, RelocInfo::WASM_GLOBAL_REFERENCE);
|
||||
const Operator* op = jsgraph()->machine()->Load(mem_type);
|
||||
@ -3111,12 +3104,11 @@ Node* WasmGraphBuilder::GetGlobal(uint32_t index) {
|
||||
|
||||
Node* WasmGraphBuilder::SetGlobal(uint32_t index, Node* val) {
|
||||
MachineType mem_type =
|
||||
wasm::WasmOpcodes::MachineTypeFor(module_env_->GetGlobalType(index));
|
||||
byte* globals_start = module_env_->globals_start();
|
||||
wasm::WasmOpcodes::MachineTypeFor(env_->module->globals[index].type);
|
||||
uintptr_t global_addr =
|
||||
env_->globals_start + env_->module->globals[index].offset;
|
||||
Node* addr = jsgraph()->RelocatableIntPtrConstant(
|
||||
reinterpret_cast<uintptr_t>(globals_start +
|
||||
module_env_->module()->globals[index].offset),
|
||||
RelocInfo::WASM_GLOBAL_REFERENCE);
|
||||
global_addr, RelocInfo::WASM_GLOBAL_REFERENCE);
|
||||
const Operator* op = jsgraph()->machine()->Store(
|
||||
StoreRepresentation(mem_type.representation(), kNoWriteBarrier));
|
||||
Node* node = graph()->NewNode(op, addr, jsgraph()->Int32Constant(0), val,
|
||||
@ -3129,49 +3121,50 @@ void WasmGraphBuilder::BoundsCheckMem(MachineType memtype, Node* index,
|
||||
uint32_t offset,
|
||||
wasm::WasmCodePosition position) {
|
||||
if (FLAG_wasm_no_bounds_checks) return;
|
||||
uint32_t size = module_env_->mem_size();
|
||||
byte memsize = wasm::WasmOpcodes::MemSize(memtype);
|
||||
|
||||
size_t effective_size;
|
||||
if (size <= offset || size < (static_cast<uint64_t>(offset) + memsize)) {
|
||||
// Two checks are needed in the case where the offset is statically
|
||||
// out of bounds; one check for the offset being in bounds, and the next for
|
||||
// the offset + index being out of bounds for code to be patched correctly
|
||||
// on relocation.
|
||||
uint64_t min_size = static_cast<uint64_t>(env_->module->initial_pages) *
|
||||
wasm::WasmModule::kPageSize;
|
||||
uint64_t max_size = static_cast<uint64_t>(env_->module->has_maximum_pages
|
||||
? env_->module->maximum_pages
|
||||
: wasm::kV8MaxWasmMemoryPages) *
|
||||
wasm::WasmModule::kPageSize;
|
||||
|
||||
// Check for overflows.
|
||||
if ((std::numeric_limits<uint32_t>::max() - memsize) + 1 < offset) {
|
||||
// Always trap. Do not use TrapAlways because it does not create a valid
|
||||
// graph here.
|
||||
TrapIfEq32(wasm::kTrapMemOutOfBounds, jsgraph()->Int32Constant(0), 0,
|
||||
position);
|
||||
return;
|
||||
}
|
||||
size_t effective_offset = (offset - 1) + memsize;
|
||||
byte access_size = wasm::WasmOpcodes::MemSize(memtype);
|
||||
|
||||
Node* cond = graph()->NewNode(jsgraph()->machine()->Uint32LessThan(),
|
||||
jsgraph()->IntPtrConstant(effective_offset),
|
||||
jsgraph()->RelocatableInt32Constant(
|
||||
static_cast<uint32_t>(size),
|
||||
RelocInfo::WASM_MEMORY_SIZE_REFERENCE));
|
||||
uint64_t end_offset = static_cast<uint64_t>(offset) + access_size;
|
||||
if (end_offset > max_size) {
|
||||
// The access will be out of bounds, even for the largest memory.
|
||||
TrapIfEq32(wasm::kTrapMemOutOfBounds, jsgraph()->Int32Constant(0), 0,
|
||||
position);
|
||||
return;
|
||||
}
|
||||
|
||||
if (end_offset > min_size) {
|
||||
// The end offset is larger than the smallest memory.
|
||||
// Dynamically check the end offset against the actual memory size, which
|
||||
// is not known at compile time.
|
||||
Node* cond = graph()->NewNode(
|
||||
jsgraph()->machine()->Uint32LessThanOrEqual(),
|
||||
jsgraph()->IntPtrConstant(static_cast<uintptr_t>(end_offset)),
|
||||
jsgraph()->RelocatableInt32Constant(
|
||||
static_cast<uint32_t>(env_->mem_size),
|
||||
RelocInfo::WASM_MEMORY_SIZE_REFERENCE));
|
||||
TrapIfFalse(wasm::kTrapMemOutOfBounds, cond, position);
|
||||
// For offset > effective size, this relies on check above to fail and
|
||||
// effective size can be negative, relies on wrap around.
|
||||
effective_size = size - offset - memsize + 1;
|
||||
} else {
|
||||
effective_size = size - offset - memsize + 1;
|
||||
CHECK(effective_size <= kMaxUInt32);
|
||||
|
||||
// The end offset is within the bounds of the smallest memory, so only
|
||||
// one check is required. Check to see if the index is also a constant.
|
||||
Uint32Matcher m(index);
|
||||
if (m.HasValue()) {
|
||||
uint32_t value = m.Value();
|
||||
if (value < effective_size) {
|
||||
// The bounds check will always succeed.
|
||||
uint64_t index_val = m.Value();
|
||||
if ((index_val + offset + access_size) <= min_size) {
|
||||
// The input index is a constant and everything is statically within
|
||||
// bounds of the smallest possible memory.
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t effective_size = env_->mem_size - (end_offset - 1);
|
||||
Node* cond = graph()->NewNode(jsgraph()->machine()->Uint32LessThan(), index,
|
||||
jsgraph()->RelocatableInt32Constant(
|
||||
static_cast<uint32_t>(effective_size),
|
||||
@ -3824,11 +3817,18 @@ Handle<Code> CompileJSToWasmWrapper(Isolate* isolate, wasm::WasmModule* module,
|
||||
Node* control = nullptr;
|
||||
Node* effect = nullptr;
|
||||
|
||||
// TODO(mtrofin): refactor CompileJSToWasmWrapper to not require a module_env.
|
||||
// It's not really applicable.
|
||||
wasm::ModuleEnv module_env(module, BUILTIN_CODE(isolate, Illegal));
|
||||
// TODO(titzer): compile JS to WASM wrappers without a {ModuleEnv}.
|
||||
ModuleEnv env = {module,
|
||||
std::vector<Handle<FixedArray>>(), // function_tables
|
||||
std::vector<Handle<FixedArray>>(), // signature_tables
|
||||
std::vector<wasm::SignatureMap*>(), // signature_maps
|
||||
std::vector<Handle<Code>>(), // function_code
|
||||
BUILTIN_CODE(isolate, Illegal), // default_function_code
|
||||
0,
|
||||
0,
|
||||
0};
|
||||
|
||||
WasmGraphBuilder builder(&module_env, &zone, &jsgraph,
|
||||
WasmGraphBuilder builder(&env, &zone, &jsgraph,
|
||||
CEntryStub(isolate, 1).GetCode(), func->sig);
|
||||
builder.set_control_ptr(&control);
|
||||
builder.set_effect_ptr(&effect);
|
||||
@ -3844,8 +3844,8 @@ Handle<Code> CompileJSToWasmWrapper(Isolate* isolate, wasm::WasmModule* module,
|
||||
}
|
||||
|
||||
// Schedule and compile to machine code.
|
||||
int params = static_cast<int>(
|
||||
module_env.GetFunctionSignature(index)->parameter_count());
|
||||
int params =
|
||||
static_cast<int>(module->functions[index].sig->parameter_count());
|
||||
CallDescriptor* incoming = Linkage::GetJSCallDescriptor(
|
||||
&zone, false, params + 1, CallDescriptor::kNoFlags);
|
||||
Code::Flags flags = Code::ComputeFlags(Code::JS_TO_WASM_FUNCTION);
|
||||
@ -4103,6 +4103,15 @@ Handle<Code> CompileCWasmEntry(Isolate* isolate, wasm::FunctionSig* sig) {
|
||||
|
||||
SourcePositionTable* WasmCompilationUnit::BuildGraphForWasmFunction(
|
||||
double* decode_ms) {
|
||||
#if DEBUG
|
||||
if (env_) {
|
||||
size_t tables_size = env_->module->function_tables.size();
|
||||
DCHECK_EQ(tables_size, env_->function_tables.size());
|
||||
DCHECK_EQ(tables_size, env_->signature_tables.size());
|
||||
DCHECK_EQ(tables_size, env_->signature_maps.size());
|
||||
}
|
||||
#endif
|
||||
|
||||
base::ElapsedTimer decode_timer;
|
||||
if (FLAG_trace_wasm_decode_time) {
|
||||
decode_timer.Start();
|
||||
@ -4111,8 +4120,8 @@ SourcePositionTable* WasmCompilationUnit::BuildGraphForWasmFunction(
|
||||
|
||||
SourcePositionTable* source_position_table =
|
||||
new (jsgraph_->zone()) SourcePositionTable(jsgraph_->graph());
|
||||
WasmGraphBuilder builder(module_env_, jsgraph_->zone(), jsgraph_,
|
||||
centry_stub_, func_body_.sig, source_position_table);
|
||||
WasmGraphBuilder builder(env_, jsgraph_->zone(), jsgraph_, centry_stub_,
|
||||
func_body_.sig, source_position_table);
|
||||
graph_construction_result_ =
|
||||
wasm::BuildTFGraph(isolate_->allocator(), &builder, func_body_);
|
||||
|
||||
@ -4133,7 +4142,7 @@ SourcePositionTable* WasmCompilationUnit::BuildGraphForWasmFunction(
|
||||
|
||||
if (func_index_ >= FLAG_trace_wasm_ast_start &&
|
||||
func_index_ < FLAG_trace_wasm_ast_end) {
|
||||
PrintRawWasmCode(isolate_->allocator(), func_body_, module_env_->module());
|
||||
PrintRawWasmCode(isolate_->allocator(), func_body_, env_->module);
|
||||
}
|
||||
if (FLAG_trace_wasm_decode_time) {
|
||||
*decode_ms = decode_timer.Elapsed().InMillisecondsF();
|
||||
@ -4162,24 +4171,22 @@ Vector<const char> GetDebugName(Zone* zone, wasm::WasmName name, int index) {
|
||||
} // namespace
|
||||
|
||||
WasmCompilationUnit::WasmCompilationUnit(
|
||||
Isolate* isolate, const wasm::ModuleWireBytes& wire_bytes,
|
||||
const wasm::ModuleEnv* module_env, const wasm::WasmFunction* function,
|
||||
Handle<Code> centry_stub)
|
||||
Isolate* isolate, const wasm::ModuleWireBytes& wire_bytes, ModuleEnv* env,
|
||||
const wasm::WasmFunction* function, Handle<Code> centry_stub)
|
||||
: WasmCompilationUnit(
|
||||
isolate, module_env,
|
||||
isolate, env,
|
||||
wasm::FunctionBody{function->sig, function->code.offset(),
|
||||
wire_bytes.start() + function->code.offset(),
|
||||
wire_bytes.start() + function->code.end_offset()},
|
||||
wire_bytes.GetNameOrNull(function), function->func_index,
|
||||
centry_stub) {}
|
||||
|
||||
WasmCompilationUnit::WasmCompilationUnit(Isolate* isolate,
|
||||
const wasm::ModuleEnv* module_env,
|
||||
WasmCompilationUnit::WasmCompilationUnit(Isolate* isolate, ModuleEnv* env,
|
||||
wasm::FunctionBody body,
|
||||
wasm::WasmName name, int index,
|
||||
Handle<Code> centry_stub)
|
||||
: isolate_(isolate),
|
||||
module_env_(module_env),
|
||||
env_(env),
|
||||
func_body_(body),
|
||||
func_name_(name),
|
||||
counters_(isolate->counters()),
|
||||
@ -4187,11 +4194,11 @@ WasmCompilationUnit::WasmCompilationUnit(Isolate* isolate,
|
||||
func_index_(index) {}
|
||||
|
||||
WasmCompilationUnit::WasmCompilationUnit(
|
||||
Isolate* isolate, const wasm::ModuleWireBytes& wire_bytes,
|
||||
const wasm::ModuleEnv* module_env, const wasm::WasmFunction* function,
|
||||
Handle<Code> centry_stub, const std::shared_ptr<Counters>& async_counters)
|
||||
Isolate* isolate, const wasm::ModuleWireBytes& wire_bytes, ModuleEnv* env,
|
||||
const wasm::WasmFunction* function, Handle<Code> centry_stub,
|
||||
const std::shared_ptr<Counters>& async_counters)
|
||||
: WasmCompilationUnit(
|
||||
isolate, module_env,
|
||||
isolate, env,
|
||||
wasm::FunctionBody{function->sig, function->code.offset(),
|
||||
wire_bytes.start() + function->code.offset(),
|
||||
wire_bytes.start() + function->code.end_offset()},
|
||||
@ -4199,11 +4206,11 @@ WasmCompilationUnit::WasmCompilationUnit(
|
||||
async_counters) {}
|
||||
|
||||
WasmCompilationUnit::WasmCompilationUnit(
|
||||
Isolate* isolate, const wasm::ModuleEnv* module_env,
|
||||
wasm::FunctionBody body, wasm::WasmName name, int index,
|
||||
Handle<Code> centry_stub, const std::shared_ptr<Counters>& async_counters)
|
||||
Isolate* isolate, ModuleEnv* env, wasm::FunctionBody body,
|
||||
wasm::WasmName name, int index, Handle<Code> centry_stub,
|
||||
const std::shared_ptr<Counters>& async_counters)
|
||||
: isolate_(isolate),
|
||||
module_env_(module_env),
|
||||
env_(env),
|
||||
func_body_(body),
|
||||
func_name_(name),
|
||||
counters_(async_counters.get()),
|
||||
@ -4211,7 +4218,7 @@ WasmCompilationUnit::WasmCompilationUnit(
|
||||
func_index_(index) {}
|
||||
|
||||
void WasmCompilationUnit::ExecuteCompilation() {
|
||||
auto timed_histogram = module_env_->is_wasm()
|
||||
auto timed_histogram = env_->module->is_wasm()
|
||||
? counters()->wasm_compile_wasm_function_time()
|
||||
: counters()->wasm_compile_asm_function_time();
|
||||
TimedHistogramScope wasm_compile_function_time_scope(timed_histogram);
|
||||
@ -4270,7 +4277,7 @@ void WasmCompilationUnit::ExecuteCompilation() {
|
||||
|
||||
job_.reset(Pipeline::NewWasmCompilationJob(
|
||||
info_.get(), jsgraph_, descriptor, source_positions,
|
||||
&protected_instructions, module_env_->module()->origin()));
|
||||
&protected_instructions, env_->module->origin()));
|
||||
ok_ = job_->ExecuteJob() == CompilationJob::SUCCEEDED;
|
||||
// TODO(bradnelson): Improve histogram handling of size_t.
|
||||
counters()->wasm_compile_function_peak_memory_bytes()->AddSample(
|
||||
@ -4341,9 +4348,9 @@ MaybeHandle<Code> WasmCompilationUnit::FinishCompilation(
|
||||
// static
|
||||
MaybeHandle<Code> WasmCompilationUnit::CompileWasmFunction(
|
||||
wasm::ErrorThrower* thrower, Isolate* isolate,
|
||||
const wasm::ModuleWireBytes& wire_bytes, const wasm::ModuleEnv* module_env,
|
||||
const wasm::ModuleWireBytes& wire_bytes, ModuleEnv* env,
|
||||
const wasm::WasmFunction* function) {
|
||||
WasmCompilationUnit unit(isolate, wire_bytes, module_env, function,
|
||||
WasmCompilationUnit unit(isolate, wire_bytes, env, function,
|
||||
CEntryStub(isolate, 1).GetCode());
|
||||
unit.ExecuteCompilation();
|
||||
return unit.FinishCompilation(thrower);
|
||||
|
@ -32,33 +32,67 @@ class SourcePositionTable;
|
||||
|
||||
namespace wasm {
|
||||
struct DecodeStruct;
|
||||
class SignatureMap;
|
||||
// Expose {Node} and {Graph} opaquely as {wasm::TFNode} and {wasm::TFGraph}.
|
||||
typedef compiler::Node TFNode;
|
||||
typedef compiler::JSGraph TFGraph;
|
||||
} // namespace wasm
|
||||
|
||||
namespace compiler {
|
||||
|
||||
// The {ModuleEnv} encapsulates the module data that is used by the
|
||||
// {WasmGraphBuilder} during graph building. It represents the parameters to
|
||||
// which the compiled code should be specialized, including which code to call
|
||||
// for direct calls {function_code}, which tables to use for indirect calls
|
||||
// {function_tables}, memory start address and size {mem_start, mem_size},
|
||||
// globals start address {globals_start}, as well as signature maps
|
||||
// {signature_maps} and the module itself {module}.
|
||||
// ModuleEnvs are shareable across multiple compilations.
|
||||
struct ModuleEnv {
|
||||
// A pointer to the decoded module's static representation.
|
||||
const wasm::WasmModule* module;
|
||||
// The function tables are FixedArrays of code used to dispatch indirect
|
||||
// calls. (the same length as module.function_tables)
|
||||
const std::vector<Handle<FixedArray>> function_tables;
|
||||
// The signatures tables are FixedArrays of SMIs used to check signatures
|
||||
// match at runtime.
|
||||
// (the same length as module.function_tables)
|
||||
const std::vector<Handle<FixedArray>> signature_tables;
|
||||
// Signature maps canonicalize {FunctionSig*} to indexes. New entries can be
|
||||
// added to a signature map during graph building.
|
||||
// Normally, these signature maps correspond to the signature maps in the
|
||||
// function tables stored in the {module}.
|
||||
const std::vector<wasm::SignatureMap*> signature_maps;
|
||||
// Contains the code objects to call for each indirect call.
|
||||
// (the same length as module.functions)
|
||||
const std::vector<Handle<Code>> function_code;
|
||||
// If the default code is not a null handle, always use it for direct calls.
|
||||
const Handle<Code> default_function_code;
|
||||
// Address of the start of memory.
|
||||
const uintptr_t mem_start;
|
||||
// Size of memory in bytes.
|
||||
const uint32_t mem_size;
|
||||
// Address of the start of the globals region.
|
||||
const uintptr_t globals_start;
|
||||
};
|
||||
|
||||
class WasmCompilationUnit final {
|
||||
public:
|
||||
// Use the following constructors if you know you are running on the
|
||||
// foreground thread.
|
||||
WasmCompilationUnit(Isolate* isolate, const wasm::ModuleWireBytes& wire_bytes,
|
||||
const wasm::ModuleEnv* module_env,
|
||||
const wasm::WasmFunction* function,
|
||||
Handle<Code> centry_stub);
|
||||
WasmCompilationUnit(Isolate* isolate, const wasm::ModuleEnv* module_env,
|
||||
wasm::FunctionBody body, wasm::WasmName name, int index,
|
||||
ModuleEnv* env, const wasm::WasmFunction* function,
|
||||
Handle<Code> centry_stub);
|
||||
WasmCompilationUnit(Isolate* isolate, ModuleEnv* env, wasm::FunctionBody body,
|
||||
wasm::WasmName name, int index, Handle<Code> centry_stub);
|
||||
// Use the following constructors if the compilation may run on a background
|
||||
// thread.
|
||||
WasmCompilationUnit(Isolate* isolate, const wasm::ModuleWireBytes& wire_bytes,
|
||||
const wasm::ModuleEnv* module_env,
|
||||
const wasm::WasmFunction* function,
|
||||
ModuleEnv* env, const wasm::WasmFunction* function,
|
||||
Handle<Code> centry_stub,
|
||||
const std::shared_ptr<Counters>& async_counters);
|
||||
WasmCompilationUnit(Isolate* isolate, const wasm::ModuleEnv* module_env,
|
||||
wasm::FunctionBody body, wasm::WasmName name, int index,
|
||||
Handle<Code> centry_stub,
|
||||
WasmCompilationUnit(Isolate* isolate, ModuleEnv* env, wasm::FunctionBody body,
|
||||
wasm::WasmName name, int index, Handle<Code> centry_stub,
|
||||
const std::shared_ptr<Counters>& async_counters);
|
||||
|
||||
int func_index() const { return func_index_; }
|
||||
@ -68,8 +102,8 @@ class WasmCompilationUnit final {
|
||||
|
||||
static MaybeHandle<Code> CompileWasmFunction(
|
||||
wasm::ErrorThrower* thrower, Isolate* isolate,
|
||||
const wasm::ModuleWireBytes& wire_bytes,
|
||||
const wasm::ModuleEnv* module_env, const wasm::WasmFunction* function);
|
||||
const wasm::ModuleWireBytes& wire_bytes, ModuleEnv* env,
|
||||
const wasm::WasmFunction* function);
|
||||
|
||||
void set_memory_cost(size_t memory_cost) { memory_cost_ = memory_cost; }
|
||||
size_t memory_cost() const { return memory_cost_; }
|
||||
@ -78,7 +112,7 @@ class WasmCompilationUnit final {
|
||||
SourcePositionTable* BuildGraphForWasmFunction(double* decode_ms);
|
||||
|
||||
Isolate* isolate_;
|
||||
const wasm::ModuleEnv* module_env_;
|
||||
ModuleEnv* env_;
|
||||
wasm::FunctionBody func_body_;
|
||||
wasm::WasmName func_name_;
|
||||
Counters* counters_;
|
||||
@ -137,8 +171,8 @@ typedef ZoneVector<Node*> NodeVector;
|
||||
class WasmGraphBuilder {
|
||||
public:
|
||||
WasmGraphBuilder(
|
||||
const wasm::ModuleEnv* module_env, Zone* z, JSGraph* g,
|
||||
Handle<Code> centry_stub_, wasm::FunctionSig* sig,
|
||||
ModuleEnv* env, Zone* z, JSGraph* g, Handle<Code> centry_stub_,
|
||||
wasm::FunctionSig* sig,
|
||||
compiler::SourcePositionTable* source_position_table = nullptr);
|
||||
|
||||
Node** Buffer(size_t count) {
|
||||
@ -284,19 +318,19 @@ class WasmGraphBuilder {
|
||||
|
||||
bool has_simd() const { return has_simd_; }
|
||||
|
||||
const wasm::ModuleEnv* module_env() const { return module_env_; }
|
||||
|
||||
void SetRuntimeExceptionSupport(bool value) {
|
||||
has_runtime_exception_support_ = value;
|
||||
}
|
||||
|
||||
const wasm::WasmModule* module() { return env_ ? env_->module : nullptr; }
|
||||
|
||||
private:
|
||||
static const int kDefaultBufferSize = 16;
|
||||
|
||||
Zone* zone_;
|
||||
JSGraph* jsgraph_;
|
||||
Node* centry_stub_node_;
|
||||
const wasm::ModuleEnv* module_env_ = nullptr;
|
||||
ModuleEnv* env_ = nullptr;
|
||||
Node* mem_buffer_ = nullptr;
|
||||
Node* mem_size_ = nullptr;
|
||||
NodeVector signature_tables_;
|
||||
|
@ -619,11 +619,7 @@ class WasmFullDecoder : public WasmDecoder {
|
||||
: WasmFullDecoder(zone, module, nullptr, body) {}
|
||||
|
||||
WasmFullDecoder(Zone* zone, TFBuilder* builder, const FunctionBody& body)
|
||||
: WasmFullDecoder(zone,
|
||||
builder->module_env() == nullptr
|
||||
? nullptr
|
||||
: builder->module_env()->module(),
|
||||
builder, body) {}
|
||||
: WasmFullDecoder(zone, builder->module(), builder, body) {}
|
||||
|
||||
bool Decode() {
|
||||
if (FLAG_wasm_code_fuzzer_gen_test) {
|
||||
|
@ -83,7 +83,8 @@ size_t ModuleCompiler::CodeGenerationSchedule::GetRandomIndexInSchedule() {
|
||||
}
|
||||
|
||||
ModuleCompiler::ModuleCompiler(Isolate* isolate,
|
||||
std::unique_ptr<WasmModule> module)
|
||||
std::unique_ptr<WasmModule> module,
|
||||
Handle<Code> centry_stub)
|
||||
: isolate_(isolate),
|
||||
module_(std::move(module)),
|
||||
async_counters_(isolate->async_counters()),
|
||||
@ -97,7 +98,7 @@ ModuleCompiler::ModuleCompiler(Isolate* isolate,
|
||||
Min(static_cast<size_t>(FLAG_wasm_num_compilation_tasks),
|
||||
V8::GetCurrentPlatform()->NumberOfAvailableBackgroundThreads())),
|
||||
stopped_compilation_tasks_(num_background_tasks_),
|
||||
centry_stub_(CEntryStub(isolate, 1).GetCode()) {}
|
||||
centry_stub_(centry_stub) {}
|
||||
|
||||
// The actual runnable task that performs compilations in the background.
|
||||
ModuleCompiler::CompilationTask::CompilationTask(ModuleCompiler* compiler)
|
||||
@ -150,8 +151,8 @@ bool ModuleCompiler::FetchAndExecuteCompilationUnit(
|
||||
|
||||
size_t ModuleCompiler::InitializeCompilationUnits(
|
||||
const std::vector<WasmFunction>& functions,
|
||||
const ModuleWireBytes& wire_bytes, const ModuleEnv* module_env) {
|
||||
uint32_t start = module_env->module()->num_imported_functions +
|
||||
const ModuleWireBytes& wire_bytes, compiler::ModuleEnv* module_env) {
|
||||
uint32_t start = module_env->module->num_imported_functions +
|
||||
FLAG_skip_compiling_wasm_funcs;
|
||||
uint32_t num_funcs = static_cast<uint32_t>(functions.size());
|
||||
uint32_t funcs_to_compile = start > num_funcs ? 0 : num_funcs - start;
|
||||
@ -168,10 +169,6 @@ size_t ModuleCompiler::InitializeCompilationUnits(
|
||||
return funcs_to_compile;
|
||||
}
|
||||
|
||||
void ModuleCompiler::ReopenHandlesInDeferredScope() {
|
||||
centry_stub_ = handle(*centry_stub_, isolate_);
|
||||
}
|
||||
|
||||
void ModuleCompiler::RestartCompilationTasks() {
|
||||
base::LockGuard<base::Mutex> guard(&tasks_mutex_);
|
||||
for (; stopped_compilation_tasks_ > 0; --stopped_compilation_tasks_) {
|
||||
@ -220,10 +217,10 @@ MaybeHandle<Code> ModuleCompiler::FinishCompilationUnit(ErrorThrower* thrower,
|
||||
}
|
||||
|
||||
void ModuleCompiler::CompileInParallel(const ModuleWireBytes& wire_bytes,
|
||||
const ModuleEnv* module_env,
|
||||
compiler::ModuleEnv* module_env,
|
||||
std::vector<Handle<Code>>& results,
|
||||
ErrorThrower* thrower) {
|
||||
const WasmModule* module = module_env->module();
|
||||
const WasmModule* module = module_env->module;
|
||||
// Data structures for the parallel compilation.
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
@ -277,12 +274,12 @@ void ModuleCompiler::CompileInParallel(const ModuleWireBytes& wire_bytes,
|
||||
}
|
||||
|
||||
void ModuleCompiler::CompileSequentially(const ModuleWireBytes& wire_bytes,
|
||||
const ModuleEnv* module_env,
|
||||
compiler::ModuleEnv* module_env,
|
||||
std::vector<Handle<Code>>& results,
|
||||
ErrorThrower* thrower) {
|
||||
DCHECK(!thrower->error());
|
||||
|
||||
const WasmModule* module = module_env->module();
|
||||
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];
|
||||
@ -302,11 +299,11 @@ void ModuleCompiler::CompileSequentially(const ModuleWireBytes& wire_bytes,
|
||||
}
|
||||
|
||||
void ModuleCompiler::ValidateSequentially(const ModuleWireBytes& wire_bytes,
|
||||
const ModuleEnv* module_env,
|
||||
compiler::ModuleEnv* module_env,
|
||||
ErrorThrower* thrower) {
|
||||
DCHECK(!thrower->error());
|
||||
|
||||
const WasmModule* module = module_env->module();
|
||||
const WasmModule* module = module_env->module;
|
||||
for (uint32_t i = 0; i < module->functions.size(); ++i) {
|
||||
const WasmFunction& func = module->functions[i];
|
||||
if (func.imported) continue;
|
||||
@ -365,7 +362,8 @@ void RecordStats(Code* code, Counters* counters) {
|
||||
void RecordStats(Handle<FixedArray> functions, Counters* counters) {
|
||||
DisallowHeapAllocation no_gc;
|
||||
for (int i = 0; i < functions->length(); ++i) {
|
||||
RecordStats(Code::cast(functions->get(i)), counters);
|
||||
Object* val = functions->get(i);
|
||||
if (val->IsCode()) RecordStats(Code::cast(val), counters);
|
||||
}
|
||||
}
|
||||
Handle<Script> CreateWasmScript(Isolate* isolate,
|
||||
@ -520,14 +518,48 @@ double MonotonicallyIncreasingTimeInMs() {
|
||||
base::Time::kMillisecondsPerSecond;
|
||||
}
|
||||
|
||||
void SetFunctionTablesToDefault(Factory* factory, wasm::ModuleEnv* module_env) {
|
||||
for (uint32_t i = 0,
|
||||
e = static_cast<uint32_t>(module_env->function_tables().size());
|
||||
i < e; ++i) {
|
||||
DCHECK(module_env->function_tables()[i].is_null());
|
||||
DCHECK(module_env->signature_tables()[i].is_null());
|
||||
module_env->SetFunctionTable(i, factory->NewFixedArray(1, TENURED),
|
||||
factory->NewFixedArray(1, TENURED));
|
||||
std::unique_ptr<compiler::ModuleEnv> CreateDefaultModuleEnv(
|
||||
Factory* factory, WasmModule* module, Handle<Code> illegal_builtin) {
|
||||
std::vector<Handle<FixedArray>> function_tables;
|
||||
std::vector<Handle<FixedArray>> signature_tables;
|
||||
std::vector<SignatureMap*> signature_maps;
|
||||
|
||||
for (size_t i = 0; i < module->function_tables.size(); i++) {
|
||||
auto& function_table = module->function_tables[i];
|
||||
function_tables.push_back(factory->NewFixedArray(1, TENURED));
|
||||
signature_tables.push_back(factory->NewFixedArray(1, TENURED));
|
||||
signature_maps.push_back(&function_table.map);
|
||||
}
|
||||
|
||||
std::vector<Handle<Code>> empty_code;
|
||||
|
||||
compiler::ModuleEnv result = {
|
||||
module, // --
|
||||
function_tables, // --
|
||||
signature_tables, // --
|
||||
signature_maps, // --
|
||||
empty_code, // --
|
||||
illegal_builtin, // --
|
||||
0, // --
|
||||
0, // --
|
||||
0 // --
|
||||
};
|
||||
return std::unique_ptr<compiler::ModuleEnv>(new compiler::ModuleEnv(result));
|
||||
}
|
||||
|
||||
Handle<WasmCompiledModule> NewCompiledModule(
|
||||
Isolate* isolate, Handle<WasmSharedModuleData> shared,
|
||||
Handle<FixedArray> code_table, compiler::ModuleEnv* env) {
|
||||
Handle<WasmCompiledModule> compiled_module = WasmCompiledModule::New(
|
||||
isolate, shared, code_table, env->function_tables, env->signature_tables);
|
||||
return compiled_module;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void ReopenHandles(Isolate* isolate, const std::vector<Handle<T>>& vec) {
|
||||
auto& mut = const_cast<std::vector<Handle<T>>&>(vec);
|
||||
for (size_t i = 0; i < mut.size(); i++) {
|
||||
mut[i] = Handle<T>(*mut[i], isolate);
|
||||
}
|
||||
}
|
||||
|
||||
@ -547,9 +579,7 @@ MaybeHandle<WasmModuleObject> ModuleCompiler::CompileToModuleObjectInternal(
|
||||
? BUILTIN_CODE(isolate_, WasmCompileLazy)
|
||||
: BUILTIN_CODE(isolate_, Illegal);
|
||||
|
||||
ModuleEnv env(module_.get(), init_builtin);
|
||||
|
||||
SetFunctionTablesToDefault(factory, &env);
|
||||
auto env = CreateDefaultModuleEnv(factory, module_.get(), init_builtin);
|
||||
|
||||
// The {code_table} array contains import wrappers and functions (which
|
||||
// are both included in {functions.size()}, and export wrappers).
|
||||
@ -570,12 +600,12 @@ MaybeHandle<WasmModuleObject> ModuleCompiler::CompileToModuleObjectInternal(
|
||||
funcs_to_compile > 1 &&
|
||||
V8::GetCurrentPlatform()->NumberOfAvailableBackgroundThreads() > 0;
|
||||
// Avoid a race condition by collecting results into a second vector.
|
||||
std::vector<Handle<Code>> results(env.module()->functions.size());
|
||||
std::vector<Handle<Code>> results(env->module->functions.size());
|
||||
|
||||
if (compile_parallel) {
|
||||
CompileInParallel(wire_bytes, &env, results, thrower);
|
||||
CompileInParallel(wire_bytes, env.get(), results, thrower);
|
||||
} else {
|
||||
CompileSequentially(wire_bytes, &env, results, thrower);
|
||||
CompileSequentially(wire_bytes, env.get(), results, thrower);
|
||||
}
|
||||
if (thrower->error()) return {};
|
||||
|
||||
@ -594,7 +624,7 @@ MaybeHandle<WasmModuleObject> ModuleCompiler::CompileToModuleObjectInternal(
|
||||
// TODO(clemensh): According to the spec, we can actually skip validation
|
||||
// at module creation time, and return a function that always traps at
|
||||
// (lazy) compilation time.
|
||||
ValidateSequentially(wire_bytes, &env, thrower);
|
||||
ValidateSequentially(wire_bytes, env.get(), thrower);
|
||||
}
|
||||
if (thrower->error()) return {};
|
||||
|
||||
@ -636,12 +666,12 @@ MaybeHandle<WasmModuleObject> ModuleCompiler::CompileToModuleObjectInternal(
|
||||
script, asm_js_offset_table);
|
||||
if (lazy_compile) WasmSharedModuleData::PrepareForLazyCompilation(shared);
|
||||
|
||||
// Create the compiled module object, and populate with compiled functions
|
||||
// Create the compiled module object and populate with compiled functions
|
||||
// and information needed at instantiation time. This object needs to be
|
||||
// serializable. Instantiation may occur off a deserialized version of this
|
||||
// object.
|
||||
Handle<WasmCompiledModule> compiled_module =
|
||||
WasmCompiledModule::New(isolate_, shared, code_table, env);
|
||||
NewCompiledModule(isolate_, shared, code_table, env.get());
|
||||
|
||||
// If we created a wasm script, finish it now and make it public to the
|
||||
// debugger.
|
||||
@ -937,7 +967,7 @@ MaybeHandle<WasmInstanceObject> InstanceBuilder::Build() {
|
||||
CHECK(memory->byte_length()->ToUint32(&mem_size));
|
||||
LoadDataSegments(mem_start, mem_size);
|
||||
|
||||
uint32_t old_mem_size = compiled_module_->mem_size();
|
||||
uint32_t old_mem_size = compiled_module_->GetEmbeddedMemSizeOrZero();
|
||||
Address old_mem_start = compiled_module_->GetEmbeddedMemStartOrNull();
|
||||
// We might get instantiated again with the same memory. No patching
|
||||
// needed in this case.
|
||||
@ -1877,14 +1907,6 @@ AsyncCompileJob::~AsyncCompileJob() {
|
||||
for (auto d : deferred_handles_) delete d;
|
||||
}
|
||||
|
||||
void AsyncCompileJob::ReopenHandlesInDeferredScope() {
|
||||
DeferredHandleScope deferred(isolate_);
|
||||
code_table_ = handle(*code_table_, isolate_);
|
||||
module_env_->ReopenHandles(isolate_);
|
||||
compiler_->ReopenHandlesInDeferredScope();
|
||||
deferred_handles_.push_back(deferred.Detach());
|
||||
}
|
||||
|
||||
void AsyncCompileJob::AsyncCompileFailed(ErrorThrower& thrower) {
|
||||
RejectPromise(isolate_, context_, thrower, module_promise_);
|
||||
isolate_->wasm_compilation_manager()->RemoveJob(this);
|
||||
@ -2031,39 +2053,49 @@ class AsyncCompileJob::PrepareAndStartCompile : public CompileStep {
|
||||
std::unique_ptr<WasmModule> module_;
|
||||
void RunInForeground() override {
|
||||
TRACE_COMPILE("(2) Prepare and start compile...\n");
|
||||
HandleScope scope(job_->isolate_);
|
||||
Isolate* isolate = job_->isolate_;
|
||||
HandleScope scope(isolate);
|
||||
|
||||
Factory* factory = job_->isolate_->factory();
|
||||
// Initialize {code_table_} with the illegal builtin. All call sites
|
||||
// will be patched at instantiation.
|
||||
// TODO(wasm): Fix this for lazy compilation.
|
||||
Handle<Code> illegal_builtin = BUILTIN_CODE(job_->isolate_, Illegal);
|
||||
job_->module_env_.reset(new ModuleEnv(module_.get(), illegal_builtin));
|
||||
ModuleEnv* module_env = job_->module_env_.get();
|
||||
|
||||
SetFunctionTablesToDefault(factory, module_env);
|
||||
Factory* factory = isolate->factory();
|
||||
Handle<Code> illegal_builtin = BUILTIN_CODE(isolate, Illegal);
|
||||
job_->module_env_ =
|
||||
CreateDefaultModuleEnv(factory, module_.get(), illegal_builtin);
|
||||
|
||||
// The {code_table} array contains import wrappers and functions (which
|
||||
// are both included in {functions.size()}, and export wrappers.
|
||||
// The results of compilation will be written into it.
|
||||
// Initialize {code_table_} with the illegal builtin. All call sites
|
||||
// will be patched at instantiation.
|
||||
int code_table_size = static_cast<int>(module_->functions.size() +
|
||||
module_->num_exported_functions);
|
||||
job_->code_table_ = factory->NewFixedArray(code_table_size, TENURED);
|
||||
|
||||
// TODO(wasm): Fix this for lazy compilation.
|
||||
for (int i = 0; i < code_table_size; ++i) {
|
||||
job_->code_table_->set(static_cast<int>(i), *illegal_builtin);
|
||||
}
|
||||
|
||||
// Transfer ownership of the {WasmModule} to the {ModuleCompiler}, but
|
||||
// keep a pointer.
|
||||
WasmModule* module = module_.get();
|
||||
job_->compiler_.reset(
|
||||
new ModuleCompiler(job_->isolate_, std::move(module_)));
|
||||
job_->compiler_->EnableThrottling();
|
||||
Handle<Code> centry_stub = CEntryStub(isolate, 1).GetCode();
|
||||
|
||||
// Reopen all handles which should survive in the DeferredHandleScope.
|
||||
job_->ReopenHandlesInDeferredScope();
|
||||
{
|
||||
// Now reopen the handles in a deferred scope in order to use
|
||||
// them in the concurrent steps.
|
||||
DeferredHandleScope deferred(isolate);
|
||||
|
||||
centry_stub = Handle<Code>(*centry_stub, isolate);
|
||||
job_->code_table_ = Handle<FixedArray>(*job_->code_table_, isolate);
|
||||
compiler::ModuleEnv* env = job_->module_env_.get();
|
||||
ReopenHandles(isolate, env->function_tables);
|
||||
ReopenHandles(isolate, env->signature_tables);
|
||||
ReopenHandles(isolate, env->function_code);
|
||||
Handle<Code>* mut =
|
||||
const_cast<Handle<Code>*>(&env->default_function_code);
|
||||
*mut = Handle<Code>(**mut, isolate);
|
||||
|
||||
job_->deferred_handles_.push_back(deferred.Detach());
|
||||
}
|
||||
|
||||
job_->compiler_.reset(
|
||||
new ModuleCompiler(isolate, std::move(module_), centry_stub));
|
||||
job_->compiler_->EnableThrottling();
|
||||
|
||||
DCHECK_LE(module->num_imported_functions, module->functions.size());
|
||||
size_t num_functions =
|
||||
@ -2203,8 +2235,8 @@ class AsyncCompileJob::FinishCompile : public CompileStep {
|
||||
for (int i = FLAG_skip_compiling_wasm_funcs,
|
||||
e = job_->code_table_->length();
|
||||
i < e; ++i) {
|
||||
Code* code = Code::cast(job_->code_table_->get(i));
|
||||
RecordStats(code, job_->counters());
|
||||
Object* val = job_->code_table_->get(i);
|
||||
if (val->IsCode()) RecordStats(Code::cast(val), job_->counters());
|
||||
}
|
||||
|
||||
// Create heap objects for script and module bytes to be stored in the
|
||||
@ -2243,9 +2275,8 @@ class AsyncCompileJob::FinishCompile : public CompileStep {
|
||||
// and information needed at instantiation time. This object needs to be
|
||||
// serializable. Instantiation may occur off a deserialized version of
|
||||
// this object.
|
||||
job_->compiled_module_ = WasmCompiledModule::New(
|
||||
job_->isolate_, shared, job_->code_table_, *job_->module_env_);
|
||||
|
||||
job_->compiled_module_ = NewCompiledModule(
|
||||
job_->isolate_, shared, job_->code_table_, job_->module_env_.get());
|
||||
// Finish the wasm script now and make it public to the debugger.
|
||||
script->set_wasm_compiled_module(*job_->compiled_module_);
|
||||
job_->isolate_->debug()->OnAfterCompile(script);
|
||||
|
@ -27,7 +27,8 @@ class ModuleCompiler {
|
||||
// In {CompileToModuleObject}, it will transfer ownership to the generated
|
||||
// {WasmModuleWrapper}. If this method is not called, ownership may be
|
||||
// reclaimed by explicitely releasing the {module_} field.
|
||||
ModuleCompiler(Isolate* isolate, std::unique_ptr<WasmModule> module);
|
||||
ModuleCompiler(Isolate* isolate, std::unique_ptr<WasmModule> module,
|
||||
Handle<Code> centry_stub);
|
||||
|
||||
// The actual runnable task that performs compilations in the background.
|
||||
class CompilationTask : public CancelableTask {
|
||||
@ -48,7 +49,7 @@ class ModuleCompiler {
|
||||
|
||||
~CompilationUnitBuilder() { DCHECK(units_.empty()); }
|
||||
|
||||
void AddUnit(const ModuleEnv* module_env, const WasmFunction* function,
|
||||
void AddUnit(compiler::ModuleEnv* module_env, const WasmFunction* function,
|
||||
uint32_t buffer_offset, Vector<const uint8_t> bytes,
|
||||
WasmName name) {
|
||||
units_.emplace_back(new compiler::WasmCompilationUnit(
|
||||
@ -128,9 +129,7 @@ class ModuleCompiler {
|
||||
|
||||
size_t InitializeCompilationUnits(const std::vector<WasmFunction>& functions,
|
||||
const ModuleWireBytes& wire_bytes,
|
||||
const ModuleEnv* module_env);
|
||||
|
||||
void ReopenHandlesInDeferredScope();
|
||||
compiler::ModuleEnv* module_env);
|
||||
|
||||
void RestartCompilationTasks();
|
||||
|
||||
@ -143,17 +142,18 @@ class ModuleCompiler {
|
||||
int* func_index);
|
||||
|
||||
void CompileInParallel(const ModuleWireBytes& wire_bytes,
|
||||
const ModuleEnv* module_env,
|
||||
compiler::ModuleEnv* module_env,
|
||||
std::vector<Handle<Code>>& results,
|
||||
ErrorThrower* thrower);
|
||||
|
||||
void CompileSequentially(const ModuleWireBytes& wire_bytes,
|
||||
const ModuleEnv* module_env,
|
||||
compiler::ModuleEnv* module_env,
|
||||
std::vector<Handle<Code>>& results,
|
||||
ErrorThrower* thrower);
|
||||
|
||||
void ValidateSequentially(const ModuleWireBytes& wire_bytes,
|
||||
const ModuleEnv* module_env, ErrorThrower* thrower);
|
||||
compiler::ModuleEnv* module_env,
|
||||
ErrorThrower* thrower);
|
||||
|
||||
MaybeHandle<WasmModuleObject> CompileToModuleObject(
|
||||
ErrorThrower* thrower, const ModuleWireBytes& wire_bytes,
|
||||
@ -346,7 +346,7 @@ class AsyncCompileJob {
|
||||
Handle<Context> context_;
|
||||
Handle<JSPromise> module_promise_;
|
||||
std::unique_ptr<ModuleCompiler> compiler_;
|
||||
std::unique_ptr<ModuleEnv> module_env_;
|
||||
std::unique_ptr<compiler::ModuleEnv> module_env_;
|
||||
|
||||
std::vector<DeferredHandles*> deferred_handles_;
|
||||
Handle<WasmModuleObject> module_object_;
|
||||
@ -365,8 +365,6 @@ class AsyncCompileJob {
|
||||
}
|
||||
Counters* counters() const { return async_counters().get(); }
|
||||
|
||||
void ReopenHandlesInDeferredScope();
|
||||
|
||||
void AsyncCompileFailed(ErrorThrower& thrower);
|
||||
|
||||
void AsyncCompileSucceeded(Handle<Object> result);
|
||||
|
@ -12,6 +12,11 @@
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
namespace compiler {
|
||||
struct ModuleEnv;
|
||||
}
|
||||
|
||||
namespace wasm {
|
||||
|
||||
const uint32_t kWasmMagic = 0x6d736100;
|
||||
@ -106,7 +111,7 @@ V8_EXPORT_PRIVATE FunctionResult SyncDecodeWasmFunction(
|
||||
const byte* function_end);
|
||||
|
||||
V8_EXPORT_PRIVATE FunctionResult
|
||||
AsyncDecodeWasmFunction(Isolate* isolate, Zone* zone, const ModuleEnv* env,
|
||||
AsyncDecodeWasmFunction(Isolate* isolate, Zone* zone, compiler::ModuleEnv* env,
|
||||
const byte* function_start, const byte* function_end,
|
||||
const std::shared_ptr<Counters> async_counters);
|
||||
|
||||
|
@ -95,7 +95,6 @@ void CodeSpecialization::RelocateMemoryReferences(Address old_start,
|
||||
uint32_t new_size) {
|
||||
DCHECK(old_mem_start == nullptr && old_mem_size == 0 &&
|
||||
new_mem_start == nullptr && new_mem_size == 0);
|
||||
DCHECK(old_start != new_start || old_size != new_size);
|
||||
old_mem_start = old_start;
|
||||
old_mem_size = old_size;
|
||||
new_mem_start = new_start;
|
||||
@ -104,14 +103,12 @@ void CodeSpecialization::RelocateMemoryReferences(Address old_start,
|
||||
|
||||
void CodeSpecialization::RelocateGlobals(Address old_start, Address new_start) {
|
||||
DCHECK(old_globals_start == 0 && new_globals_start == 0);
|
||||
DCHECK(old_start != 0 || new_start != 0);
|
||||
old_globals_start = old_start;
|
||||
new_globals_start = new_start;
|
||||
}
|
||||
|
||||
void CodeSpecialization::PatchTableSize(uint32_t old_size, uint32_t new_size) {
|
||||
DCHECK(old_function_table_size == 0 && new_function_table_size == 0);
|
||||
DCHECK(old_size != 0 || new_size != 0);
|
||||
old_function_table_size = old_size;
|
||||
new_function_table_size = new_size;
|
||||
}
|
||||
|
@ -212,48 +212,43 @@ void RecordLazyCodeStats(Code* code, Counters* counters) {
|
||||
counters->wasm_reloc_size()->Increment(code->relocation_info()->length());
|
||||
}
|
||||
|
||||
ModuleEnv CreateModuleEnvFromRuntimeObject(
|
||||
compiler::ModuleEnv CreateModuleEnvFromCompiledModule(
|
||||
Isolate* isolate, Handle<WasmCompiledModule> compiled_module) {
|
||||
DisallowHeapAllocation no_gc;
|
||||
// Store a vector of handles to be embedded in the generated code.
|
||||
// TODO(clemensh): For concurrent compilation, these will have to live in a
|
||||
// DeferredHandleScope.
|
||||
wasm::ModuleEnv module_env(compiled_module->module(),
|
||||
BUILTIN_CODE(isolate, WasmCompileLazy));
|
||||
WasmModule* module = compiled_module->module();
|
||||
|
||||
// We set unchecked because the data on the compiled module
|
||||
// is authoritative.
|
||||
module_env.SetMemSizeUnchecked(compiled_module->has_embedded_mem_size()
|
||||
? compiled_module->embedded_mem_size()
|
||||
: 0);
|
||||
module_env.set_mem_start(
|
||||
reinterpret_cast<byte*>(compiled_module->has_embedded_mem_start()
|
||||
? compiled_module->embedded_mem_start()
|
||||
: 0));
|
||||
module_env.set_globals_start(reinterpret_cast<byte*>(
|
||||
compiled_module->has_globals_start() ? compiled_module->globals_start()
|
||||
: 0));
|
||||
std::vector<Handle<FixedArray>> function_tables;
|
||||
std::vector<Handle<FixedArray>> signature_tables;
|
||||
std::vector<SignatureMap*> signature_maps;
|
||||
|
||||
DCHECK_EQ(compiled_module->has_function_tables(),
|
||||
compiled_module->has_signature_tables());
|
||||
int num_function_tables = static_cast<int>(module->function_tables.size());
|
||||
for (int i = 0; i < num_function_tables; i++) {
|
||||
FixedArray* ft = compiled_module->ptr_to_function_tables();
|
||||
FixedArray* st = compiled_module->ptr_to_signature_tables();
|
||||
|
||||
if (compiled_module->has_function_tables()) {
|
||||
// TODO(clemensh): For concurrent compilation, these will have to live in a
|
||||
// DeferredHandleScope.
|
||||
FixedArray* function_tables = compiled_module->ptr_to_function_tables();
|
||||
FixedArray* signature_tables = compiled_module->ptr_to_signature_tables();
|
||||
DCHECK_EQ(function_tables->length(), signature_tables->length());
|
||||
DCHECK_EQ(function_tables->length(), module_env.function_tables().size());
|
||||
for (uint32_t i = 0, e = static_cast<uint32_t>(
|
||||
module_env.function_tables().size());
|
||||
i < e; ++i) {
|
||||
int index = static_cast<int>(i);
|
||||
module_env.SetFunctionTable(
|
||||
i, handle(FixedArray::cast(function_tables->get(index))),
|
||||
handle(FixedArray::cast(signature_tables->get(index))));
|
||||
}
|
||||
// TODO(clemensh): defer these handles for concurrent compilation.
|
||||
function_tables.push_back(handle(FixedArray::cast(ft->get(i))));
|
||||
signature_tables.push_back(handle(FixedArray::cast(st->get(i))));
|
||||
signature_maps.push_back(&module->function_tables[i].map);
|
||||
}
|
||||
return module_env;
|
||||
|
||||
std::vector<Handle<Code>> empty_code;
|
||||
|
||||
compiler::ModuleEnv result = {
|
||||
module, // --
|
||||
function_tables, // --
|
||||
signature_tables, // --
|
||||
signature_maps, // --
|
||||
empty_code, // --
|
||||
BUILTIN_CODE(isolate, WasmCompileLazy), // --
|
||||
reinterpret_cast<uintptr_t>( // --
|
||||
compiled_module->GetEmbeddedMemStartOrNull()), // --
|
||||
reinterpret_cast<uint32_t>( // --
|
||||
compiled_module->GetEmbeddedMemSizeOrZero()), // --
|
||||
reinterpret_cast<uintptr_t>( // --
|
||||
compiled_module->GetGlobalsStartOrNull()) // --
|
||||
};
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
@ -804,9 +799,10 @@ MaybeHandle<WasmModuleObject> wasm::SyncCompileTranslatedAsmJs(
|
||||
|
||||
// Transfer ownership to the {WasmModuleWrapper} generated in
|
||||
// {CompileToModuleObject}.
|
||||
ModuleCompiler helper(isolate, std::move(result.val));
|
||||
return helper.CompileToModuleObject(thrower, bytes, asm_js_script,
|
||||
asm_js_offset_table_bytes);
|
||||
Handle<Code> centry_stub = CEntryStub(isolate, 1).GetCode();
|
||||
ModuleCompiler compiler(isolate, std::move(result.val), centry_stub);
|
||||
return compiler.CompileToModuleObject(thrower, bytes, asm_js_script,
|
||||
asm_js_offset_table_bytes);
|
||||
}
|
||||
|
||||
MaybeHandle<WasmModuleObject> wasm::SyncCompile(Isolate* isolate,
|
||||
@ -826,9 +822,10 @@ MaybeHandle<WasmModuleObject> wasm::SyncCompile(Isolate* isolate,
|
||||
|
||||
// Transfer ownership to the {WasmModuleWrapper} generated in
|
||||
// {CompileToModuleObject}.
|
||||
ModuleCompiler helper(isolate, std::move(result.val));
|
||||
return helper.CompileToModuleObject(thrower, bytes, Handle<Script>(),
|
||||
Vector<const byte>());
|
||||
Handle<Code> centry_stub = CEntryStub(isolate, 1).GetCode();
|
||||
ModuleCompiler compiler(isolate, std::move(result.val), centry_stub);
|
||||
return compiler.CompileToModuleObject(thrower, bytes, Handle<Script>(),
|
||||
Vector<const byte>());
|
||||
}
|
||||
|
||||
MaybeHandle<WasmInstanceObject> wasm::SyncInstantiate(
|
||||
@ -1001,12 +998,12 @@ void LazyCompilationOrchestrator::CompileFunction(
|
||||
return;
|
||||
}
|
||||
|
||||
wasm::ModuleEnv module_env =
|
||||
CreateModuleEnvFromRuntimeObject(isolate, compiled_module);
|
||||
compiler::ModuleEnv module_env =
|
||||
CreateModuleEnvFromCompiledModule(isolate, compiled_module);
|
||||
|
||||
const uint8_t* module_start = compiled_module->module_bytes()->GetChars();
|
||||
|
||||
const WasmFunction* func = &module_env.module()->functions[func_index];
|
||||
const WasmFunction* func = &module_env.module->functions[func_index];
|
||||
wasm::FunctionBody body{func->sig, func->code.offset(),
|
||||
module_start + func->code.offset(),
|
||||
module_start + func->code.end_offset()};
|
||||
|
@ -280,142 +280,6 @@ struct V8_EXPORT_PRIVATE ModuleWireBytes {
|
||||
const Vector<const byte> module_bytes_;
|
||||
};
|
||||
|
||||
// Specialization parameters the compiler needs to use when compiling the wasm
|
||||
// functions of a module.
|
||||
// We currently only produce code specialized to an instance. Even when
|
||||
// compiling without instantiating, we still need to pick *a* value for these
|
||||
// parameters.
|
||||
class V8_EXPORT_PRIVATE ModuleEnv {
|
||||
public:
|
||||
MOVE_ONLY_NO_DEFAULT_CONSTRUCTOR(ModuleEnv);
|
||||
|
||||
ModuleEnv(WasmModule* module, Handle<Code> default_function_code)
|
||||
: module_(module),
|
||||
function_tables_(module->function_tables.size()),
|
||||
signature_tables_(module->function_tables.size()),
|
||||
default_function_code_(default_function_code),
|
||||
mem_size_(module->initial_pages * WasmModule::kPageSize) {}
|
||||
|
||||
WasmModule* module() const { return module_; }
|
||||
|
||||
uint32_t mem_size() const { return mem_size_; }
|
||||
void set_mem_size(uint32_t mem_size) {
|
||||
DCHECK_EQ(0, mem_size % WasmModule::kPageSize);
|
||||
mem_size_ = mem_size;
|
||||
}
|
||||
|
||||
byte* mem_start() const { return mem_start_; }
|
||||
void set_mem_start(byte* mem_start) { mem_start_ = mem_start; }
|
||||
|
||||
byte* globals_start() const { return globals_start_; }
|
||||
void set_globals_start(byte* globals_start) {
|
||||
globals_start_ = globals_start;
|
||||
}
|
||||
|
||||
const std::vector<Handle<FixedArray>>& function_tables() const {
|
||||
return function_tables_;
|
||||
}
|
||||
const std::vector<Handle<FixedArray>>& signature_tables() const {
|
||||
return signature_tables_;
|
||||
}
|
||||
|
||||
void SetFunctionTable(uint32_t index, Handle<FixedArray> function_table,
|
||||
Handle<FixedArray> signature_table) {
|
||||
DCHECK(IsValidTable(index));
|
||||
DCHECK_EQ(function_tables_.size(), signature_tables_.size());
|
||||
function_tables_[index] = function_table;
|
||||
signature_tables_[index] = signature_table;
|
||||
}
|
||||
|
||||
bool IsValidGlobal(uint32_t index) const {
|
||||
return index < module_->globals.size();
|
||||
}
|
||||
bool IsValidFunction(uint32_t index) const {
|
||||
return index < module_->functions.size();
|
||||
}
|
||||
bool IsValidSignature(uint32_t index) const {
|
||||
return index < module_->signatures.size();
|
||||
}
|
||||
bool IsValidTable(uint32_t index) const {
|
||||
return index < module_->function_tables.size();
|
||||
}
|
||||
ValueType GetGlobalType(uint32_t index) const {
|
||||
DCHECK(IsValidGlobal(index));
|
||||
return module_->globals[index].type;
|
||||
}
|
||||
FunctionSig* GetFunctionSignature(uint32_t index) const {
|
||||
DCHECK(IsValidFunction(index));
|
||||
// This const_cast preserves design intent, because
|
||||
// FunctionSig is an immutable type.
|
||||
return const_cast<FunctionSig*>(module_->functions[index].sig);
|
||||
}
|
||||
FunctionSig* GetSignature(uint32_t index) const {
|
||||
DCHECK(IsValidSignature(index));
|
||||
// This const_cast preserves design intent, because
|
||||
// FunctionSig is an immutable type.
|
||||
return const_cast<FunctionSig*>(module_->signatures[index]);
|
||||
}
|
||||
const WasmIndirectFunctionTable* GetTable(uint32_t index) const {
|
||||
DCHECK(IsValidTable(index));
|
||||
return &module_->function_tables[index];
|
||||
}
|
||||
|
||||
bool is_asm_js() const { return module_->is_asm_js(); }
|
||||
bool is_wasm() const { return module_->is_wasm(); }
|
||||
|
||||
Handle<Code> GetFunctionCode(uint32_t index) const {
|
||||
if (index < function_code_.size()) {
|
||||
return function_code_[index];
|
||||
}
|
||||
return default_function_code_;
|
||||
}
|
||||
|
||||
// TODO(mtrofin): this is async compilation-specific. Move this out.
|
||||
void ReopenHandles(Isolate* isolate) {
|
||||
for (auto& table : function_tables_) {
|
||||
table = handle(*table, isolate);
|
||||
}
|
||||
for (auto& table : signature_tables_) {
|
||||
table = handle(*table, isolate);
|
||||
}
|
||||
for (auto& code : function_code_) {
|
||||
code = handle(*code, isolate);
|
||||
}
|
||||
default_function_code_ = handle(*default_function_code_, isolate);
|
||||
}
|
||||
|
||||
// Intentionally set a memory size that may not conform to
|
||||
// the wasm invariant that it should be divisible by kPageSize - for test.
|
||||
void SetMemSizeUnchecked(uint32_t size) { mem_size_ = size; }
|
||||
|
||||
protected:
|
||||
// The derived class is responsible for correctly setting up the
|
||||
// state. This is currently used by test, where we set up the state
|
||||
// gradually, and also sometimes intentionally invalidating some
|
||||
// invariants.
|
||||
ModuleEnv() = default;
|
||||
|
||||
// decoded wasm module.
|
||||
WasmModule* module_ = nullptr;
|
||||
// indirect function tables.
|
||||
std::vector<Handle<FixedArray>> function_tables_;
|
||||
// indirect signature tables.
|
||||
std::vector<Handle<FixedArray>> signature_tables_;
|
||||
// a user of the compiler may choose to pre-populate this
|
||||
// with code objects to be used instead of the default
|
||||
std::vector<Handle<Code>> function_code_;
|
||||
|
||||
private:
|
||||
Handle<Code> default_function_code_;
|
||||
// size of the linear memory.
|
||||
uint32_t mem_size_ = 0;
|
||||
|
||||
// start of linear memory.
|
||||
byte* mem_start_ = nullptr;
|
||||
// start of the globals area.
|
||||
byte* globals_start_ = nullptr;
|
||||
};
|
||||
|
||||
// A helper for printing out the names of functions.
|
||||
struct WasmFunctionName {
|
||||
WasmFunctionName(const WasmFunction* function, WasmName name)
|
||||
|
@ -796,7 +796,10 @@ void WasmSharedModuleData::PrepareForLazyCompilation(
|
||||
|
||||
Handle<WasmCompiledModule> WasmCompiledModule::New(
|
||||
Isolate* isolate, Handle<WasmSharedModuleData> shared,
|
||||
Handle<FixedArray> code_table, const ModuleEnv& module_env) {
|
||||
Handle<FixedArray> code_table,
|
||||
const std::vector<Handle<FixedArray>>& function_tables,
|
||||
const std::vector<Handle<FixedArray>>& signature_tables) {
|
||||
DCHECK_EQ(function_tables.size(), signature_tables.size());
|
||||
Handle<FixedArray> ret =
|
||||
isolate->factory()->NewFixedArray(PropertyIndices::Count, TENURED);
|
||||
// WasmCompiledModule::cast would fail since fields are not set yet.
|
||||
@ -806,25 +809,6 @@ Handle<WasmCompiledModule> WasmCompiledModule::New(
|
||||
compiled_module->set_shared(shared);
|
||||
compiled_module->set_native_context(isolate->native_context());
|
||||
compiled_module->set_code_table(code_table);
|
||||
size_t function_table_count = shared->module()->function_tables.size();
|
||||
if (function_table_count > 0) {
|
||||
DCHECK_EQ(module_env.function_tables().size(),
|
||||
module_env.signature_tables().size());
|
||||
DCHECK_EQ(module_env.function_tables().size(), function_table_count);
|
||||
int count_as_int = static_cast<int>(function_table_count);
|
||||
Handle<FixedArray> sig_tables =
|
||||
isolate->factory()->NewFixedArray(count_as_int, TENURED);
|
||||
Handle<FixedArray> func_tables =
|
||||
isolate->factory()->NewFixedArray(count_as_int, TENURED);
|
||||
for (int i = 0; i < count_as_int; ++i) {
|
||||
size_t index = static_cast<size_t>(i);
|
||||
sig_tables->set(i, *(module_env.signature_tables()[index]));
|
||||
func_tables->set(i, *(module_env.function_tables()[index]));
|
||||
}
|
||||
compiled_module->set_signature_tables(sig_tables);
|
||||
compiled_module->set_empty_function_tables(func_tables);
|
||||
compiled_module->set_function_tables(func_tables);
|
||||
}
|
||||
// TODO(mtrofin): we copy these because the order of finalization isn't
|
||||
// reliable, and we need these at Reset (which is called at
|
||||
// finalization). If the order were reliable, and top-down, we could instead
|
||||
@ -832,6 +816,22 @@ Handle<WasmCompiledModule> WasmCompiledModule::New(
|
||||
compiled_module->set_initial_pages(shared->module()->initial_pages);
|
||||
compiled_module->set_num_imported_functions(
|
||||
shared->module()->num_imported_functions);
|
||||
|
||||
int num_function_tables = static_cast<int>(function_tables.size());
|
||||
if (num_function_tables > 0) {
|
||||
Handle<FixedArray> st =
|
||||
isolate->factory()->NewFixedArray(num_function_tables, TENURED);
|
||||
Handle<FixedArray> ft =
|
||||
isolate->factory()->NewFixedArray(num_function_tables, TENURED);
|
||||
for (int i = 0; i < num_function_tables; ++i) {
|
||||
st->set(i, *(signature_tables[i]));
|
||||
ft->set(i, *(function_tables[i]));
|
||||
}
|
||||
compiled_module->set_signature_tables(st);
|
||||
compiled_module->set_empty_function_tables(ft);
|
||||
compiled_module->set_function_tables(ft);
|
||||
}
|
||||
|
||||
// TODO(mtrofin): copy the rest of the specialization parameters over.
|
||||
// We're currently OK because we're only using defaults.
|
||||
return compiled_module;
|
||||
@ -871,7 +871,7 @@ void WasmCompiledModule::Reset(Isolate* isolate,
|
||||
Object* undefined = *isolate->factory()->undefined_value();
|
||||
Object* fct_obj = compiled_module->ptr_to_code_table();
|
||||
if (fct_obj != nullptr && fct_obj != undefined) {
|
||||
uint32_t old_mem_size = compiled_module->mem_size();
|
||||
uint32_t old_mem_size = compiled_module->GetEmbeddedMemSizeOrZero();
|
||||
// We use default_mem_size throughout, as the mem size of an uninstantiated
|
||||
// module, because if we can statically prove a memory access is over
|
||||
// bounds, we'll codegen a trap. See {WasmGraphBuilder::BoundsCheckMem}
|
||||
@ -1069,11 +1069,6 @@ void WasmCompiledModule::ReinitializeAfterDeserialization(
|
||||
DCHECK(WasmSharedModuleData::IsWasmSharedModuleData(*shared));
|
||||
}
|
||||
|
||||
uint32_t WasmCompiledModule::mem_size() const {
|
||||
DCHECK(has_embedded_mem_size() == has_embedded_mem_start());
|
||||
return has_embedded_mem_start() ? embedded_mem_size() : default_mem_size();
|
||||
}
|
||||
|
||||
uint32_t WasmCompiledModule::default_mem_size() const {
|
||||
return initial_pages() * WasmModule::kPageSize;
|
||||
}
|
||||
|
@ -386,7 +386,7 @@ class WasmCompiledModule : public FixedArray {
|
||||
MACRO(OBJECT, FixedArray, weak_exported_functions) \
|
||||
MACRO(OBJECT, FixedArray, function_tables) \
|
||||
MACRO(OBJECT, FixedArray, signature_tables) \
|
||||
MACRO(CONST_OBJECT, FixedArray, empty_function_tables) \
|
||||
MACRO(OBJECT, FixedArray, empty_function_tables) \
|
||||
MACRO(LARGE_NUMBER, size_t, embedded_mem_start) \
|
||||
MACRO(LARGE_NUMBER, size_t, globals_start) \
|
||||
MACRO(LARGE_NUMBER, uint32_t, embedded_mem_size) \
|
||||
@ -417,32 +417,31 @@ class WasmCompiledModule : public FixedArray {
|
||||
};
|
||||
|
||||
public:
|
||||
static Handle<WasmCompiledModule> New(Isolate* isolate,
|
||||
Handle<WasmSharedModuleData> shared,
|
||||
Handle<FixedArray> code_table,
|
||||
const wasm::ModuleEnv& module_env);
|
||||
static Handle<WasmCompiledModule> New(
|
||||
Isolate* isolate, Handle<WasmSharedModuleData> shared,
|
||||
Handle<FixedArray> code_table,
|
||||
const std::vector<Handle<FixedArray>>& function_tables,
|
||||
const std::vector<Handle<FixedArray>>& signature_tables);
|
||||
|
||||
static Handle<WasmCompiledModule> Clone(Isolate* isolate,
|
||||
Handle<WasmCompiledModule> module);
|
||||
static void Reset(Isolate* isolate, WasmCompiledModule* module);
|
||||
|
||||
Address GetEmbeddedMemStartOrNull() const {
|
||||
DisallowHeapAllocation no_gc;
|
||||
if (has_embedded_mem_start()) {
|
||||
return reinterpret_cast<Address>(embedded_mem_start());
|
||||
}
|
||||
return nullptr;
|
||||
return has_embedded_mem_start()
|
||||
? reinterpret_cast<Address>(embedded_mem_start())
|
||||
: nullptr;
|
||||
}
|
||||
|
||||
Address GetGlobalsStartOrNull() const {
|
||||
DisallowHeapAllocation no_gc;
|
||||
if (has_globals_start()) {
|
||||
return reinterpret_cast<Address>(globals_start());
|
||||
}
|
||||
return nullptr;
|
||||
return has_globals_start() ? reinterpret_cast<Address>(globals_start())
|
||||
: nullptr;
|
||||
}
|
||||
|
||||
uint32_t GetEmbeddedMemSizeOrZero() const {
|
||||
return has_embedded_mem_size() ? embedded_mem_size() : 0;
|
||||
}
|
||||
|
||||
uint32_t mem_size() const;
|
||||
uint32_t default_mem_size() const;
|
||||
|
||||
void ResetSpecializationMemInfoIfNeeded();
|
||||
|
@ -141,7 +141,7 @@ Handle<JSObject> MakeFakeBreakpoint(Isolate* isolate, int position) {
|
||||
void SetBreakpoint(WasmRunnerBase& runner, int function_index, int byte_offset,
|
||||
int expected_set_byte_offset = -1) {
|
||||
int func_offset =
|
||||
runner.module().module()->functions[function_index].code.offset();
|
||||
runner.module().GetFunctionAt(function_index)->code.offset();
|
||||
int code_offset = func_offset + byte_offset;
|
||||
if (expected_set_byte_offset == -1) expected_set_byte_offset = byte_offset;
|
||||
Handle<WasmInstanceObject> instance = runner.module().instance_object();
|
||||
|
@ -73,17 +73,18 @@ const uint32_t kMaxGlobalsSize = 128;
|
||||
// progressively added by a test. In turn, we piecemeal update the runtime
|
||||
// objects, i.e. {WasmInstanceObject}, {WasmCompiledModule} and, if necessary,
|
||||
// the interpreter.
|
||||
class TestingModule : public ModuleEnv {
|
||||
class TestingModule {
|
||||
public:
|
||||
explicit TestingModule(Zone* zone, WasmExecutionMode mode = kExecuteCompiled)
|
||||
: isolate_(CcTest::InitIsolateOnce()),
|
||||
: test_module_ptr_(&test_module_),
|
||||
isolate_(CcTest::InitIsolateOnce()),
|
||||
global_offset(0),
|
||||
mem_start_(nullptr),
|
||||
mem_size_(0),
|
||||
interpreter_(nullptr) {
|
||||
module_ = &test_module_;
|
||||
WasmJs::Install(isolate_);
|
||||
set_globals_start(global_data);
|
||||
test_module_.globals_size = kMaxGlobalsSize;
|
||||
memset(global_data, 0, sizeof(global_data));
|
||||
memset(globals_data_, 0, sizeof(globals_data_));
|
||||
instance_object_ = InitInstanceObject();
|
||||
if (mode == kExecuteInterpreted) {
|
||||
interpreter_ = WasmDebugInfo::SetupForTesting(instance_object_);
|
||||
@ -94,8 +95,8 @@ class TestingModule : public ModuleEnv {
|
||||
|
||||
byte* AddMemory(uint32_t size) {
|
||||
CHECK(!test_module_.has_memory);
|
||||
CHECK_NULL(mem_start());
|
||||
CHECK_EQ(0, mem_size());
|
||||
CHECK_NULL(mem_start_);
|
||||
CHECK_EQ(0, mem_size_);
|
||||
DCHECK(!instance_object_->has_memory_buffer());
|
||||
test_module_.has_memory = true;
|
||||
bool enable_guard_regions = EnableGuardRegions() && test_module_.is_wasm();
|
||||
@ -105,10 +106,10 @@ class TestingModule : public ModuleEnv {
|
||||
wasm::NewArrayBuffer(isolate_, alloc_size, enable_guard_regions);
|
||||
CHECK(!new_buffer.is_null());
|
||||
instance_object_->set_memory_buffer(*new_buffer);
|
||||
set_mem_start(reinterpret_cast<byte*>(new_buffer->backing_store()));
|
||||
CHECK(size == 0 || mem_start());
|
||||
memset(mem_start(), 0, size);
|
||||
SetMemSizeUnchecked(size);
|
||||
mem_start_ = reinterpret_cast<byte*>(new_buffer->backing_store());
|
||||
mem_size_ = size;
|
||||
CHECK(size == 0 || mem_start_);
|
||||
memset(mem_start_, 0, size);
|
||||
Handle<WasmCompiledModule> compiled_module =
|
||||
handle(instance_object_->compiled_module());
|
||||
Factory* factory = CcTest::i_isolate()->factory();
|
||||
@ -116,14 +117,14 @@ class TestingModule : public ModuleEnv {
|
||||
// if we happened to have one, but this is a reasonable inefficiencly,
|
||||
// given this is test.
|
||||
WasmCompiledModule::recreate_embedded_mem_size(compiled_module, factory,
|
||||
mem_size());
|
||||
mem_size_);
|
||||
WasmCompiledModule::recreate_embedded_mem_start(
|
||||
compiled_module, factory, reinterpret_cast<size_t>(mem_start()));
|
||||
compiled_module, factory, reinterpret_cast<size_t>(mem_start_));
|
||||
|
||||
if (interpreter_) {
|
||||
interpreter_->UpdateMemory(mem_start(), mem_size());
|
||||
interpreter_->UpdateMemory(mem_start_, mem_size_);
|
||||
}
|
||||
return mem_start();
|
||||
return mem_start_;
|
||||
}
|
||||
|
||||
size_t CodeTableLength() const { return function_code_.size(); }
|
||||
@ -138,37 +139,37 @@ class TestingModule : public ModuleEnv {
|
||||
T* AddGlobal(
|
||||
ValueType type = WasmOpcodes::ValueTypeFor(MachineTypeForC<T>())) {
|
||||
const WasmGlobal* global = AddGlobal(type);
|
||||
return reinterpret_cast<T*>(globals_start() + global->offset);
|
||||
return reinterpret_cast<T*>(globals_data_ + global->offset);
|
||||
}
|
||||
|
||||
byte AddSignature(FunctionSig* sig) {
|
||||
test_module_.signatures.push_back(sig);
|
||||
size_t size = module()->signatures.size();
|
||||
size_t size = test_module_.signatures.size();
|
||||
CHECK(size < 127);
|
||||
return static_cast<byte>(size - 1);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T* raw_mem_start() {
|
||||
DCHECK(mem_start());
|
||||
return reinterpret_cast<T*>(mem_start());
|
||||
DCHECK(mem_start_);
|
||||
return reinterpret_cast<T*>(mem_start_);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T* raw_mem_end() {
|
||||
DCHECK(mem_start());
|
||||
return reinterpret_cast<T*>(mem_start() + mem_size());
|
||||
DCHECK(mem_start_);
|
||||
return reinterpret_cast<T*>(mem_start_ + mem_size_);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T raw_mem_at(int i) {
|
||||
DCHECK(mem_start());
|
||||
return ReadMemory(&(reinterpret_cast<T*>(mem_start())[i]));
|
||||
DCHECK(mem_start_);
|
||||
return ReadMemory(&(reinterpret_cast<T*>(mem_start_)[i]));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T raw_val_at(int i) {
|
||||
return ReadMemory(reinterpret_cast<T*>(mem_start() + i));
|
||||
return ReadMemory(reinterpret_cast<T*>(mem_start_ + i));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
@ -184,7 +185,7 @@ class TestingModule : public ModuleEnv {
|
||||
// Zero-initialize the memory.
|
||||
void BlankMemory() {
|
||||
byte* raw = raw_mem_start<byte>();
|
||||
memset(raw, 0, mem_size());
|
||||
memset(raw, 0, mem_size_);
|
||||
}
|
||||
|
||||
// Pseudo-randomly intialize the memory.
|
||||
@ -201,12 +202,12 @@ class TestingModule : public ModuleEnv {
|
||||
}
|
||||
|
||||
uint32_t AddFunction(FunctionSig* sig, Handle<Code> code, const char* name) {
|
||||
if (module()->functions.size() == 0) {
|
||||
if (test_module_.functions.size() == 0) {
|
||||
// TODO(titzer): Reserving space here to avoid the underlying WasmFunction
|
||||
// structs from moving.
|
||||
test_module_.functions.reserve(kMaxFunctions);
|
||||
}
|
||||
uint32_t index = static_cast<uint32_t>(module()->functions.size());
|
||||
uint32_t index = static_cast<uint32_t>(test_module_.functions.size());
|
||||
test_module_.functions.push_back(
|
||||
{sig, index, 0, {0, 0}, {0, 0}, false, false});
|
||||
if (name) {
|
||||
@ -216,7 +217,7 @@ class TestingModule : public ModuleEnv {
|
||||
}
|
||||
function_code_.push_back(code);
|
||||
if (interpreter_) {
|
||||
interpreter_->AddFunctionForTesting(&module()->functions.back());
|
||||
interpreter_->AddFunctionForTesting(&test_module_.functions.back());
|
||||
}
|
||||
DCHECK_LT(index, kMaxFunctions); // limited for testing.
|
||||
return index;
|
||||
@ -228,7 +229,7 @@ class TestingModule : public ModuleEnv {
|
||||
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());
|
||||
Handle<String>::null(), test_module_.origin());
|
||||
function_code_[index] = code;
|
||||
return index;
|
||||
}
|
||||
@ -237,11 +238,11 @@ class TestingModule : public ModuleEnv {
|
||||
// Wrap the code so it can be called as a JS function.
|
||||
Handle<Code> code = function_code_[index];
|
||||
Handle<Code> ret_code =
|
||||
compiler::CompileJSToWasmWrapper(isolate_, module(), code, index);
|
||||
compiler::CompileJSToWasmWrapper(isolate_, &test_module_, code, index);
|
||||
Handle<JSFunction> ret = WasmExportedFunction::New(
|
||||
isolate_, instance_object(), MaybeHandle<String>(),
|
||||
static_cast<int>(index),
|
||||
static_cast<int>(module()->functions[index].sig->parameter_count()),
|
||||
static_cast<int>(test_module_.functions[index].sig->parameter_count()),
|
||||
ret_code);
|
||||
|
||||
// Add weak reference to exported functions.
|
||||
@ -281,10 +282,10 @@ class TestingModule : public ModuleEnv {
|
||||
void PopulateIndirectFunctionTable() {
|
||||
if (interpret()) return;
|
||||
// Initialize the fixed arrays in instance->function_tables.
|
||||
for (uint32_t i = 0; i < function_tables().size(); i++) {
|
||||
for (uint32_t i = 0; i < function_tables_.size(); i++) {
|
||||
WasmIndirectFunctionTable& table = test_module_.function_tables[i];
|
||||
Handle<FixedArray> function_table = function_tables()[i];
|
||||
Handle<FixedArray> signature_table = signature_tables()[i];
|
||||
Handle<FixedArray> function_table = function_tables_[i];
|
||||
Handle<FixedArray> signature_table = signature_tables_[i];
|
||||
int table_size = static_cast<int>(table.values.size());
|
||||
for (int j = 0; j < table_size; j++) {
|
||||
WasmFunction& function = test_module_.functions[table.values[j]];
|
||||
@ -319,12 +320,42 @@ class TestingModule : public ModuleEnv {
|
||||
bool interpret() { return interpreter_ != nullptr; }
|
||||
Isolate* isolate() { return isolate_; }
|
||||
Handle<WasmInstanceObject> instance_object() { return instance_object_; }
|
||||
Handle<Code> GetFunctionCode(int index) { return function_code_[index]; }
|
||||
void SetFunctionCode(int index, Handle<Code> code) {
|
||||
function_code_[index] = code;
|
||||
}
|
||||
Address globals_start() { return reinterpret_cast<Address>(globals_data_); }
|
||||
|
||||
compiler::ModuleEnv CreateModuleEnv() {
|
||||
std::vector<SignatureMap*> signature_maps;
|
||||
for (size_t i = 0; i < test_module_.function_tables.size(); i++) {
|
||||
auto& function_table = test_module_.function_tables[i];
|
||||
signature_maps.push_back(&function_table.map);
|
||||
}
|
||||
return {
|
||||
&test_module_,
|
||||
function_tables_,
|
||||
signature_tables_,
|
||||
signature_maps,
|
||||
function_code_,
|
||||
Handle<Code>::null(),
|
||||
reinterpret_cast<uintptr_t>(mem_start_),
|
||||
mem_size_,
|
||||
reinterpret_cast<uintptr_t>(globals_data_),
|
||||
};
|
||||
}
|
||||
|
||||
private:
|
||||
WasmModule test_module_;
|
||||
WasmModule* test_module_ptr_;
|
||||
Isolate* isolate_;
|
||||
uint32_t global_offset;
|
||||
V8_ALIGNED(8) byte global_data[kMaxGlobalsSize]; // preallocated global data.
|
||||
byte* mem_start_;
|
||||
uint32_t mem_size_;
|
||||
std::vector<Handle<Code>> function_code_;
|
||||
std::vector<Handle<FixedArray>> function_tables_;
|
||||
std::vector<Handle<FixedArray>> signature_tables_;
|
||||
V8_ALIGNED(8) byte globals_data_[kMaxGlobalsSize];
|
||||
WasmInterpreter* interpreter_;
|
||||
Handle<WasmInstanceObject> instance_object_;
|
||||
|
||||
@ -336,7 +367,7 @@ class TestingModule : public ModuleEnv {
|
||||
global_offset += size;
|
||||
// limit number of globals.
|
||||
CHECK_LT(global_offset, kMaxGlobalsSize);
|
||||
return &module()->globals.back();
|
||||
return &test_module_.globals.back();
|
||||
}
|
||||
|
||||
Handle<WasmInstanceObject> InitInstanceObject() {
|
||||
@ -344,8 +375,8 @@ class TestingModule : public ModuleEnv {
|
||||
isolate_->factory()->NewStringFromOneByte({}).ToHandleChecked());
|
||||
// The lifetime of the wasm module is tied to this object's, and we cannot
|
||||
// rely on the mechanics of Managed<T>.
|
||||
Handle<Foreign> module_wrapper =
|
||||
isolate_->factory()->NewForeign(reinterpret_cast<Address>(&module_));
|
||||
Handle<Foreign> module_wrapper = isolate_->factory()->NewForeign(
|
||||
reinterpret_cast<Address>(&test_module_ptr_));
|
||||
Handle<Script> script =
|
||||
isolate_->factory()->NewScript(isolate_->factory()->empty_string());
|
||||
script->set_type(Script::TYPE_WASM);
|
||||
@ -354,14 +385,15 @@ class TestingModule : public ModuleEnv {
|
||||
script, Handle<ByteArray>::null());
|
||||
Handle<FixedArray> code_table = isolate_->factory()->NewFixedArray(0);
|
||||
|
||||
Handle<WasmCompiledModule> compiled_module = WasmCompiledModule::New(
|
||||
isolate_, shared_module_data, code_table, *this);
|
||||
Handle<WasmCompiledModule> compiled_module =
|
||||
WasmCompiledModule::New(isolate_, shared_module_data, code_table,
|
||||
function_tables_, signature_tables_);
|
||||
// This method is called when we initialize TestEnvironment. We don't
|
||||
// have a memory yet, so we won't create it here. We'll update the
|
||||
// interpreter when we get a memory. We do have globals, though.
|
||||
WasmCompiledModule::recreate_globals_start(
|
||||
compiled_module, isolate_->factory(),
|
||||
reinterpret_cast<size_t>(globals_start()));
|
||||
reinterpret_cast<size_t>(globals_data_));
|
||||
Handle<FixedArray> weak_exported = isolate_->factory()->NewFixedArray(0);
|
||||
compiled_module->set_weak_exported_functions(weak_exported);
|
||||
DCHECK(WasmCompiledModule::IsWasmCompiledModule(*compiled_module));
|
||||
@ -568,7 +600,8 @@ class WasmFunctionCompiler : private GraphAndBuilders {
|
||||
}
|
||||
|
||||
// Build the TurboFan graph.
|
||||
TestBuildingGraph(zone(), &jsgraph, testing_module_, sig,
|
||||
compiler::ModuleEnv module_env = testing_module_->CreateModuleEnv();
|
||||
TestBuildingGraph(zone(), &jsgraph, &module_env, sig,
|
||||
&source_position_table_, start, end,
|
||||
runtime_exception_support_);
|
||||
Handle<Code> code = Compile();
|
||||
@ -801,8 +834,7 @@ class WasmRunner : public WasmRunnerBase {
|
||||
};
|
||||
set_trap_callback_for_testing(trap_callback);
|
||||
|
||||
wrapper_.SetInnerCode(
|
||||
module_.GetFunctionCode(functions_[0]->function_index()));
|
||||
wrapper_.SetInnerCode(module_.GetFunctionCode(0));
|
||||
CodeRunner<int32_t> runner(CcTest::InitIsolateOnce(),
|
||||
wrapper_.GetWrapperCode(), wrapper_.signature());
|
||||
int32_t result = runner.Call(static_cast<void*>(&p)...,
|
||||
|
@ -14,6 +14,7 @@ function instantiate(buffer, ffi) {
|
||||
}
|
||||
|
||||
(function BasicTest() {
|
||||
print("BasicTest");
|
||||
let builder = new WasmModuleBuilder();
|
||||
builder.addMemory(1, 2, false);
|
||||
builder.addFunction("foo", kSig_i_v)
|
||||
@ -26,6 +27,7 @@ function instantiate(buffer, ffi) {
|
||||
})();
|
||||
|
||||
(function ImportTest() {
|
||||
print("ImportTest");
|
||||
let builder = new WasmModuleBuilder();
|
||||
var index = builder.addImport("", "print", makeSig_v_x(kWasmI32));
|
||||
builder.addFunction("foo", kSig_v_v)
|
||||
@ -39,6 +41,7 @@ function instantiate(buffer, ffi) {
|
||||
})();
|
||||
|
||||
(function LocalsTest() {
|
||||
print("LocalsTest");
|
||||
let builder = new WasmModuleBuilder();
|
||||
builder.addFunction(undefined, kSig_i_i)
|
||||
.addLocals({i32_count: 1})
|
||||
@ -52,6 +55,7 @@ function instantiate(buffer, ffi) {
|
||||
})();
|
||||
|
||||
(function LocalsTest2() {
|
||||
print("LocalsTest2");
|
||||
// TODO(titzer): i64 only works on 64-bit platforms.
|
||||
var types = [
|
||||
{locals: {i32_count: 1}, type: kWasmI32},
|
||||
@ -75,6 +79,7 @@ function instantiate(buffer, ffi) {
|
||||
})();
|
||||
|
||||
(function CallTest() {
|
||||
print("CallTest");
|
||||
let builder = new WasmModuleBuilder();
|
||||
builder.addFunction("add", kSig_i_ii)
|
||||
.addBody([kExprGetLocal, 0, kExprGetLocal, 1, kExprI32Add]);
|
||||
@ -88,6 +93,7 @@ function instantiate(buffer, ffi) {
|
||||
})();
|
||||
|
||||
(function IndirectCallTest() {
|
||||
print("IndirectCallTest");
|
||||
let builder = new WasmModuleBuilder();
|
||||
builder.addFunction("add", kSig_i_ii)
|
||||
.addBody([kExprGetLocal, 0, kExprGetLocal, 1, kExprI32Add]);
|
||||
@ -104,6 +110,7 @@ function instantiate(buffer, ffi) {
|
||||
})();
|
||||
|
||||
(function DataSegmentTest() {
|
||||
print("DataSegmentTest");
|
||||
let builder = new WasmModuleBuilder();
|
||||
builder.addMemory(1, 1, false);
|
||||
builder.addFunction("load", kSig_i_i)
|
||||
@ -118,6 +125,7 @@ function instantiate(buffer, ffi) {
|
||||
|
||||
|
||||
(function BasicTestWithUint8Array() {
|
||||
print("BasicTestWithUint8Array");
|
||||
let builder = new WasmModuleBuilder();
|
||||
builder.addMemory(1, 2, false);
|
||||
builder.addFunction("foo", kSig_i_v)
|
||||
@ -144,6 +152,7 @@ function instantiate(buffer, ffi) {
|
||||
})();
|
||||
|
||||
(function ImportTestTwoLevel() {
|
||||
print("ImportTestTwoLevel");
|
||||
let builder = new WasmModuleBuilder();
|
||||
var index = builder.addImport("mod", "print", makeSig_v_x(kWasmI32));
|
||||
builder.addFunction("foo", kSig_v_v)
|
||||
|
@ -90,7 +90,7 @@ class FunctionBodyDecoderTest : public TestWithZone {
|
||||
FunctionBodyDecoderTest() : module(nullptr), local_decls(zone()) {}
|
||||
|
||||
TestSignatures sigs;
|
||||
ModuleEnv* module;
|
||||
WasmModule* module;
|
||||
LocalDeclEncoder local_decls;
|
||||
|
||||
void AddLocals(ValueType type, uint32_t count) {
|
||||
@ -121,9 +121,8 @@ class FunctionBodyDecoderTest : public TestWithZone {
|
||||
PrepareBytecode(&start, &end);
|
||||
|
||||
// Verify the code.
|
||||
DecodeResult result = VerifyWasmCode(
|
||||
zone()->allocator(), module == nullptr ? nullptr : module->module(),
|
||||
sig, start, end);
|
||||
DecodeResult result =
|
||||
VerifyWasmCode(zone()->allocator(), module, sig, start, end);
|
||||
|
||||
uint32_t pc = result.error_offset();
|
||||
std::ostringstream str;
|
||||
@ -191,10 +190,9 @@ constexpr size_t kMaxByteSizedLeb128 = 127;
|
||||
|
||||
// A helper for tests that require a module environment for functions,
|
||||
// globals, or memories.
|
||||
class TestModuleEnv : public ModuleEnv {
|
||||
class TestModuleBuilder {
|
||||
public:
|
||||
explicit TestModuleEnv(ModuleOrigin origin = kWasmOrigin) {
|
||||
module_ = &mod;
|
||||
explicit TestModuleBuilder(ModuleOrigin origin = kWasmOrigin) {
|
||||
mod.set_origin(origin);
|
||||
}
|
||||
byte AddGlobal(ValueType type, bool mutability = true) {
|
||||
@ -237,6 +235,8 @@ class TestModuleEnv : public ModuleEnv {
|
||||
|
||||
void InitializeFunctionTable() { mod.function_tables.emplace_back(); }
|
||||
|
||||
WasmModule* module() { return &mod; }
|
||||
|
||||
private:
|
||||
WasmModule mod;
|
||||
};
|
||||
@ -1089,9 +1089,9 @@ TEST_F(FunctionBodyDecoderTest, TypeConversions) {
|
||||
}
|
||||
|
||||
TEST_F(FunctionBodyDecoderTest, MacrosStmt) {
|
||||
TestModuleEnv module_env;
|
||||
module = &module_env;
|
||||
module_env.InitializeMemory();
|
||||
TestModuleBuilder builder;
|
||||
module = builder.module();
|
||||
builder.InitializeMemory();
|
||||
EXPECT_VERIFIES(v_i, WASM_SET_LOCAL(0, WASM_I32V_3(87348)));
|
||||
EXPECT_VERIFIES(v_i, WASM_STORE_MEM(MachineType::Int32(), WASM_I32V_1(24),
|
||||
WASM_I32V_1(40)));
|
||||
@ -1228,18 +1228,18 @@ TEST_F(FunctionBodyDecoderTest, AllSimpleExpressions) {
|
||||
}
|
||||
|
||||
TEST_F(FunctionBodyDecoderTest, MemorySize) {
|
||||
TestModuleEnv module_env;
|
||||
module = &module_env;
|
||||
module_env.InitializeMemory();
|
||||
TestModuleBuilder builder;
|
||||
module = builder.module();
|
||||
builder.InitializeMemory();
|
||||
byte code[] = {kExprMemorySize, 0};
|
||||
EXPECT_VERIFIES_C(i_i, code);
|
||||
EXPECT_FAILURE_C(f_ff, code);
|
||||
}
|
||||
|
||||
TEST_F(FunctionBodyDecoderTest, LoadMemOffset) {
|
||||
TestModuleEnv module_env;
|
||||
module = &module_env;
|
||||
module_env.InitializeMemory();
|
||||
TestModuleBuilder builder;
|
||||
module = builder.module();
|
||||
builder.InitializeMemory();
|
||||
for (int offset = 0; offset < 128; offset += 7) {
|
||||
byte code[] = {kExprI32Const, 0, kExprI32LoadMem, ZERO_ALIGNMENT,
|
||||
static_cast<byte>(offset)};
|
||||
@ -1248,9 +1248,9 @@ TEST_F(FunctionBodyDecoderTest, LoadMemOffset) {
|
||||
}
|
||||
|
||||
TEST_F(FunctionBodyDecoderTest, LoadMemAlignment) {
|
||||
TestModuleEnv module_env;
|
||||
module = &module_env;
|
||||
module_env.InitializeMemory();
|
||||
TestModuleBuilder builder;
|
||||
module = builder.module();
|
||||
builder.InitializeMemory();
|
||||
struct {
|
||||
WasmOpcode instruction;
|
||||
uint32_t maximum_aligment;
|
||||
@ -1285,9 +1285,9 @@ TEST_F(FunctionBodyDecoderTest, LoadMemAlignment) {
|
||||
}
|
||||
|
||||
TEST_F(FunctionBodyDecoderTest, StoreMemOffset) {
|
||||
TestModuleEnv module_env;
|
||||
module = &module_env;
|
||||
module_env.InitializeMemory();
|
||||
TestModuleBuilder builder;
|
||||
module = builder.module();
|
||||
builder.InitializeMemory();
|
||||
for (byte offset = 0; offset < 128; offset += 7) {
|
||||
byte code[] = {WASM_STORE_MEM_OFFSET(MachineType::Int32(), offset,
|
||||
WASM_ZERO, WASM_ZERO)};
|
||||
@ -1296,9 +1296,9 @@ TEST_F(FunctionBodyDecoderTest, StoreMemOffset) {
|
||||
}
|
||||
|
||||
TEST_F(FunctionBodyDecoderTest, StoreMemOffset_void) {
|
||||
TestModuleEnv module_env;
|
||||
module = &module_env;
|
||||
module_env.InitializeMemory();
|
||||
TestModuleBuilder builder;
|
||||
module = builder.module();
|
||||
builder.InitializeMemory();
|
||||
EXPECT_FAILURE(i_i, WASM_STORE_MEM_OFFSET(MachineType::Int32(), 0, WASM_ZERO,
|
||||
WASM_ZERO));
|
||||
}
|
||||
@ -1314,9 +1314,9 @@ TEST_F(FunctionBodyDecoderTest, StoreMemOffset_void) {
|
||||
#define VARINT4(x) BYTE0(x) | 0x80, BYTE1(x) | 0x80, BYTE2(x) | 0x80, BYTE3(x)
|
||||
|
||||
TEST_F(FunctionBodyDecoderTest, LoadMemOffset_varint) {
|
||||
TestModuleEnv module_env;
|
||||
module = &module_env;
|
||||
module_env.InitializeMemory();
|
||||
TestModuleBuilder builder;
|
||||
module = builder.module();
|
||||
builder.InitializeMemory();
|
||||
EXPECT_VERIFIES(i_i, WASM_ZERO, kExprI32LoadMem, ZERO_ALIGNMENT,
|
||||
VARINT1(0x45));
|
||||
EXPECT_VERIFIES(i_i, WASM_ZERO, kExprI32LoadMem, ZERO_ALIGNMENT,
|
||||
@ -1328,9 +1328,9 @@ TEST_F(FunctionBodyDecoderTest, LoadMemOffset_varint) {
|
||||
}
|
||||
|
||||
TEST_F(FunctionBodyDecoderTest, StoreMemOffset_varint) {
|
||||
TestModuleEnv module_env;
|
||||
module = &module_env;
|
||||
module_env.InitializeMemory();
|
||||
TestModuleBuilder builder;
|
||||
module = builder.module();
|
||||
builder.InitializeMemory();
|
||||
EXPECT_VERIFIES(v_i, WASM_ZERO, WASM_ZERO, kExprI32StoreMem, ZERO_ALIGNMENT,
|
||||
VARINT1(0x33));
|
||||
EXPECT_VERIFIES(v_i, WASM_ZERO, WASM_ZERO, kExprI32StoreMem, ZERO_ALIGNMENT,
|
||||
@ -1342,9 +1342,9 @@ TEST_F(FunctionBodyDecoderTest, StoreMemOffset_varint) {
|
||||
}
|
||||
|
||||
TEST_F(FunctionBodyDecoderTest, AllLoadMemCombinations) {
|
||||
TestModuleEnv module_env;
|
||||
module = &module_env;
|
||||
module_env.InitializeMemory();
|
||||
TestModuleBuilder builder;
|
||||
module = builder.module();
|
||||
builder.InitializeMemory();
|
||||
for (size_t i = 0; i < arraysize(kValueTypes); i++) {
|
||||
ValueType local_type = kValueTypes[i];
|
||||
for (size_t j = 0; j < arraysize(machineTypes); j++) {
|
||||
@ -1361,9 +1361,9 @@ TEST_F(FunctionBodyDecoderTest, AllLoadMemCombinations) {
|
||||
}
|
||||
|
||||
TEST_F(FunctionBodyDecoderTest, AllStoreMemCombinations) {
|
||||
TestModuleEnv module_env;
|
||||
module = &module_env;
|
||||
module_env.InitializeMemory();
|
||||
TestModuleBuilder builder;
|
||||
module = builder.module();
|
||||
builder.InitializeMemory();
|
||||
for (size_t i = 0; i < arraysize(kValueTypes); i++) {
|
||||
ValueType local_type = kValueTypes[i];
|
||||
for (size_t j = 0; j < arraysize(machineTypes); j++) {
|
||||
@ -1381,12 +1381,12 @@ TEST_F(FunctionBodyDecoderTest, AllStoreMemCombinations) {
|
||||
|
||||
TEST_F(FunctionBodyDecoderTest, SimpleCalls) {
|
||||
FunctionSig* sig = sigs.i_i();
|
||||
TestModuleEnv module_env;
|
||||
module = &module_env;
|
||||
TestModuleBuilder builder;
|
||||
module = builder.module();
|
||||
|
||||
module_env.AddFunction(sigs.i_v());
|
||||
module_env.AddFunction(sigs.i_i());
|
||||
module_env.AddFunction(sigs.i_ii());
|
||||
builder.AddFunction(sigs.i_v());
|
||||
builder.AddFunction(sigs.i_i());
|
||||
builder.AddFunction(sigs.i_ii());
|
||||
|
||||
EXPECT_VERIFIES_S(sig, WASM_CALL_FUNCTION0(0));
|
||||
EXPECT_VERIFIES_S(sig, WASM_CALL_FUNCTION(1, WASM_I32V_1(27)));
|
||||
@ -1396,12 +1396,12 @@ TEST_F(FunctionBodyDecoderTest, SimpleCalls) {
|
||||
|
||||
TEST_F(FunctionBodyDecoderTest, CallsWithTooFewArguments) {
|
||||
FunctionSig* sig = sigs.i_i();
|
||||
TestModuleEnv module_env;
|
||||
module = &module_env;
|
||||
TestModuleBuilder builder;
|
||||
module = builder.module();
|
||||
|
||||
module_env.AddFunction(sigs.i_i());
|
||||
module_env.AddFunction(sigs.i_ii());
|
||||
module_env.AddFunction(sigs.f_ff());
|
||||
builder.AddFunction(sigs.i_i());
|
||||
builder.AddFunction(sigs.i_ii());
|
||||
builder.AddFunction(sigs.f_ff());
|
||||
|
||||
EXPECT_FAILURE_S(sig, WASM_CALL_FUNCTION0(0));
|
||||
EXPECT_FAILURE_S(sig, WASM_CALL_FUNCTION(1, WASM_ZERO));
|
||||
@ -1410,10 +1410,10 @@ TEST_F(FunctionBodyDecoderTest, CallsWithTooFewArguments) {
|
||||
|
||||
TEST_F(FunctionBodyDecoderTest, CallsWithMismatchedSigs2) {
|
||||
FunctionSig* sig = sigs.i_i();
|
||||
TestModuleEnv module_env;
|
||||
module = &module_env;
|
||||
TestModuleBuilder builder;
|
||||
module = builder.module();
|
||||
|
||||
module_env.AddFunction(sigs.i_i());
|
||||
builder.AddFunction(sigs.i_i());
|
||||
|
||||
EXPECT_FAILURE_S(sig, WASM_CALL_FUNCTION(0, WASM_I64V_1(17)));
|
||||
EXPECT_FAILURE_S(sig, WASM_CALL_FUNCTION(0, WASM_F32(17.1)));
|
||||
@ -1422,16 +1422,16 @@ TEST_F(FunctionBodyDecoderTest, CallsWithMismatchedSigs2) {
|
||||
|
||||
TEST_F(FunctionBodyDecoderTest, CallsWithMismatchedSigs3) {
|
||||
FunctionSig* sig = sigs.i_i();
|
||||
TestModuleEnv module_env;
|
||||
module = &module_env;
|
||||
TestModuleBuilder builder;
|
||||
module = builder.module();
|
||||
|
||||
module_env.AddFunction(sigs.i_f());
|
||||
builder.AddFunction(sigs.i_f());
|
||||
|
||||
EXPECT_FAILURE_S(sig, WASM_CALL_FUNCTION(0, WASM_I32V_1(17)));
|
||||
EXPECT_FAILURE_S(sig, WASM_CALL_FUNCTION(0, WASM_I64V_1(27)));
|
||||
EXPECT_FAILURE_S(sig, WASM_CALL_FUNCTION(0, WASM_F64(37.2)));
|
||||
|
||||
module_env.AddFunction(sigs.i_d());
|
||||
builder.AddFunction(sigs.i_d());
|
||||
|
||||
EXPECT_FAILURE_S(sig, WASM_CALL_FUNCTION(1, WASM_I32V_1(16)));
|
||||
EXPECT_FAILURE_S(sig, WASM_CALL_FUNCTION(1, WASM_I64V_1(16)));
|
||||
@ -1443,11 +1443,11 @@ TEST_F(FunctionBodyDecoderTest, MultiReturn) {
|
||||
ValueType storage[] = {kWasmI32, kWasmI32};
|
||||
FunctionSig sig_ii_v(2, 0, storage);
|
||||
FunctionSig sig_v_ii(0, 2, storage);
|
||||
TestModuleEnv module_env;
|
||||
module = &module_env;
|
||||
TestModuleBuilder builder;
|
||||
module = builder.module();
|
||||
|
||||
module_env.AddFunction(&sig_v_ii);
|
||||
module_env.AddFunction(&sig_ii_v);
|
||||
builder.AddFunction(&sig_v_ii);
|
||||
builder.AddFunction(&sig_ii_v);
|
||||
|
||||
EXPECT_VERIFIES_S(&sig_ii_v, WASM_CALL_FUNCTION0(1));
|
||||
EXPECT_VERIFIES(v_v, WASM_CALL_FUNCTION0(1), WASM_DROP, WASM_DROP);
|
||||
@ -1465,9 +1465,9 @@ TEST_F(FunctionBodyDecoderTest, MultiReturnType) {
|
||||
ValueType storage_cd[] = {kValueTypes[c], kValueTypes[d]};
|
||||
FunctionSig sig_cd_v(2, 0, storage_cd);
|
||||
|
||||
TestModuleEnv module_env;
|
||||
module = &module_env;
|
||||
module_env.AddFunction(&sig_cd_v);
|
||||
TestModuleBuilder builder;
|
||||
module = builder.module();
|
||||
builder.AddFunction(&sig_cd_v);
|
||||
|
||||
EXPECT_VERIFIES_S(&sig_cd_v, WASM_CALL_FUNCTION0(0));
|
||||
|
||||
@ -1484,13 +1484,13 @@ TEST_F(FunctionBodyDecoderTest, MultiReturnType) {
|
||||
|
||||
TEST_F(FunctionBodyDecoderTest, SimpleIndirectCalls) {
|
||||
FunctionSig* sig = sigs.i_i();
|
||||
TestModuleEnv module_env;
|
||||
module_env.InitializeFunctionTable();
|
||||
module = &module_env;
|
||||
TestModuleBuilder builder;
|
||||
builder.InitializeFunctionTable();
|
||||
module = builder.module();
|
||||
|
||||
byte f0 = module_env.AddSignature(sigs.i_v());
|
||||
byte f1 = module_env.AddSignature(sigs.i_i());
|
||||
byte f2 = module_env.AddSignature(sigs.i_ii());
|
||||
byte f0 = builder.AddSignature(sigs.i_v());
|
||||
byte f1 = builder.AddSignature(sigs.i_i());
|
||||
byte f2 = builder.AddSignature(sigs.i_ii());
|
||||
|
||||
EXPECT_VERIFIES_S(sig, WASM_CALL_INDIRECT0(f0, WASM_ZERO));
|
||||
EXPECT_VERIFIES_S(sig, WASM_CALL_INDIRECT1(f1, WASM_ZERO, WASM_I32V_1(22)));
|
||||
@ -1500,16 +1500,16 @@ TEST_F(FunctionBodyDecoderTest, SimpleIndirectCalls) {
|
||||
|
||||
TEST_F(FunctionBodyDecoderTest, IndirectCallsOutOfBounds) {
|
||||
FunctionSig* sig = sigs.i_i();
|
||||
TestModuleEnv module_env;
|
||||
module_env.InitializeFunctionTable();
|
||||
module = &module_env;
|
||||
TestModuleBuilder builder;
|
||||
builder.InitializeFunctionTable();
|
||||
module = builder.module();
|
||||
|
||||
EXPECT_FAILURE_S(sig, WASM_CALL_INDIRECT0(0, WASM_ZERO));
|
||||
module_env.AddSignature(sigs.i_v());
|
||||
builder.AddSignature(sigs.i_v());
|
||||
EXPECT_VERIFIES_S(sig, WASM_CALL_INDIRECT0(0, WASM_ZERO));
|
||||
|
||||
EXPECT_FAILURE_S(sig, WASM_CALL_INDIRECT1(1, WASM_ZERO, WASM_I32V_1(22)));
|
||||
module_env.AddSignature(sigs.i_i());
|
||||
builder.AddSignature(sigs.i_i());
|
||||
EXPECT_VERIFIES_S(sig, WASM_CALL_INDIRECT1(1, WASM_ZERO, WASM_I32V_1(27)));
|
||||
|
||||
EXPECT_FAILURE_S(sig, WASM_CALL_INDIRECT1(2, WASM_ZERO, WASM_I32V_1(27)));
|
||||
@ -1517,11 +1517,11 @@ TEST_F(FunctionBodyDecoderTest, IndirectCallsOutOfBounds) {
|
||||
|
||||
TEST_F(FunctionBodyDecoderTest, IndirectCallsWithMismatchedSigs3) {
|
||||
FunctionSig* sig = sigs.i_i();
|
||||
TestModuleEnv module_env;
|
||||
module_env.InitializeFunctionTable();
|
||||
module = &module_env;
|
||||
TestModuleBuilder builder;
|
||||
builder.InitializeFunctionTable();
|
||||
module = builder.module();
|
||||
|
||||
byte f0 = module_env.AddFunction(sigs.i_f());
|
||||
byte f0 = builder.AddFunction(sigs.i_f());
|
||||
|
||||
EXPECT_FAILURE_S(sig, WASM_CALL_INDIRECT1(f0, WASM_ZERO, WASM_I32V_1(17)));
|
||||
EXPECT_FAILURE_S(sig, WASM_CALL_INDIRECT1(f0, WASM_ZERO, WASM_I64V_1(27)));
|
||||
@ -1531,7 +1531,7 @@ TEST_F(FunctionBodyDecoderTest, IndirectCallsWithMismatchedSigs3) {
|
||||
EXPECT_FAILURE_S(sig, WASM_CALL_INDIRECT0(f0, WASM_I64V_1(27)));
|
||||
EXPECT_FAILURE_S(sig, WASM_CALL_INDIRECT0(f0, WASM_F64(37.2)));
|
||||
|
||||
byte f1 = module_env.AddFunction(sigs.i_d());
|
||||
byte f1 = builder.AddFunction(sigs.i_d());
|
||||
|
||||
EXPECT_FAILURE_S(sig, WASM_CALL_INDIRECT1(f1, WASM_ZERO, WASM_I32V_1(16)));
|
||||
EXPECT_FAILURE_S(sig, WASM_CALL_INDIRECT1(f1, WASM_ZERO, WASM_I64V_1(16)));
|
||||
@ -1540,12 +1540,12 @@ TEST_F(FunctionBodyDecoderTest, IndirectCallsWithMismatchedSigs3) {
|
||||
|
||||
TEST_F(FunctionBodyDecoderTest, IndirectCallsWithoutTableCrash) {
|
||||
FunctionSig* sig = sigs.i_i();
|
||||
TestModuleEnv module_env;
|
||||
module = &module_env;
|
||||
TestModuleBuilder builder;
|
||||
module = builder.module();
|
||||
|
||||
byte f0 = module_env.AddSignature(sigs.i_v());
|
||||
byte f1 = module_env.AddSignature(sigs.i_i());
|
||||
byte f2 = module_env.AddSignature(sigs.i_ii());
|
||||
byte f0 = builder.AddSignature(sigs.i_v());
|
||||
byte f1 = builder.AddSignature(sigs.i_i());
|
||||
byte f2 = builder.AddSignature(sigs.i_ii());
|
||||
|
||||
EXPECT_FAILURE_S(sig, WASM_CALL_INDIRECT0(f0, WASM_ZERO));
|
||||
EXPECT_FAILURE_S(sig, WASM_CALL_INDIRECT1(f1, WASM_ZERO, WASM_I32V_1(22)));
|
||||
@ -1555,12 +1555,12 @@ TEST_F(FunctionBodyDecoderTest, IndirectCallsWithoutTableCrash) {
|
||||
|
||||
TEST_F(FunctionBodyDecoderTest, SimpleImportCalls) {
|
||||
FunctionSig* sig = sigs.i_i();
|
||||
TestModuleEnv module_env;
|
||||
module = &module_env;
|
||||
TestModuleBuilder builder;
|
||||
module = builder.module();
|
||||
|
||||
byte f0 = module_env.AddImport(sigs.i_v());
|
||||
byte f1 = module_env.AddImport(sigs.i_i());
|
||||
byte f2 = module_env.AddImport(sigs.i_ii());
|
||||
byte f0 = builder.AddImport(sigs.i_v());
|
||||
byte f1 = builder.AddImport(sigs.i_i());
|
||||
byte f2 = builder.AddImport(sigs.i_ii());
|
||||
|
||||
EXPECT_VERIFIES_S(sig, WASM_CALL_FUNCTION0(f0));
|
||||
EXPECT_VERIFIES_S(sig, WASM_CALL_FUNCTION(f1, WASM_I32V_1(22)));
|
||||
@ -1570,17 +1570,17 @@ TEST_F(FunctionBodyDecoderTest, SimpleImportCalls) {
|
||||
|
||||
TEST_F(FunctionBodyDecoderTest, ImportCallsWithMismatchedSigs3) {
|
||||
FunctionSig* sig = sigs.i_i();
|
||||
TestModuleEnv module_env;
|
||||
module = &module_env;
|
||||
TestModuleBuilder builder;
|
||||
module = builder.module();
|
||||
|
||||
byte f0 = module_env.AddImport(sigs.i_f());
|
||||
byte f0 = builder.AddImport(sigs.i_f());
|
||||
|
||||
EXPECT_FAILURE_S(sig, WASM_CALL_FUNCTION0(f0));
|
||||
EXPECT_FAILURE_S(sig, WASM_CALL_FUNCTION(f0, WASM_I32V_1(17)));
|
||||
EXPECT_FAILURE_S(sig, WASM_CALL_FUNCTION(f0, WASM_I64V_1(27)));
|
||||
EXPECT_FAILURE_S(sig, WASM_CALL_FUNCTION(f0, WASM_F64(37.2)));
|
||||
|
||||
byte f1 = module_env.AddImport(sigs.i_d());
|
||||
byte f1 = builder.AddImport(sigs.i_d());
|
||||
|
||||
EXPECT_FAILURE_S(sig, WASM_CALL_FUNCTION0(f1));
|
||||
EXPECT_FAILURE_S(sig, WASM_CALL_FUNCTION(f1, WASM_I32V_1(16)));
|
||||
@ -1590,10 +1590,10 @@ TEST_F(FunctionBodyDecoderTest, ImportCallsWithMismatchedSigs3) {
|
||||
|
||||
TEST_F(FunctionBodyDecoderTest, Int32Globals) {
|
||||
FunctionSig* sig = sigs.i_i();
|
||||
TestModuleEnv module_env;
|
||||
module = &module_env;
|
||||
TestModuleBuilder builder;
|
||||
module = builder.module();
|
||||
|
||||
module_env.AddGlobal(kWasmI32);
|
||||
builder.AddGlobal(kWasmI32);
|
||||
|
||||
EXPECT_VERIFIES_S(sig, WASM_GET_GLOBAL(0));
|
||||
EXPECT_FAILURE_S(sig, WASM_SET_GLOBAL(0, WASM_GET_LOCAL(0)));
|
||||
@ -1602,11 +1602,11 @@ TEST_F(FunctionBodyDecoderTest, Int32Globals) {
|
||||
|
||||
TEST_F(FunctionBodyDecoderTest, ImmutableGlobal) {
|
||||
FunctionSig* sig = sigs.v_v();
|
||||
TestModuleEnv module_env;
|
||||
module = &module_env;
|
||||
TestModuleBuilder builder;
|
||||
module = builder.module();
|
||||
|
||||
uint32_t g0 = module_env.AddGlobal(kWasmI32, true);
|
||||
uint32_t g1 = module_env.AddGlobal(kWasmI32, false);
|
||||
uint32_t g0 = builder.AddGlobal(kWasmI32, true);
|
||||
uint32_t g1 = builder.AddGlobal(kWasmI32, false);
|
||||
|
||||
EXPECT_VERIFIES_S(sig, WASM_SET_GLOBAL(g0, WASM_ZERO));
|
||||
EXPECT_FAILURE_S(sig, WASM_SET_GLOBAL(g1, WASM_ZERO));
|
||||
@ -1614,13 +1614,13 @@ TEST_F(FunctionBodyDecoderTest, ImmutableGlobal) {
|
||||
|
||||
TEST_F(FunctionBodyDecoderTest, Int32Globals_fail) {
|
||||
FunctionSig* sig = sigs.i_i();
|
||||
TestModuleEnv module_env;
|
||||
module = &module_env;
|
||||
TestModuleBuilder builder;
|
||||
module = builder.module();
|
||||
|
||||
module_env.AddGlobal(kWasmI64);
|
||||
module_env.AddGlobal(kWasmI64);
|
||||
module_env.AddGlobal(kWasmF32);
|
||||
module_env.AddGlobal(kWasmF64);
|
||||
builder.AddGlobal(kWasmI64);
|
||||
builder.AddGlobal(kWasmI64);
|
||||
builder.AddGlobal(kWasmF32);
|
||||
builder.AddGlobal(kWasmF64);
|
||||
|
||||
EXPECT_FAILURE_S(sig, WASM_GET_GLOBAL(0));
|
||||
EXPECT_FAILURE_S(sig, WASM_GET_GLOBAL(1));
|
||||
@ -1635,11 +1635,11 @@ TEST_F(FunctionBodyDecoderTest, Int32Globals_fail) {
|
||||
|
||||
TEST_F(FunctionBodyDecoderTest, Int64Globals) {
|
||||
FunctionSig* sig = sigs.l_l();
|
||||
TestModuleEnv module_env;
|
||||
module = &module_env;
|
||||
TestModuleBuilder builder;
|
||||
module = builder.module();
|
||||
|
||||
module_env.AddGlobal(kWasmI64);
|
||||
module_env.AddGlobal(kWasmI64);
|
||||
builder.AddGlobal(kWasmI64);
|
||||
builder.AddGlobal(kWasmI64);
|
||||
|
||||
EXPECT_VERIFIES_S(sig, WASM_GET_GLOBAL(0));
|
||||
EXPECT_VERIFIES_S(sig, WASM_GET_GLOBAL(1));
|
||||
@ -1652,10 +1652,10 @@ TEST_F(FunctionBodyDecoderTest, Int64Globals) {
|
||||
|
||||
TEST_F(FunctionBodyDecoderTest, Float32Globals) {
|
||||
FunctionSig* sig = sigs.f_ff();
|
||||
TestModuleEnv module_env;
|
||||
module = &module_env;
|
||||
TestModuleBuilder builder;
|
||||
module = builder.module();
|
||||
|
||||
module_env.AddGlobal(kWasmF32);
|
||||
builder.AddGlobal(kWasmF32);
|
||||
|
||||
EXPECT_VERIFIES_S(sig, WASM_GET_GLOBAL(0));
|
||||
EXPECT_VERIFIES_S(sig, WASM_SET_GLOBAL(0, WASM_GET_LOCAL(0)),
|
||||
@ -1664,10 +1664,10 @@ TEST_F(FunctionBodyDecoderTest, Float32Globals) {
|
||||
|
||||
TEST_F(FunctionBodyDecoderTest, Float64Globals) {
|
||||
FunctionSig* sig = sigs.d_dd();
|
||||
TestModuleEnv module_env;
|
||||
module = &module_env;
|
||||
TestModuleBuilder builder;
|
||||
module = builder.module();
|
||||
|
||||
module_env.AddGlobal(kWasmF64);
|
||||
builder.AddGlobal(kWasmF64);
|
||||
|
||||
EXPECT_VERIFIES_S(sig, WASM_GET_GLOBAL(0));
|
||||
EXPECT_VERIFIES_S(sig, WASM_SET_GLOBAL(0, WASM_GET_LOCAL(0)),
|
||||
@ -1680,9 +1680,9 @@ TEST_F(FunctionBodyDecoderTest, AllGetGlobalCombinations) {
|
||||
for (size_t j = 0; j < arraysize(kValueTypes); j++) {
|
||||
ValueType global_type = kValueTypes[j];
|
||||
FunctionSig sig(1, 0, &local_type);
|
||||
TestModuleEnv module_env;
|
||||
module = &module_env;
|
||||
module_env.AddGlobal(global_type);
|
||||
TestModuleBuilder builder;
|
||||
module = builder.module();
|
||||
builder.AddGlobal(global_type);
|
||||
if (local_type == global_type) {
|
||||
EXPECT_VERIFIES_S(&sig, WASM_GET_GLOBAL(0));
|
||||
} else {
|
||||
@ -1698,9 +1698,9 @@ TEST_F(FunctionBodyDecoderTest, AllSetGlobalCombinations) {
|
||||
for (size_t j = 0; j < arraysize(kValueTypes); j++) {
|
||||
ValueType global_type = kValueTypes[j];
|
||||
FunctionSig sig(0, 1, &local_type);
|
||||
TestModuleEnv module_env;
|
||||
module = &module_env;
|
||||
module_env.AddGlobal(global_type);
|
||||
TestModuleBuilder builder;
|
||||
module = builder.module();
|
||||
builder.AddGlobal(global_type);
|
||||
if (local_type == global_type) {
|
||||
EXPECT_VERIFIES_S(&sig, WASM_SET_GLOBAL(0, WASM_GET_LOCAL(0)));
|
||||
} else {
|
||||
@ -1711,9 +1711,9 @@ TEST_F(FunctionBodyDecoderTest, AllSetGlobalCombinations) {
|
||||
}
|
||||
|
||||
TEST_F(FunctionBodyDecoderTest, WasmGrowMemory) {
|
||||
TestModuleEnv module_env;
|
||||
module = &module_env;
|
||||
module_env.InitializeMemory();
|
||||
TestModuleBuilder builder;
|
||||
module = builder.module();
|
||||
builder.InitializeMemory();
|
||||
|
||||
byte code[] = {WASM_GET_LOCAL(0), kExprGrowMemory, 0};
|
||||
EXPECT_VERIFIES_C(i_i, code);
|
||||
@ -1721,9 +1721,9 @@ TEST_F(FunctionBodyDecoderTest, WasmGrowMemory) {
|
||||
}
|
||||
|
||||
TEST_F(FunctionBodyDecoderTest, AsmJsGrowMemory) {
|
||||
TestModuleEnv module_env(kAsmJsOrigin);
|
||||
module = &module_env;
|
||||
module_env.InitializeMemory();
|
||||
TestModuleBuilder builder(kAsmJsOrigin);
|
||||
module = builder.module();
|
||||
builder.InitializeMemory();
|
||||
|
||||
byte code[] = {WASM_GET_LOCAL(0), kExprGrowMemory, 0};
|
||||
EXPECT_FAILURE_C(i_i, code);
|
||||
@ -1753,18 +1753,18 @@ TEST_F(FunctionBodyDecoderTest, AsmJsBinOpsCheckOrigin) {
|
||||
};
|
||||
|
||||
{
|
||||
TestModuleEnv module_env(kAsmJsOrigin);
|
||||
module = &module_env;
|
||||
module_env.InitializeMemory();
|
||||
TestModuleBuilder builder(kAsmJsOrigin);
|
||||
module = builder.module();
|
||||
builder.InitializeMemory();
|
||||
for (size_t i = 0; i < arraysize(AsmJsBinOps); i++) {
|
||||
TestBinop(AsmJsBinOps[i].op, AsmJsBinOps[i].sig);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
TestModuleEnv module_env;
|
||||
module = &module_env;
|
||||
module_env.InitializeMemory();
|
||||
TestModuleBuilder builder;
|
||||
module = builder.module();
|
||||
builder.InitializeMemory();
|
||||
for (size_t i = 0; i < arraysize(AsmJsBinOps); i++) {
|
||||
byte code[] = {
|
||||
WASM_BINOP(AsmJsBinOps[i].op, WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))};
|
||||
@ -1801,18 +1801,18 @@ TEST_F(FunctionBodyDecoderTest, AsmJsUnOpsCheckOrigin) {
|
||||
{kExprI32AsmjsSConvertF64, sigs.i_d()},
|
||||
{kExprI32AsmjsUConvertF64, sigs.i_d()}};
|
||||
{
|
||||
TestModuleEnv module_env(kAsmJsOrigin);
|
||||
module = &module_env;
|
||||
module_env.InitializeMemory();
|
||||
TestModuleBuilder builder(kAsmJsOrigin);
|
||||
module = builder.module();
|
||||
builder.InitializeMemory();
|
||||
for (size_t i = 0; i < arraysize(AsmJsUnOps); i++) {
|
||||
TestUnop(AsmJsUnOps[i].op, AsmJsUnOps[i].sig);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
TestModuleEnv module_env;
|
||||
module = &module_env;
|
||||
module_env.InitializeMemory();
|
||||
TestModuleBuilder builder;
|
||||
module = builder.module();
|
||||
builder.InitializeMemory();
|
||||
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);
|
||||
@ -2241,11 +2241,11 @@ TEST_F(FunctionBodyDecoderTest, Select_TypeCheck) {
|
||||
|
||||
TEST_F(FunctionBodyDecoderTest, Throw) {
|
||||
EXPERIMENTAL_FLAG_SCOPE(eh);
|
||||
TestModuleEnv module_env;
|
||||
module = &module_env;
|
||||
TestModuleBuilder builder;
|
||||
module = builder.module();
|
||||
|
||||
module_env.AddException(sigs.v_v());
|
||||
module_env.AddException(sigs.v_i());
|
||||
builder.AddException(sigs.v_v());
|
||||
builder.AddException(sigs.v_i());
|
||||
AddLocals(kWasmI32, 1);
|
||||
|
||||
EXPECT_VERIFIES(v_v, kExprThrow, 0);
|
||||
@ -2262,11 +2262,11 @@ TEST_F(FunctionBodyDecoderTest, Throw) {
|
||||
TEST_F(FunctionBodyDecoderTest, ThrowUnreachable) {
|
||||
// TODO(titzer): unreachable code after throw should validate.
|
||||
EXPERIMENTAL_FLAG_SCOPE(eh);
|
||||
TestModuleEnv module_env;
|
||||
module = &module_env;
|
||||
TestModuleBuilder builder;
|
||||
module = builder.module();
|
||||
|
||||
module_env.AddException(sigs.v_v());
|
||||
module_env.AddException(sigs.v_i());
|
||||
builder.AddException(sigs.v_v());
|
||||
builder.AddException(sigs.v_i());
|
||||
AddLocals(kWasmI32, 1);
|
||||
EXPECT_VERIFIES(i_i, kExprThrow, 0, WASM_GET_LOCAL(0));
|
||||
|
||||
@ -2281,10 +2281,10 @@ TEST_F(FunctionBodyDecoderTest, ThrowUnreachable) {
|
||||
TEST_F(FunctionBodyDecoderTest, TryCatch) {
|
||||
EXPERIMENTAL_FLAG_SCOPE(eh);
|
||||
|
||||
TestModuleEnv module_env;
|
||||
module = &module_env;
|
||||
module_env.AddException(sigs.v_v());
|
||||
module_env.AddException(sigs.v_v());
|
||||
TestModuleBuilder builder;
|
||||
module = builder.module();
|
||||
builder.AddException(sigs.v_v());
|
||||
builder.AddException(sigs.v_v());
|
||||
|
||||
// TODO(kschimpf): Need to fix catch to use declared exception.
|
||||
EXPECT_VERIFIES(v_v, WASM_TRY_OP, WASM_CATCH(0), kExprEnd);
|
||||
|
@ -985,16 +985,11 @@ TEST_F(WasmSignatureDecodeTest, Fail_invalid_param_type2) {
|
||||
|
||||
class WasmFunctionVerifyTest : public TestWithIsolateAndZone {
|
||||
public:
|
||||
WasmFunctionVerifyTest() : env(&module, Handle<Code>::null()) {}
|
||||
WasmFunctionVerifyTest() {}
|
||||
virtual ~WasmFunctionVerifyTest() {}
|
||||
|
||||
const ModuleEnv* get_env() const { return &env; }
|
||||
Vector<const byte> get_bytes() const { return bytes; }
|
||||
|
||||
private:
|
||||
WasmModule module;
|
||||
Vector<const byte> bytes;
|
||||
ModuleEnv env;
|
||||
DISALLOW_COPY_AND_ASSIGN(WasmFunctionVerifyTest);
|
||||
};
|
||||
|
||||
@ -1013,9 +1008,8 @@ TEST_F(WasmFunctionVerifyTest, Ok_v_v_empty) {
|
||||
kExprEnd // body
|
||||
};
|
||||
|
||||
FunctionResult result =
|
||||
SyncDecodeWasmFunction(isolate(), zone(), get_bytes(),
|
||||
get_env()->module(), data, data + sizeof(data));
|
||||
FunctionResult result = SyncDecodeWasmFunction(
|
||||
isolate(), zone(), bytes, &module, data, data + sizeof(data));
|
||||
EXPECT_OK(result);
|
||||
|
||||
if (result.val && result.ok()) {
|
||||
|
Loading…
Reference in New Issue
Block a user