[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:
gdeepti 2017-01-10 11:07:34 -08:00 committed by Commit bot
parent b1cfa6448c
commit 0c4b8ff44c
22 changed files with 225 additions and 94 deletions

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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;

View File

@ -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

View File

@ -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()));

View File

@ -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:

View File

@ -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());
}

View File

@ -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()));

View File

@ -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;

View File

@ -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));
}
}

View File

@ -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;

View File

@ -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;

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}
};

View File

@ -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()) {}
};

View File

@ -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);

View File

@ -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) \

View File

@ -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;
}

View File

@ -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());
}

View File

@ -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]);
}
}
}