[wasm] Prerequisites for WebAssembly Table.Grow
- Refactor Dispatch tables to have separate function, signature tables - New Relocation type for WasmFunctionTableReference, assembler, compiler support. - RelocInfo helper functions for Wasm references Review-Url: https://codereview.chromium.org/2627543003 Cr-Commit-Position: refs/heads/master@{#42192}
This commit is contained in:
parent
b1cfa6448c
commit
0c4b8ff44c
@ -351,13 +351,18 @@ Address RelocInfo::wasm_global_reference() {
|
||||
return Assembler::target_address_at(pc_, host_);
|
||||
}
|
||||
|
||||
uint32_t RelocInfo::wasm_function_table_size_reference() {
|
||||
DCHECK(IsWasmFunctionTableSizeReference(rmode_));
|
||||
return reinterpret_cast<uint32_t>(Assembler::target_address_at(pc_, host_));
|
||||
}
|
||||
|
||||
void RelocInfo::unchecked_update_wasm_memory_reference(
|
||||
Address address, ICacheFlushMode flush_mode) {
|
||||
Assembler::set_target_address_at(isolate_, pc_, host_, address, flush_mode);
|
||||
}
|
||||
|
||||
void RelocInfo::unchecked_update_wasm_memory_size(uint32_t size,
|
||||
ICacheFlushMode flush_mode) {
|
||||
void RelocInfo::unchecked_update_wasm_size(uint32_t size,
|
||||
ICacheFlushMode flush_mode) {
|
||||
Assembler::set_target_address_at(isolate_, pc_, host_,
|
||||
reinterpret_cast<Address>(size), flush_mode);
|
||||
}
|
||||
|
@ -194,13 +194,18 @@ Address RelocInfo::wasm_global_reference() {
|
||||
return Memory::Address_at(Assembler::target_pointer_address_at(pc_));
|
||||
}
|
||||
|
||||
uint32_t RelocInfo::wasm_function_table_size_reference() {
|
||||
DCHECK(IsWasmFunctionTableSizeReference(rmode_));
|
||||
return Memory::uint32_at(Assembler::target_pointer_address_at(pc_));
|
||||
}
|
||||
|
||||
void RelocInfo::unchecked_update_wasm_memory_reference(
|
||||
Address address, ICacheFlushMode flush_mode) {
|
||||
Assembler::set_target_address_at(isolate_, pc_, host_, address, flush_mode);
|
||||
}
|
||||
|
||||
void RelocInfo::unchecked_update_wasm_memory_size(uint32_t size,
|
||||
ICacheFlushMode flush_mode) {
|
||||
void RelocInfo::unchecked_update_wasm_size(uint32_t size,
|
||||
ICacheFlushMode flush_mode) {
|
||||
Memory::uint32_at(Assembler::target_pointer_address_at(pc_)) = size;
|
||||
}
|
||||
|
||||
|
@ -334,8 +334,7 @@ void RelocInfo::update_wasm_memory_reference(
|
||||
uint32_t current_size_reference = wasm_memory_size_reference();
|
||||
uint32_t updated_size_reference =
|
||||
new_size + (current_size_reference - old_size);
|
||||
unchecked_update_wasm_memory_size(updated_size_reference,
|
||||
icache_flush_mode);
|
||||
unchecked_update_wasm_size(updated_size_reference, icache_flush_mode);
|
||||
} else {
|
||||
UNREACHABLE();
|
||||
}
|
||||
@ -359,6 +358,18 @@ void RelocInfo::update_wasm_global_reference(
|
||||
}
|
||||
}
|
||||
|
||||
void RelocInfo::update_wasm_function_table_size_reference(
|
||||
uint32_t old_size, uint32_t new_size, ICacheFlushMode icache_flush_mode) {
|
||||
DCHECK(IsWasmFunctionTableSizeReference(rmode_));
|
||||
uint32_t current_size_reference = wasm_function_table_size_reference();
|
||||
uint32_t updated_size_reference =
|
||||
new_size + (current_size_reference - old_size);
|
||||
unchecked_update_wasm_size(updated_size_reference, icache_flush_mode);
|
||||
if (icache_flush_mode != SKIP_ICACHE_FLUSH) {
|
||||
Assembler::FlushICache(isolate_, pc_, sizeof(int64_t));
|
||||
}
|
||||
}
|
||||
|
||||
void RelocInfo::set_target_address(Address target,
|
||||
WriteBarrierMode write_barrier_mode,
|
||||
ICacheFlushMode icache_flush_mode) {
|
||||
@ -769,6 +780,8 @@ const char* RelocInfo::RelocModeName(RelocInfo::Mode rmode) {
|
||||
return "wasm memory size reference";
|
||||
case WASM_GLOBAL_REFERENCE:
|
||||
return "wasm global value reference";
|
||||
case WASM_FUNCTION_TABLE_SIZE_REFERENCE:
|
||||
return "wasm function table size reference";
|
||||
case NUMBER_OF_MODES:
|
||||
case PC_JUMP:
|
||||
UNREACHABLE();
|
||||
@ -866,6 +879,7 @@ void RelocInfo::Verify(Isolate* isolate) {
|
||||
case WASM_MEMORY_REFERENCE:
|
||||
case WASM_MEMORY_SIZE_REFERENCE:
|
||||
case WASM_GLOBAL_REFERENCE:
|
||||
case WASM_FUNCTION_TABLE_SIZE_REFERENCE:
|
||||
case NONE32:
|
||||
case NONE64:
|
||||
break;
|
||||
|
@ -395,6 +395,7 @@ class RelocInfo {
|
||||
WASM_MEMORY_REFERENCE,
|
||||
WASM_GLOBAL_REFERENCE,
|
||||
WASM_MEMORY_SIZE_REFERENCE,
|
||||
WASM_FUNCTION_TABLE_SIZE_REFERENCE,
|
||||
CELL,
|
||||
|
||||
// Everything after runtime_entry (inclusive) is not GC'ed.
|
||||
@ -437,7 +438,7 @@ class RelocInfo {
|
||||
FIRST_REAL_RELOC_MODE = CODE_TARGET,
|
||||
LAST_REAL_RELOC_MODE = VENEER_POOL,
|
||||
LAST_CODE_ENUM = DEBUGGER_STATEMENT,
|
||||
LAST_GCED_ENUM = WASM_MEMORY_SIZE_REFERENCE,
|
||||
LAST_GCED_ENUM = WASM_FUNCTION_TABLE_SIZE_REFERENCE,
|
||||
FIRST_SHAREABLE_RELOC_MODE = CELL,
|
||||
};
|
||||
|
||||
@ -530,6 +531,22 @@ class RelocInfo {
|
||||
static inline bool IsWasmGlobalReference(Mode mode) {
|
||||
return mode == WASM_GLOBAL_REFERENCE;
|
||||
}
|
||||
static inline bool IsWasmFunctionTableSizeReference(Mode mode) {
|
||||
return mode == WASM_FUNCTION_TABLE_SIZE_REFERENCE;
|
||||
}
|
||||
static inline bool IsWasmReference(Mode mode) {
|
||||
return mode == WASM_MEMORY_REFERENCE || mode == WASM_GLOBAL_REFERENCE ||
|
||||
mode == WASM_MEMORY_SIZE_REFERENCE ||
|
||||
mode == WASM_FUNCTION_TABLE_SIZE_REFERENCE;
|
||||
}
|
||||
static inline bool IsWasmSizeReference(Mode mode) {
|
||||
return mode == WASM_MEMORY_SIZE_REFERENCE ||
|
||||
mode == WASM_FUNCTION_TABLE_SIZE_REFERENCE;
|
||||
}
|
||||
static inline bool IsWasmPtrReference(Mode mode) {
|
||||
return mode == WASM_MEMORY_REFERENCE || mode == WASM_GLOBAL_REFERENCE;
|
||||
}
|
||||
|
||||
static inline int ModeMask(Mode mode) { return 1 << mode; }
|
||||
|
||||
// Accessors
|
||||
@ -558,6 +575,7 @@ class RelocInfo {
|
||||
|
||||
Address wasm_memory_reference();
|
||||
Address wasm_global_reference();
|
||||
uint32_t wasm_function_table_size_reference();
|
||||
uint32_t wasm_memory_size_reference();
|
||||
void update_wasm_memory_reference(
|
||||
Address old_base, Address new_base, uint32_t old_size, uint32_t new_size,
|
||||
@ -565,6 +583,9 @@ class RelocInfo {
|
||||
void update_wasm_global_reference(
|
||||
Address old_base, Address new_base,
|
||||
ICacheFlushMode icache_flush_mode = FLUSH_ICACHE_IF_NEEDED);
|
||||
void update_wasm_function_table_size_reference(
|
||||
uint32_t old_base, uint32_t new_base,
|
||||
ICacheFlushMode icache_flush_mode = FLUSH_ICACHE_IF_NEEDED);
|
||||
void set_target_address(
|
||||
Address target,
|
||||
WriteBarrierMode write_barrier_mode = UPDATE_WRITE_BARRIER,
|
||||
@ -673,8 +694,7 @@ class RelocInfo {
|
||||
private:
|
||||
void unchecked_update_wasm_memory_reference(Address address,
|
||||
ICacheFlushMode flush_mode);
|
||||
void unchecked_update_wasm_memory_size(uint32_t size,
|
||||
ICacheFlushMode flush_mode);
|
||||
void unchecked_update_wasm_size(uint32_t size, ICacheFlushMode flush_mode);
|
||||
|
||||
Isolate* isolate_;
|
||||
// On ARM, note that pc_ is the address of the constant pool entry
|
||||
|
@ -1990,9 +1990,7 @@ void CodeGenerator::AssembleMove(InstructionOperand* source,
|
||||
destination->IsRegister() ? g.ToRegister(destination) : kScratchReg;
|
||||
switch (src.type()) {
|
||||
case Constant::kInt32:
|
||||
if (src.rmode() == RelocInfo::WASM_MEMORY_REFERENCE ||
|
||||
src.rmode() == RelocInfo::WASM_GLOBAL_REFERENCE ||
|
||||
src.rmode() == RelocInfo::WASM_MEMORY_SIZE_REFERENCE) {
|
||||
if (RelocInfo::IsWasmReference(src.rmode())) {
|
||||
__ mov(dst, Operand(src.ToInt32(), src.rmode()));
|
||||
} else {
|
||||
__ mov(dst, Operand(src.ToInt32()));
|
||||
|
@ -209,17 +209,16 @@ class Arm64OperandConverter final : public InstructionOperandConverter {
|
||||
Constant constant = ToConstant(operand);
|
||||
switch (constant.type()) {
|
||||
case Constant::kInt32:
|
||||
if (constant.rmode() == RelocInfo::WASM_MEMORY_SIZE_REFERENCE) {
|
||||
if (RelocInfo::IsWasmSizeReference(constant.rmode())) {
|
||||
return Operand(constant.ToInt32(), constant.rmode());
|
||||
} else {
|
||||
return Operand(constant.ToInt32());
|
||||
}
|
||||
case Constant::kInt64:
|
||||
if (constant.rmode() == RelocInfo::WASM_MEMORY_REFERENCE ||
|
||||
constant.rmode() == RelocInfo::WASM_GLOBAL_REFERENCE) {
|
||||
if (RelocInfo::IsWasmPtrReference(constant.rmode())) {
|
||||
return Operand(constant.ToInt64(), constant.rmode());
|
||||
} else {
|
||||
DCHECK(constant.rmode() != RelocInfo::WASM_MEMORY_SIZE_REFERENCE);
|
||||
DCHECK(!RelocInfo::IsWasmSizeReference(constant.rmode()));
|
||||
return Operand(constant.ToInt64());
|
||||
}
|
||||
case Constant::kFloat32:
|
||||
|
@ -66,9 +66,7 @@ class IA32OperandConverter : public InstructionOperandConverter {
|
||||
Immediate ToImmediate(InstructionOperand* operand) {
|
||||
Constant constant = ToConstant(operand);
|
||||
if (constant.type() == Constant::kInt32 &&
|
||||
(constant.rmode() == RelocInfo::WASM_MEMORY_REFERENCE ||
|
||||
constant.rmode() == RelocInfo::WASM_GLOBAL_REFERENCE ||
|
||||
constant.rmode() == RelocInfo::WASM_MEMORY_SIZE_REFERENCE)) {
|
||||
RelocInfo::IsWasmReference(constant.rmode())) {
|
||||
return Immediate(reinterpret_cast<Address>(constant.ToInt32()),
|
||||
constant.rmode());
|
||||
}
|
||||
|
@ -2084,9 +2084,7 @@ void CodeGenerator::AssembleMove(InstructionOperand* source,
|
||||
destination->IsRegister() ? g.ToRegister(destination) : kScratchReg;
|
||||
switch (src.type()) {
|
||||
case Constant::kInt32:
|
||||
if (src.rmode() == RelocInfo::WASM_MEMORY_REFERENCE ||
|
||||
src.rmode() == RelocInfo::WASM_GLOBAL_REFERENCE ||
|
||||
src.rmode() == RelocInfo::WASM_MEMORY_SIZE_REFERENCE) {
|
||||
if (RelocInfo::IsWasmReference(src.rmode())) {
|
||||
__ li(dst, Operand(src.ToInt32(), src.rmode()));
|
||||
} else {
|
||||
__ li(dst, Operand(src.ToInt32()));
|
||||
|
@ -2405,7 +2405,7 @@ void CodeGenerator::AssembleMove(InstructionOperand* source,
|
||||
destination->IsRegister() ? g.ToRegister(destination) : kScratchReg;
|
||||
switch (src.type()) {
|
||||
case Constant::kInt32:
|
||||
if (src.rmode() == RelocInfo::WASM_MEMORY_SIZE_REFERENCE) {
|
||||
if (RelocInfo::IsWasmSizeReference(src.rmode())) {
|
||||
__ li(dst, Operand(src.ToInt32(), src.rmode()));
|
||||
} else {
|
||||
__ li(dst, Operand(src.ToInt32()));
|
||||
@ -2415,11 +2415,10 @@ void CodeGenerator::AssembleMove(InstructionOperand* source,
|
||||
__ li(dst, isolate()->factory()->NewNumber(src.ToFloat32(), TENURED));
|
||||
break;
|
||||
case Constant::kInt64:
|
||||
if (src.rmode() == RelocInfo::WASM_MEMORY_REFERENCE ||
|
||||
src.rmode() == RelocInfo::WASM_GLOBAL_REFERENCE) {
|
||||
if (RelocInfo::IsWasmPtrReference(src.rmode())) {
|
||||
__ li(dst, Operand(src.ToInt64(), src.rmode()));
|
||||
} else {
|
||||
DCHECK(src.rmode() != RelocInfo::WASM_MEMORY_SIZE_REFERENCE);
|
||||
DCHECK(!RelocInfo::IsWasmSizeReference(src.rmode()));
|
||||
__ li(dst, Operand(src.ToInt64()));
|
||||
}
|
||||
break;
|
||||
|
@ -348,6 +348,7 @@ WasmGraphBuilder::WasmGraphBuilder(
|
||||
: zone_(zone),
|
||||
jsgraph_(jsgraph),
|
||||
module_(module_env),
|
||||
signature_tables_(zone),
|
||||
function_tables_(zone),
|
||||
function_table_sizes_(zone),
|
||||
cur_buffer_(def_buffer_),
|
||||
@ -2306,6 +2307,7 @@ Node* WasmGraphBuilder::CallIndirect(uint32_t sig_index, Node** args,
|
||||
Node* in_bounds = graph()->NewNode(machine->Uint32LessThan(), key, size);
|
||||
trap_->AddTrapIfFalse(wasm::kTrapFuncInvalid, in_bounds, position);
|
||||
Node* table = function_tables_[table_index];
|
||||
Node* signatures = signature_tables_[table_index];
|
||||
|
||||
// Load signature from the table and check.
|
||||
// The table is a FixedArray; signatures are encoded as SMIs.
|
||||
@ -2314,7 +2316,7 @@ Node* WasmGraphBuilder::CallIndirect(uint32_t sig_index, Node** args,
|
||||
const int fixed_offset = access.header_size - access.tag();
|
||||
{
|
||||
Node* load_sig = graph()->NewNode(
|
||||
machine->Load(MachineType::AnyTagged()), table,
|
||||
machine->Load(MachineType::AnyTagged()), signatures,
|
||||
graph()->NewNode(machine->Int32Add(),
|
||||
graph()->NewNode(machine->Word32Shl(), key,
|
||||
Int32Constant(kPointerSizeLog2)),
|
||||
@ -2329,14 +2331,12 @@ Node* WasmGraphBuilder::CallIndirect(uint32_t sig_index, Node** args,
|
||||
}
|
||||
|
||||
// Load code object from the table.
|
||||
uint32_t table_size = module_->module->function_tables[table_index].min_size;
|
||||
uint32_t offset = fixed_offset + kPointerSize * table_size;
|
||||
Node* load_code = graph()->NewNode(
|
||||
machine->Load(MachineType::AnyTagged()), table,
|
||||
graph()->NewNode(machine->Int32Add(),
|
||||
graph()->NewNode(machine->Word32Shl(), key,
|
||||
Int32Constant(kPointerSizeLog2)),
|
||||
Uint32Constant(offset)),
|
||||
Uint32Constant(fixed_offset)),
|
||||
*effect_, *control_);
|
||||
|
||||
args[0] = load_code;
|
||||
@ -2968,12 +2968,18 @@ Node* WasmGraphBuilder::MemSize(uint32_t offset) {
|
||||
|
||||
void WasmGraphBuilder::EnsureFunctionTableNodes() {
|
||||
if (function_tables_.size() > 0) return;
|
||||
for (size_t i = 0; i < module_->instance->function_tables.size(); ++i) {
|
||||
auto handle = module_->instance->function_tables[i];
|
||||
DCHECK(!handle.is_null());
|
||||
function_tables_.push_back(HeapConstant(handle));
|
||||
size_t tables_size = module_->instance->function_tables.size();
|
||||
DCHECK(tables_size == module_->instance->signature_tables.size());
|
||||
for (size_t i = 0; i < tables_size; ++i) {
|
||||
auto function_handle = module_->instance->function_tables[i];
|
||||
auto signature_handle = module_->instance->signature_tables[i];
|
||||
DCHECK(!function_handle.is_null() && !signature_handle.is_null());
|
||||
function_tables_.push_back(HeapConstant(function_handle));
|
||||
signature_tables_.push_back(HeapConstant(signature_handle));
|
||||
uint32_t table_size = module_->module->function_tables[i].min_size;
|
||||
function_table_sizes_.push_back(Uint32Constant(table_size));
|
||||
function_table_sizes_.push_back(jsgraph()->RelocatableInt32Constant(
|
||||
static_cast<uint32_t>(table_size),
|
||||
RelocInfo::WASM_FUNCTION_TABLE_SIZE_REFERENCE));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -238,6 +238,7 @@ class WasmGraphBuilder {
|
||||
wasm::ModuleEnv* module_ = nullptr;
|
||||
Node* mem_buffer_ = nullptr;
|
||||
Node* mem_size_ = nullptr;
|
||||
NodeVector signature_tables_;
|
||||
NodeVector function_tables_;
|
||||
NodeVector function_table_sizes_;
|
||||
Node** control_ = nullptr;
|
||||
|
@ -43,9 +43,7 @@ class X64OperandConverter : public InstructionOperandConverter {
|
||||
DCHECK_EQ(0, bit_cast<int64_t>(constant.ToFloat64()));
|
||||
return Immediate(0);
|
||||
}
|
||||
if (constant.rmode() == RelocInfo::WASM_MEMORY_REFERENCE ||
|
||||
constant.rmode() == RelocInfo::WASM_MEMORY_SIZE_REFERENCE ||
|
||||
constant.rmode() == RelocInfo::WASM_GLOBAL_REFERENCE) {
|
||||
if (RelocInfo::IsWasmReference(constant.rmode())) {
|
||||
return Immediate(constant.ToInt32(), constant.rmode());
|
||||
}
|
||||
return Immediate(constant.ToInt32());
|
||||
@ -2636,8 +2634,7 @@ void CodeGenerator::AssembleMove(InstructionOperand* source,
|
||||
: kScratchRegister;
|
||||
switch (src.type()) {
|
||||
case Constant::kInt32: {
|
||||
if (src.rmode() == RelocInfo::WASM_MEMORY_REFERENCE ||
|
||||
src.rmode() == RelocInfo::WASM_GLOBAL_REFERENCE) {
|
||||
if (RelocInfo::IsWasmPtrReference(src.rmode())) {
|
||||
__ movq(dst, src.ToInt64(), src.rmode());
|
||||
} else {
|
||||
// TODO(dcarney): don't need scratch in this case.
|
||||
@ -2645,7 +2642,7 @@ void CodeGenerator::AssembleMove(InstructionOperand* source,
|
||||
if (value == 0) {
|
||||
__ xorl(dst, dst);
|
||||
} else {
|
||||
if (src.rmode() == RelocInfo::WASM_MEMORY_SIZE_REFERENCE) {
|
||||
if (RelocInfo::IsWasmSizeReference(src.rmode())) {
|
||||
__ movl(dst, Immediate(value, src.rmode()));
|
||||
} else {
|
||||
__ movl(dst, Immediate(value));
|
||||
@ -2655,11 +2652,10 @@ void CodeGenerator::AssembleMove(InstructionOperand* source,
|
||||
break;
|
||||
}
|
||||
case Constant::kInt64:
|
||||
if (src.rmode() == RelocInfo::WASM_MEMORY_REFERENCE ||
|
||||
src.rmode() == RelocInfo::WASM_GLOBAL_REFERENCE) {
|
||||
if (RelocInfo::IsWasmPtrReference(src.rmode())) {
|
||||
__ movq(dst, src.ToInt64(), src.rmode());
|
||||
} else {
|
||||
DCHECK(src.rmode() != RelocInfo::WASM_MEMORY_SIZE_REFERENCE);
|
||||
DCHECK(!RelocInfo::IsWasmSizeReference(src.rmode()));
|
||||
__ Set(dst, src.ToInt64());
|
||||
}
|
||||
break;
|
||||
|
@ -201,13 +201,18 @@ uint32_t RelocInfo::wasm_memory_size_reference() {
|
||||
return Memory::uint32_at(pc_);
|
||||
}
|
||||
|
||||
uint32_t RelocInfo::wasm_function_table_size_reference() {
|
||||
DCHECK(IsWasmFunctionTableSizeReference(rmode_));
|
||||
return Memory::uint32_at(pc_);
|
||||
}
|
||||
|
||||
void RelocInfo::unchecked_update_wasm_memory_reference(
|
||||
Address address, ICacheFlushMode flush_mode) {
|
||||
Memory::Address_at(pc_) = address;
|
||||
}
|
||||
|
||||
void RelocInfo::unchecked_update_wasm_memory_size(uint32_t size,
|
||||
ICacheFlushMode flush_mode) {
|
||||
void RelocInfo::unchecked_update_wasm_size(uint32_t size,
|
||||
ICacheFlushMode flush_mode) {
|
||||
Memory::uint32_at(pc_) = size;
|
||||
}
|
||||
|
||||
|
@ -204,13 +204,18 @@ uint32_t RelocInfo::wasm_memory_size_reference() {
|
||||
return reinterpret_cast<uint32_t>(Assembler::target_address_at(pc_, host_));
|
||||
}
|
||||
|
||||
uint32_t RelocInfo::wasm_function_table_size_reference() {
|
||||
DCHECK(IsWasmFunctionTableSizeReference(rmode_));
|
||||
return reinterpret_cast<uint32_t>(Assembler::target_address_at(pc_, host_));
|
||||
}
|
||||
|
||||
void RelocInfo::unchecked_update_wasm_memory_reference(
|
||||
Address address, ICacheFlushMode flush_mode) {
|
||||
Assembler::set_target_address_at(isolate_, pc_, host_, address, flush_mode);
|
||||
}
|
||||
|
||||
void RelocInfo::unchecked_update_wasm_memory_size(uint32_t size,
|
||||
ICacheFlushMode flush_mode) {
|
||||
void RelocInfo::unchecked_update_wasm_size(uint32_t size,
|
||||
ICacheFlushMode flush_mode) {
|
||||
Assembler::set_target_address_at(isolate_, pc_, host_,
|
||||
reinterpret_cast<Address>(size), flush_mode);
|
||||
}
|
||||
|
@ -183,13 +183,19 @@ uint32_t RelocInfo::wasm_memory_size_reference() {
|
||||
reinterpret_cast<intptr_t>((Assembler::target_address_at(pc_, host_))));
|
||||
}
|
||||
|
||||
uint32_t RelocInfo::wasm_function_table_size_reference() {
|
||||
DCHECK(IsWasmFunctionTableSizeReference(rmode_));
|
||||
return static_cast<uint32_t>(
|
||||
reinterpret_cast<intptr_t>((Assembler::target_address_at(pc_, host_))));
|
||||
}
|
||||
|
||||
void RelocInfo::unchecked_update_wasm_memory_reference(
|
||||
Address address, ICacheFlushMode flush_mode) {
|
||||
Assembler::set_target_address_at(isolate_, pc_, host_, address, flush_mode);
|
||||
}
|
||||
|
||||
void RelocInfo::unchecked_update_wasm_memory_size(uint32_t size,
|
||||
ICacheFlushMode flush_mode) {
|
||||
void RelocInfo::unchecked_update_wasm_size(uint32_t size,
|
||||
ICacheFlushMode flush_mode) {
|
||||
Assembler::set_target_address_at(isolate_, pc_, host_,
|
||||
reinterpret_cast<Address>(size), flush_mode);
|
||||
}
|
||||
|
@ -849,9 +849,13 @@ MaybeHandle<WasmCompiledModule> WasmModule::CompileFunctions(
|
||||
int function_table_count = static_cast<int>(function_tables.size());
|
||||
Handle<FixedArray> function_tables =
|
||||
factory->NewFixedArray(function_table_count, TENURED);
|
||||
Handle<FixedArray> signature_tables =
|
||||
factory->NewFixedArray(function_table_count, TENURED);
|
||||
for (int i = 0; i < function_table_count; ++i) {
|
||||
temp_instance.function_tables[i] = factory->NewFixedArray(0, TENURED);
|
||||
temp_instance.function_tables[i] = factory->NewFixedArray(1, TENURED);
|
||||
temp_instance.signature_tables[i] = factory->NewFixedArray(1, TENURED);
|
||||
function_tables->set(i, *temp_instance.function_tables[i]);
|
||||
signature_tables->set(i, *temp_instance.signature_tables[i]);
|
||||
}
|
||||
|
||||
HistogramTimerScope wasm_compile_module_time_scope(
|
||||
@ -954,6 +958,7 @@ MaybeHandle<WasmCompiledModule> WasmModule::CompileFunctions(
|
||||
ret->set_max_mem_pages(max_mem_pages);
|
||||
if (function_table_count > 0) {
|
||||
ret->set_function_tables(function_tables);
|
||||
ret->set_signature_tables(signature_tables);
|
||||
ret->set_empty_function_tables(function_tables);
|
||||
}
|
||||
|
||||
@ -1042,11 +1047,13 @@ static void UpdateDispatchTablesInternal(Isolate* isolate,
|
||||
Handle<FixedArray> dispatch_tables,
|
||||
int index, WasmFunction* function,
|
||||
Handle<Code> code) {
|
||||
DCHECK_EQ(0, dispatch_tables->length() % 3);
|
||||
for (int i = 0; i < dispatch_tables->length(); i += 3) {
|
||||
DCHECK_EQ(0, dispatch_tables->length() % 4);
|
||||
for (int i = 0; i < dispatch_tables->length(); i += 4) {
|
||||
int table_index = Smi::cast(dispatch_tables->get(i + 1))->value();
|
||||
Handle<FixedArray> dispatch_table(
|
||||
Handle<FixedArray> function_table(
|
||||
FixedArray::cast(dispatch_tables->get(i + 2)), isolate);
|
||||
Handle<FixedArray> signature_table(
|
||||
FixedArray::cast(dispatch_tables->get(i + 3)), isolate);
|
||||
if (function) {
|
||||
// TODO(titzer): the signature might need to be copied to avoid
|
||||
// a dangling pointer in the signature map.
|
||||
@ -1055,12 +1062,12 @@ static void UpdateDispatchTablesInternal(Isolate* isolate,
|
||||
int sig_index = static_cast<int>(
|
||||
instance->module()->function_tables[table_index].map.FindOrInsert(
|
||||
function->sig));
|
||||
dispatch_table->set(index, Smi::FromInt(sig_index));
|
||||
dispatch_table->set(index + (dispatch_table->length() / 2), *code);
|
||||
signature_table->set(index, Smi::FromInt(sig_index));
|
||||
function_table->set(index, *code);
|
||||
} else {
|
||||
Code* code = nullptr;
|
||||
dispatch_table->set(index, Smi::FromInt(-1));
|
||||
dispatch_table->set(index + (dispatch_table->length() / 2), code);
|
||||
signature_table->set(index, Smi::FromInt(-1));
|
||||
function_table->set(index, code);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1207,9 +1214,9 @@ class WasmInstanceBuilder {
|
||||
static_cast<int>(module_->function_tables.size());
|
||||
table_instances_.reserve(module_->function_tables.size());
|
||||
for (int index = 0; index < function_table_count; ++index) {
|
||||
table_instances_.push_back({Handle<WasmTableObject>::null(),
|
||||
Handle<FixedArray>::null(),
|
||||
Handle<FixedArray>::null()});
|
||||
table_instances_.push_back(
|
||||
{Handle<WasmTableObject>::null(), Handle<FixedArray>::null(),
|
||||
Handle<FixedArray>::null(), Handle<FixedArray>::null()});
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
@ -1415,7 +1422,8 @@ class WasmInstanceBuilder {
|
||||
struct TableInstance {
|
||||
Handle<WasmTableObject> table_object; // WebAssembly.Table instance
|
||||
Handle<FixedArray> js_wrappers; // JSFunctions exported
|
||||
Handle<FixedArray> dispatch_table; // internal (code, sig) pairs
|
||||
Handle<FixedArray> function_table; // internal code array
|
||||
Handle<FixedArray> signature_table; // internal sig array
|
||||
};
|
||||
|
||||
Isolate* isolate_;
|
||||
@ -1620,12 +1628,14 @@ class WasmInstanceBuilder {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Allocate a new dispatch table.
|
||||
table_instance.dispatch_table =
|
||||
isolate_->factory()->NewFixedArray(table_size * 2);
|
||||
for (int i = 0; i < table_size * 2; ++i) {
|
||||
table_instance.dispatch_table->set(i,
|
||||
Smi::FromInt(kInvalidSigIndex));
|
||||
// Allocate a new dispatch table and signature table.
|
||||
table_instance.function_table =
|
||||
isolate_->factory()->NewFixedArray(table_size);
|
||||
table_instance.signature_table =
|
||||
isolate_->factory()->NewFixedArray(table_size);
|
||||
for (int i = 0; i < table_size; ++i) {
|
||||
table_instance.signature_table->set(i,
|
||||
Smi::FromInt(kInvalidSigIndex));
|
||||
}
|
||||
// Initialize the dispatch table with the (foreign) JS functions
|
||||
// that are already in the table.
|
||||
@ -1640,9 +1650,8 @@ class WasmInstanceBuilder {
|
||||
return -1;
|
||||
}
|
||||
int sig_index = table.map.FindOrInsert(function->sig);
|
||||
table_instance.dispatch_table->set(i, Smi::FromInt(sig_index));
|
||||
table_instance.dispatch_table->set(i + table_size,
|
||||
*UnwrapImportWrapper(val));
|
||||
table_instance.signature_table->set(i, Smi::FromInt(sig_index));
|
||||
table_instance.function_table->set(i, *UnwrapImportWrapper(val));
|
||||
}
|
||||
|
||||
num_imported_tables++;
|
||||
@ -1907,28 +1916,37 @@ class WasmInstanceBuilder {
|
||||
Handle<WasmInstanceObject> instance) {
|
||||
Handle<FixedArray> old_function_tables =
|
||||
compiled_module_->function_tables();
|
||||
Handle<FixedArray> old_signature_tables =
|
||||
compiled_module_->signature_tables();
|
||||
int function_table_count =
|
||||
static_cast<int>(module_->function_tables.size());
|
||||
Handle<FixedArray> new_function_tables =
|
||||
isolate_->factory()->NewFixedArray(function_table_count);
|
||||
Handle<FixedArray> new_signature_tables =
|
||||
isolate_->factory()->NewFixedArray(function_table_count);
|
||||
for (int index = 0; index < function_table_count; ++index) {
|
||||
WasmIndirectFunctionTable& table = module_->function_tables[index];
|
||||
TableInstance& table_instance = table_instances_[index];
|
||||
int table_size = static_cast<int>(table.min_size);
|
||||
|
||||
if (table_instance.dispatch_table.is_null()) {
|
||||
if (table_instance.function_table.is_null()) {
|
||||
// Create a new dispatch table if necessary.
|
||||
table_instance.dispatch_table =
|
||||
isolate_->factory()->NewFixedArray(table_size * 2);
|
||||
table_instance.function_table =
|
||||
isolate_->factory()->NewFixedArray(table_size);
|
||||
table_instance.signature_table =
|
||||
isolate_->factory()->NewFixedArray(table_size);
|
||||
for (int i = 0; i < table_size; ++i) {
|
||||
// Fill the table with invalid signature indexes so that
|
||||
// uninitialized entries will always fail the signature check.
|
||||
table_instance.dispatch_table->set(i, Smi::FromInt(kInvalidSigIndex));
|
||||
table_instance.signature_table->set(i,
|
||||
Smi::FromInt(kInvalidSigIndex));
|
||||
}
|
||||
}
|
||||
|
||||
new_function_tables->set(static_cast<int>(index),
|
||||
*table_instance.dispatch_table);
|
||||
*table_instance.function_table);
|
||||
new_signature_tables->set(static_cast<int>(index),
|
||||
*table_instance.signature_table);
|
||||
|
||||
Handle<FixedArray> all_dispatch_tables;
|
||||
if (!table_instance.table_object.is_null()) {
|
||||
@ -1936,7 +1954,7 @@ class WasmInstanceBuilder {
|
||||
all_dispatch_tables = WasmTableObject::AddDispatchTable(
|
||||
isolate_, table_instance.table_object,
|
||||
Handle<WasmInstanceObject>::null(), index,
|
||||
Handle<FixedArray>::null());
|
||||
Handle<FixedArray>::null(), Handle<FixedArray>::null());
|
||||
}
|
||||
|
||||
// TODO(titzer): this does redundant work if there are multiple tables,
|
||||
@ -1955,9 +1973,9 @@ class WasmInstanceBuilder {
|
||||
int table_index = static_cast<int>(i + base);
|
||||
int32_t sig_index = table.map.Find(function->sig);
|
||||
DCHECK_GE(sig_index, 0);
|
||||
table_instance.dispatch_table->set(table_index,
|
||||
Smi::FromInt(sig_index));
|
||||
table_instance.dispatch_table->set(table_index + table_size,
|
||||
table_instance.signature_table->set(table_index,
|
||||
Smi::FromInt(sig_index));
|
||||
table_instance.function_table->set(table_index,
|
||||
code_table->get(func_index));
|
||||
|
||||
if (!all_dispatch_tables.is_null()) {
|
||||
@ -2008,7 +2026,7 @@ class WasmInstanceBuilder {
|
||||
// Add the new dispatch table to the WebAssembly.Table object.
|
||||
all_dispatch_tables = WasmTableObject::AddDispatchTable(
|
||||
isolate_, table_instance.table_object, instance, index,
|
||||
table_instance.dispatch_table);
|
||||
table_instance.function_table, table_instance.signature_table);
|
||||
}
|
||||
}
|
||||
// Patch all code that has references to the old indirect tables.
|
||||
@ -2019,9 +2037,13 @@ class WasmInstanceBuilder {
|
||||
ReplaceReferenceInCode(
|
||||
code, Handle<Object>(old_function_tables->get(j), isolate_),
|
||||
Handle<Object>(new_function_tables->get(j), isolate_));
|
||||
ReplaceReferenceInCode(
|
||||
code, Handle<Object>(old_signature_tables->get(j), isolate_),
|
||||
Handle<Object>(new_signature_tables->get(j), isolate_));
|
||||
}
|
||||
}
|
||||
compiled_module_->set_function_tables(new_function_tables);
|
||||
compiled_module_->set_signature_tables(new_signature_tables);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -234,6 +234,8 @@ struct WasmInstance {
|
||||
// -- Heap allocated --------------------------------------------------------
|
||||
Handle<Context> context; // JavaScript native context.
|
||||
std::vector<Handle<FixedArray>> function_tables; // indirect function tables.
|
||||
std::vector<Handle<FixedArray>>
|
||||
signature_tables; // indirect signature tables.
|
||||
std::vector<Handle<Code>> function_code; // code objects for each function.
|
||||
// -- raw memory ------------------------------------------------------------
|
||||
byte* mem_start = nullptr; // start of linear memory.
|
||||
@ -244,6 +246,7 @@ struct WasmInstance {
|
||||
explicit WasmInstance(const WasmModule* m)
|
||||
: module(m),
|
||||
function_tables(m->function_tables.size()),
|
||||
signature_tables(m->function_tables.size()),
|
||||
function_code(m->functions.size()) {}
|
||||
};
|
||||
|
||||
|
@ -148,22 +148,23 @@ DEFINE_OBJ_GETTER(WasmTableObject, dispatch_tables, kDispatchTables, FixedArray)
|
||||
Handle<FixedArray> WasmTableObject::AddDispatchTable(
|
||||
Isolate* isolate, Handle<WasmTableObject> table_obj,
|
||||
Handle<WasmInstanceObject> instance, int table_index,
|
||||
Handle<FixedArray> dispatch_table) {
|
||||
Handle<FixedArray> function_table, Handle<FixedArray> signature_table) {
|
||||
Handle<FixedArray> dispatch_tables(
|
||||
FixedArray::cast(table_obj->GetInternalField(kDispatchTables)), isolate);
|
||||
DCHECK_EQ(0, dispatch_tables->length() % 3);
|
||||
DCHECK_EQ(0, dispatch_tables->length() % 4);
|
||||
|
||||
if (instance.is_null()) return dispatch_tables;
|
||||
// TODO(titzer): use weak cells here to avoid leaking instances.
|
||||
|
||||
// Grow the dispatch table and add a new triple at the end.
|
||||
Handle<FixedArray> new_dispatch_tables =
|
||||
isolate->factory()->CopyFixedArrayAndGrow(dispatch_tables, 3);
|
||||
isolate->factory()->CopyFixedArrayAndGrow(dispatch_tables, 4);
|
||||
|
||||
new_dispatch_tables->set(dispatch_tables->length() + 0, *instance);
|
||||
new_dispatch_tables->set(dispatch_tables->length() + 1,
|
||||
Smi::FromInt(table_index));
|
||||
new_dispatch_tables->set(dispatch_tables->length() + 2, *dispatch_table);
|
||||
new_dispatch_tables->set(dispatch_tables->length() + 2, *function_table);
|
||||
new_dispatch_tables->set(dispatch_tables->length() + 3, *signature_table);
|
||||
|
||||
table_obj->SetInternalField(WasmTableObject::kDispatchTables,
|
||||
*new_dispatch_tables);
|
||||
|
@ -69,7 +69,7 @@ class WasmTableObject : public JSObject {
|
||||
static Handle<FixedArray> AddDispatchTable(
|
||||
Isolate* isolate, Handle<WasmTableObject> table,
|
||||
Handle<WasmInstanceObject> instance, int table_index,
|
||||
Handle<FixedArray> dispatch_table);
|
||||
Handle<FixedArray> function_table, Handle<FixedArray> signature_table);
|
||||
};
|
||||
|
||||
// Representation of a WebAssembly.Memory JavaScript-level object.
|
||||
@ -239,6 +239,7 @@ class WasmCompiledModule : public FixedArray {
|
||||
MACRO(WASM_OBJECT, WasmSharedModuleData, shared) \
|
||||
MACRO(OBJECT, FixedArray, code_table) \
|
||||
MACRO(OBJECT, FixedArray, function_tables) \
|
||||
MACRO(OBJECT, FixedArray, signature_tables) \
|
||||
MACRO(OBJECT, FixedArray, empty_function_tables) \
|
||||
MACRO(OBJECT, JSArrayBuffer, memory) \
|
||||
MACRO(SMALL_NUMBER, uint32_t, min_mem_pages) \
|
||||
|
@ -135,13 +135,18 @@ uint32_t RelocInfo::wasm_memory_size_reference() {
|
||||
return Memory::uint32_at(pc_);
|
||||
}
|
||||
|
||||
uint32_t RelocInfo::wasm_function_table_size_reference() {
|
||||
DCHECK(IsWasmFunctionTableSizeReference(rmode_));
|
||||
return Memory::uint32_at(pc_);
|
||||
}
|
||||
|
||||
void RelocInfo::unchecked_update_wasm_memory_reference(
|
||||
Address address, ICacheFlushMode flush_mode) {
|
||||
Memory::Address_at(pc_) = address;
|
||||
}
|
||||
|
||||
void RelocInfo::unchecked_update_wasm_memory_size(uint32_t size,
|
||||
ICacheFlushMode flush_mode) {
|
||||
void RelocInfo::unchecked_update_wasm_size(uint32_t size,
|
||||
ICacheFlushMode flush_mode) {
|
||||
Memory::uint32_at(pc_) = size;
|
||||
}
|
||||
|
||||
|
@ -40,6 +40,26 @@ static void UpdateMemoryReferences(Handle<Code> code, Address old_base,
|
||||
}
|
||||
}
|
||||
|
||||
static void UpdateFunctionTableSizeReferences(Handle<Code> code,
|
||||
uint32_t old_size,
|
||||
uint32_t new_size) {
|
||||
Isolate* isolate = CcTest::i_isolate();
|
||||
bool modified = false;
|
||||
int mode_mask =
|
||||
RelocInfo::ModeMask(RelocInfo::WASM_FUNCTION_TABLE_SIZE_REFERENCE);
|
||||
for (RelocIterator it(*code, mode_mask); !it.done(); it.next()) {
|
||||
RelocInfo::Mode mode = it.rinfo()->rmode();
|
||||
if (RelocInfo::IsWasmFunctionTableSizeReference(mode)) {
|
||||
it.rinfo()->update_wasm_function_table_size_reference(old_size, new_size);
|
||||
modified = true;
|
||||
}
|
||||
}
|
||||
if (modified) {
|
||||
Assembler::FlushICache(isolate, code->instruction_start(),
|
||||
code->instruction_size());
|
||||
}
|
||||
}
|
||||
|
||||
template <typename CType>
|
||||
static void RunLoadStoreRelocation(MachineType rep) {
|
||||
const int kNumElems = 2;
|
||||
@ -146,7 +166,7 @@ TEST(RunLoadStoreRelocationOffset) {
|
||||
RunLoadStoreRelocationOffset<double>(MachineType::Float64());
|
||||
}
|
||||
|
||||
TEST(Uint32LessThanRelocation) {
|
||||
TEST(Uint32LessThanMemoryRelocation) {
|
||||
RawMachineAssemblerTester<uint32_t> m;
|
||||
RawMachineLabel within_bounds, out_of_bounds;
|
||||
Node* index = m.Int32Constant(0x200);
|
||||
@ -168,3 +188,25 @@ TEST(Uint32LessThanRelocation) {
|
||||
// Check that after limit is increased, index is within bounds.
|
||||
CHECK_EQ(0xacedu, m.Call());
|
||||
}
|
||||
|
||||
TEST(Uint32LessThanFunctionTableRelocation) {
|
||||
RawMachineAssemblerTester<uint32_t> m;
|
||||
RawMachineLabel within_bounds, out_of_bounds;
|
||||
Node* index = m.Int32Constant(0x200);
|
||||
Node* limit = m.RelocatableInt32Constant(
|
||||
0x200, RelocInfo::WASM_FUNCTION_TABLE_SIZE_REFERENCE);
|
||||
Node* cond = m.AddNode(m.machine()->Uint32LessThan(), index, limit);
|
||||
m.Branch(cond, &within_bounds, &out_of_bounds);
|
||||
m.Bind(&within_bounds);
|
||||
m.Return(m.Int32Constant(0xaced));
|
||||
m.Bind(&out_of_bounds);
|
||||
m.Return(m.Int32Constant(0xdeadbeef));
|
||||
// Check that index is out of bounds with current size
|
||||
CHECK_EQ(0xdeadbeef, m.Call());
|
||||
m.GenerateCode();
|
||||
|
||||
Handle<Code> code = m.GetCode();
|
||||
UpdateFunctionTableSizeReferences(code, 0x200, 0x400);
|
||||
// Check that after limit is increased, index is within bounds.
|
||||
CHECK_EQ(0xaced, m.Call());
|
||||
}
|
||||
|
@ -247,7 +247,9 @@ class TestingModule : public ModuleEnv {
|
||||
}
|
||||
|
||||
instance->function_tables.push_back(
|
||||
isolate_->factory()->NewFixedArray(table_size * 2));
|
||||
isolate_->factory()->NewFixedArray(table_size));
|
||||
instance->signature_tables.push_back(
|
||||
isolate_->factory()->NewFixedArray(table_size));
|
||||
}
|
||||
|
||||
void PopulateIndirectFunctionTable() {
|
||||
@ -255,13 +257,13 @@ class TestingModule : public ModuleEnv {
|
||||
// Initialize the fixed arrays in instance->function_tables.
|
||||
for (uint32_t i = 0; i < instance->function_tables.size(); i++) {
|
||||
WasmIndirectFunctionTable& table = module_.function_tables[i];
|
||||
Handle<FixedArray> array = instance->function_tables[i];
|
||||
Handle<FixedArray> function_table = instance->function_tables[i];
|
||||
Handle<FixedArray> signature_table = instance->signature_tables[i];
|
||||
int table_size = static_cast<int>(table.values.size());
|
||||
for (int j = 0; j < table_size; j++) {
|
||||
WasmFunction& function = module_.functions[table.values[j]];
|
||||
array->set(j, Smi::FromInt(table.map.Find(function.sig)));
|
||||
array->set(j + table_size,
|
||||
*instance->function_code[function.func_index]);
|
||||
signature_table->set(j, Smi::FromInt(table.map.Find(function.sig)));
|
||||
function_table->set(j, *instance->function_code[function.func_index]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user