Commit c1d01aea authored by mtrofin's avatar mtrofin Committed by Commit bot

[wasm] Separate compilation from instantiation

Compilation of wasm functions happens before instantiation. Imports are linked afterwards, at instantiation time. Globals and memory are also
allocated and then tied in via relocation at instantiation time.

This paves the way for implementing Wasm.compile, a prerequisite to
offering the compiled code serialization feature.

Currently, the WasmModule::Compile method just returns a fixed array
containing the code objects. More appropriate modeling of the compiled module to come.

Opportunistically centralized the logic on how to update memory
references, size, and globals, since that logic is the exact same on each
architecture, except for the actual storing of values back in the
instruction stream.

BUG=v8:5072

Review-Url: https://codereview.chromium.org/2056633002
Cr-Commit-Position: refs/heads/master@{#37086}
parent 85fde59d
......@@ -254,42 +254,15 @@ Address RelocInfo::wasm_global_reference() {
return Assembler::target_address_at(pc_, host_);
}
void RelocInfo::update_wasm_memory_reference(
Address old_base, Address new_base, uint32_t old_size, uint32_t new_size,
ICacheFlushMode icache_flush_mode) {
DCHECK(IsWasmMemoryReference(rmode_) || IsWasmMemorySizeReference(rmode_));
if (IsWasmMemoryReference(rmode_)) {
Address updated_memory_reference;
DCHECK(old_base <= wasm_memory_reference() &&
wasm_memory_reference() < old_base + old_size);
updated_memory_reference = new_base + (wasm_memory_reference() - old_base);
DCHECK(new_base <= updated_memory_reference &&
updated_memory_reference < new_base + new_size);
Assembler::set_target_address_at(
isolate_, pc_, host_, updated_memory_reference, icache_flush_mode);
} else if (IsWasmMemorySizeReference(rmode_)) {
uint32_t updated_size_reference;
DCHECK(wasm_memory_size_reference() <= old_size);
updated_size_reference =
new_size + (wasm_memory_size_reference() - old_size);
DCHECK(updated_size_reference <= new_size);
Assembler::set_target_address_at(
isolate_, pc_, host_, reinterpret_cast<Address>(updated_size_reference),
icache_flush_mode);
} else {
UNREACHABLE();
}
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::update_wasm_global_reference(
Address old_base, Address new_base, ICacheFlushMode icache_flush_mode) {
DCHECK(IsWasmGlobalReference(rmode_));
Address updated_reference;
DCHECK(old_base <= wasm_global_reference());
updated_reference = new_base + (wasm_global_reference() - old_base);
DCHECK(new_base <= updated_reference);
Assembler::set_target_address_at(isolate_, pc_, host_, updated_reference,
icache_flush_mode);
void RelocInfo::unchecked_update_wasm_memory_size(uint32_t size,
ICacheFlushMode flush_mode) {
Assembler::set_target_address_at(isolate_, pc_, host_,
reinterpret_cast<Address>(size), flush_mode);
}
// -----------------------------------------------------------------------------
......
......@@ -194,41 +194,14 @@ Address RelocInfo::wasm_global_reference() {
return Memory::Address_at(Assembler::target_pointer_address_at(pc_));
}
void RelocInfo::update_wasm_memory_reference(
Address old_base, Address new_base, uint32_t old_size, uint32_t new_size,
ICacheFlushMode icache_flush_mode) {
DCHECK(IsWasmMemoryReference(rmode_) || IsWasmMemorySizeReference(rmode_));
if (IsWasmMemoryReference(rmode_) && old_base != new_base) {
Address updated_memory_reference;
DCHECK(old_base <= wasm_memory_reference() &&
wasm_memory_reference() < old_base + old_size);
updated_memory_reference = new_base + (wasm_memory_reference() - old_base);
DCHECK(new_base <= updated_memory_reference &&
updated_memory_reference < new_base + new_size);
Assembler::set_target_address_at(
isolate_, pc_, host_, updated_memory_reference, icache_flush_mode);
} else if (IsWasmMemorySizeReference(rmode_)) {
uint32_t updated_size_reference;
DCHECK(wasm_memory_size_reference() <= old_size);
updated_size_reference =
new_size + (wasm_memory_size_reference() - old_size);
DCHECK(updated_size_reference <= new_size);
Memory::uint32_at(Assembler::target_pointer_address_at(pc_)) =
updated_size_reference;
} else {
UNREACHABLE();
}
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::update_wasm_global_reference(
Address old_base, Address new_base, ICacheFlushMode icache_flush_mode) {
DCHECK(IsWasmGlobalReference(rmode_));
Address updated_reference;
DCHECK(old_base <= wasm_global_reference());
updated_reference = new_base + (wasm_global_reference() - old_base);
DCHECK(new_base <= updated_reference);
Assembler::set_target_address_at(isolate_, pc_, host_, updated_reference,
icache_flush_mode);
void RelocInfo::unchecked_update_wasm_memory_size(uint32_t size,
ICacheFlushMode flush_mode) {
Memory::uint32_at(Assembler::target_pointer_address_at(pc_)) = size;
}
Register GetAllocatableRegisterThatIsNotOneOf(Register reg1, Register reg2,
......
......@@ -372,6 +372,49 @@ const int kNonstatementPositionTag = 1;
const int kStatementPositionTag = 2;
const int kDeoptReasonTag = 3;
void RelocInfo::update_wasm_memory_reference(
Address old_base, Address new_base, uint32_t old_size, uint32_t new_size,
ICacheFlushMode icache_flush_mode) {
DCHECK(IsWasmMemoryReference(rmode_) || IsWasmMemorySizeReference(rmode_));
if (IsWasmMemoryReference(rmode_)) {
Address updated_reference;
DCHECK(old_size == 0 || Memory::IsAddressInRange(
old_base, wasm_memory_reference(), old_size));
updated_reference = new_base + (wasm_memory_reference() - old_base);
DCHECK(new_size == 0 ||
Memory::IsAddressInRange(new_base, updated_reference, new_size));
unchecked_update_wasm_memory_reference(updated_reference,
icache_flush_mode);
} else if (IsWasmMemorySizeReference(rmode_)) {
uint32_t updated_size_reference;
DCHECK(old_size == 0 || wasm_memory_size_reference() <= old_size);
updated_size_reference =
new_size + (wasm_memory_size_reference() - old_size);
DCHECK(updated_size_reference <= new_size);
unchecked_update_wasm_memory_size(updated_size_reference,
icache_flush_mode);
} else {
UNREACHABLE();
}
if (icache_flush_mode != SKIP_ICACHE_FLUSH) {
Assembler::FlushICache(isolate_, pc_, sizeof(int64_t));
}
}
void RelocInfo::update_wasm_global_reference(
Address old_base, Address new_base, ICacheFlushMode icache_flush_mode) {
DCHECK(IsWasmGlobalReference(rmode_));
Address updated_reference;
DCHECK(reinterpret_cast<uintptr_t>(old_base) <=
reinterpret_cast<uintptr_t>(wasm_global_reference()));
updated_reference = new_base + (wasm_global_reference() - old_base);
DCHECK(reinterpret_cast<uintptr_t>(new_base) <=
reinterpret_cast<uintptr_t>(updated_reference));
unchecked_update_wasm_memory_reference(updated_reference, icache_flush_mode);
if (icache_flush_mode != SKIP_ICACHE_FLUSH) {
Assembler::FlushICache(isolate_, pc_, sizeof(int32_t));
}
}
uint32_t RelocInfoWriter::WriteLongPCJump(uint32_t pc_delta) {
// Return if the pc_delta can fit in kSmallPCDeltaBits bits.
......
......@@ -449,8 +449,7 @@ class RelocInfo {
}
static inline bool IsRealRelocMode(Mode mode) {
return mode >= FIRST_REAL_RELOC_MODE &&
mode <= LAST_REAL_RELOC_MODE;
return mode >= FIRST_REAL_RELOC_MODE && mode <= LAST_REAL_RELOC_MODE;
}
static inline bool IsCodeTarget(Mode mode) {
return mode <= LAST_CODE_ENUM;
......@@ -572,36 +571,30 @@ class RelocInfo {
// this relocation applies to;
// can only be called if IsCodeTarget(rmode_) || IsRuntimeEntry(rmode_)
INLINE(Address target_address());
INLINE(void set_target_address(Address target,
WriteBarrierMode write_barrier_mode =
UPDATE_WRITE_BARRIER,
ICacheFlushMode icache_flush_mode =
FLUSH_ICACHE_IF_NEEDED));
INLINE(void set_target_address(
Address target,
WriteBarrierMode write_barrier_mode = UPDATE_WRITE_BARRIER,
ICacheFlushMode icache_flush_mode = FLUSH_ICACHE_IF_NEEDED));
INLINE(Object* target_object());
INLINE(Handle<Object> target_object_handle(Assembler* origin));
INLINE(void set_target_object(Object* target,
WriteBarrierMode write_barrier_mode =
UPDATE_WRITE_BARRIER,
ICacheFlushMode icache_flush_mode =
FLUSH_ICACHE_IF_NEEDED));
INLINE(void set_target_object(
Object* target,
WriteBarrierMode write_barrier_mode = UPDATE_WRITE_BARRIER,
ICacheFlushMode icache_flush_mode = FLUSH_ICACHE_IF_NEEDED));
INLINE(Address target_runtime_entry(Assembler* origin));
INLINE(void set_target_runtime_entry(Address target,
WriteBarrierMode write_barrier_mode =
UPDATE_WRITE_BARRIER,
ICacheFlushMode icache_flush_mode =
FLUSH_ICACHE_IF_NEEDED));
INLINE(void set_target_runtime_entry(
Address target,
WriteBarrierMode write_barrier_mode = UPDATE_WRITE_BARRIER,
ICacheFlushMode icache_flush_mode = FLUSH_ICACHE_IF_NEEDED));
INLINE(Cell* target_cell());
INLINE(Handle<Cell> target_cell_handle());
INLINE(void set_target_cell(Cell* cell,
WriteBarrierMode write_barrier_mode =
UPDATE_WRITE_BARRIER,
ICacheFlushMode icache_flush_mode =
FLUSH_ICACHE_IF_NEEDED));
INLINE(void set_target_cell(
Cell* cell, WriteBarrierMode write_barrier_mode = UPDATE_WRITE_BARRIER,
ICacheFlushMode icache_flush_mode = FLUSH_ICACHE_IF_NEEDED));
INLINE(Handle<Object> code_age_stub_handle(Assembler* origin));
INLINE(Code* code_age_stub());
INLINE(void set_code_age_stub(Code* stub,
ICacheFlushMode icache_flush_mode =
FLUSH_ICACHE_IF_NEEDED));
INLINE(void set_code_age_stub(
Code* stub, ICacheFlushMode icache_flush_mode = FLUSH_ICACHE_IF_NEEDED));
// Returns the address of the constant pool entry where the target address
// is held. This should only be called if IsInConstantPool returns true.
......@@ -682,6 +675,11 @@ class RelocInfo {
static const int kApplyMask; // Modes affected by apply. Depends on arch.
private:
void unchecked_update_wasm_memory_reference(Address address,
ICacheFlushMode flush_mode);
void unchecked_update_wasm_memory_size(uint32_t size,
ICacheFlushMode flush_mode);
Isolate* isolate_;
// On ARM, note that pc_ is the address of the constant pool entry
// to be relocated and not the address of the instruction
......
......@@ -201,44 +201,14 @@ uint32_t RelocInfo::wasm_memory_size_reference() {
return Memory::uint32_at(pc_);
}
void RelocInfo::update_wasm_memory_reference(
Address old_base, Address new_base, uint32_t old_size, uint32_t new_size,
ICacheFlushMode icache_flush_mode) {
DCHECK(IsWasmMemoryReference(rmode_) || IsWasmMemorySizeReference(rmode_));
if (IsWasmMemoryReference(rmode_)) {
Address updated_reference;
DCHECK(old_base <= wasm_memory_reference() &&
wasm_memory_reference() < old_base + old_size);
updated_reference = new_base + (wasm_memory_reference() - old_base);
DCHECK(new_base <= updated_reference &&
updated_reference < new_base + new_size);
Memory::Address_at(pc_) = updated_reference;
} else if (IsWasmMemorySizeReference(rmode_)) {
uint32_t updated_size_reference;
DCHECK(wasm_memory_size_reference() <= old_size);
updated_size_reference =
new_size + (wasm_memory_size_reference() - old_size);
DCHECK(updated_size_reference <= new_size);
Memory::uint32_at(pc_) = updated_size_reference;
} else {
UNREACHABLE();
}
if (icache_flush_mode != SKIP_ICACHE_FLUSH) {
Assembler::FlushICache(isolate_, pc_, sizeof(int32_t));
}
void RelocInfo::unchecked_update_wasm_memory_reference(
Address address, ICacheFlushMode flush_mode) {
Memory::Address_at(pc_) = address;
}
void RelocInfo::update_wasm_global_reference(
Address old_base, Address new_base, ICacheFlushMode icache_flush_mode) {
DCHECK(IsWasmGlobalReference(rmode_));
Address updated_reference;
DCHECK(old_base <= wasm_global_reference());
updated_reference = new_base + (wasm_global_reference() - old_base);
DCHECK(new_base <= updated_reference);
Memory::Address_at(pc_) = updated_reference;
if (icache_flush_mode != SKIP_ICACHE_FLUSH) {
Assembler::FlushICache(isolate_, pc_, sizeof(int32_t));
}
void RelocInfo::unchecked_update_wasm_memory_size(uint32_t size,
ICacheFlushMode flush_mode) {
Memory::uint32_at(pc_) = size;
}
// -----------------------------------------------------------------------------
......
......@@ -204,42 +204,15 @@ uint32_t RelocInfo::wasm_memory_size_reference() {
return reinterpret_cast<uint32_t>(Assembler::target_address_at(pc_, host_));
}
void RelocInfo::update_wasm_memory_reference(
Address old_base, Address new_base, uint32_t old_size, uint32_t new_size,
ICacheFlushMode icache_flush_mode) {
DCHECK(IsWasmMemoryReference(rmode_) || IsWasmMemorySizeReference(rmode_));
if (IsWasmMemoryReference(rmode_)) {
Address updated_memory_reference;
DCHECK(old_base <= wasm_memory_reference() &&
wasm_memory_reference() < old_base + old_size);
updated_memory_reference = new_base + (wasm_memory_reference() - old_base);
DCHECK(new_base <= updated_memory_reference &&
updated_memory_reference < new_base + new_size);
Assembler::set_target_address_at(
isolate_, pc_, host_, updated_memory_reference, icache_flush_mode);
} else if (IsWasmMemorySizeReference(rmode_)) {
uint32_t updated_size_reference;
DCHECK(wasm_memory_size_reference() <= old_size);
updated_size_reference =
new_size + (wasm_memory_size_reference() - old_size);
DCHECK(updated_size_reference <= new_size);
Assembler::set_target_address_at(
isolate_, pc_, host_, reinterpret_cast<Address>(updated_size_reference),
icache_flush_mode);
} else {
UNREACHABLE();
}
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::update_wasm_global_reference(
Address old_base, Address new_base, ICacheFlushMode icache_flush_mode) {
DCHECK(IsWasmGlobalReference(rmode_));
Address updated_global_reference;
DCHECK(old_base <= wasm_global_reference());
updated_global_reference = new_base + (wasm_global_reference() - old_base);
DCHECK(new_base <= updated_global_reference);
void RelocInfo::unchecked_update_wasm_memory_size(uint32_t size,
ICacheFlushMode flush_mode) {
Assembler::set_target_address_at(isolate_, pc_, host_,
updated_global_reference, icache_flush_mode);
reinterpret_cast<Address>(size), flush_mode);
}
// -----------------------------------------------------------------------------
......
......@@ -183,42 +183,15 @@ uint32_t RelocInfo::wasm_memory_size_reference() {
reinterpret_cast<intptr_t>((Assembler::target_address_at(pc_, host_))));
}
void RelocInfo::update_wasm_memory_reference(
Address old_base, Address new_base, uint32_t old_size, uint32_t new_size,
ICacheFlushMode icache_flush_mode) {
DCHECK(IsWasmMemoryReference(rmode_) || IsWasmMemorySizeReference(rmode_));
if (IsWasmMemoryReference(rmode_)) {
Address updated_memory_reference;
DCHECK(old_base <= wasm_memory_reference() &&
wasm_memory_reference() < old_base + old_size);
updated_memory_reference = new_base + (wasm_memory_reference() - old_base);
DCHECK(new_base <= updated_memory_reference &&
updated_memory_reference < new_base + new_size);
Assembler::set_target_address_at(
isolate_, pc_, host_, updated_memory_reference, icache_flush_mode);
} else if (IsWasmMemorySizeReference(rmode_)) {
uint32_t updated_size_reference;
DCHECK(wasm_memory_size_reference() <= old_size);
updated_size_reference =
new_size + (wasm_memory_size_reference() - old_size);
DCHECK(updated_size_reference <= new_size);
Assembler::set_target_address_at(
isolate_, pc_, host_, reinterpret_cast<Address>(updated_size_reference),
icache_flush_mode);
} else {
UNREACHABLE();
}
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::update_wasm_global_reference(
Address old_base, Address new_base, ICacheFlushMode icache_flush_mode) {
DCHECK(IsWasmGlobalReference(rmode_));
Address updated_global_reference;
DCHECK(old_base <= wasm_global_reference());
updated_global_reference = new_base + (wasm_global_reference() - old_base);
DCHECK(new_base <= updated_global_reference);
void RelocInfo::unchecked_update_wasm_memory_size(uint32_t size,
ICacheFlushMode flush_mode) {
Assembler::set_target_address_at(isolate_, pc_, host_,
updated_global_reference, icache_flush_mode);
reinterpret_cast<Address>(size), flush_mode);
}
// -----------------------------------------------------------------------------
......
......@@ -64,6 +64,13 @@ class Memory {
static Handle<Object>& Object_Handle_at(Address addr) {
return *reinterpret_cast<Handle<Object>*>(addr);
}
static bool IsAddressInRange(Address base, Address address, uint32_t size) {
uintptr_t numeric_base = reinterpret_cast<uintptr_t>(base);
uintptr_t numeric_address = reinterpret_cast<uintptr_t>(address);
return numeric_base <= numeric_address &&
numeric_address < numeric_base + size;
}
};
} // namespace internal
......
This diff is collapsed.
......@@ -212,6 +212,8 @@ struct WasmModule {
// Creates a new instantiation of the module in the given isolate.
MaybeHandle<JSObject> Instantiate(Isolate* isolate, Handle<JSReceiver> ffi,
Handle<JSArrayBuffer> memory) const;
Handle<FixedArray> CompileFunctions(Isolate* isolate) const;
};
// An instantiated WASM module, including memory, function table, etc.
......@@ -234,21 +236,21 @@ struct WasmModuleInstance {
explicit WasmModuleInstance(const WasmModule* m)
: module(m),
function_code(m->functions.size()),
import_code(m->import_table.size()),
mem_start(nullptr),
mem_size(0),
globals_start(nullptr) {}
};
// forward declaration.
class WasmLinker;
// Interface provided to the decoder/graph builder which contains only
// minimal information about the globals, functions, and function tables.
struct ModuleEnv {
const WasmModule* module;
WasmModuleInstance* instance;
WasmLinker* linker;
ModuleOrigin origin;
// TODO(mtrofin): remove this once we introduce WASM_DIRECT_CALL
// reloc infos.
std::vector<Handle<Code>> placeholders;
bool IsValidGlobal(uint32_t index) {
return module && index < module->globals.size();
......
......@@ -132,44 +132,14 @@ uint32_t RelocInfo::wasm_memory_size_reference() {
return Memory::uint32_at(pc_);
}
void RelocInfo::update_wasm_memory_reference(
Address old_base, Address new_base, uint32_t old_size, uint32_t new_size,
ICacheFlushMode icache_flush_mode) {
DCHECK(IsWasmMemoryReference(rmode_) || IsWasmMemorySizeReference(rmode_));
if (IsWasmMemoryReference(rmode_)) {
Address updated_reference;
DCHECK(old_base <= wasm_memory_reference() &&
wasm_memory_reference() < old_base + old_size);
updated_reference = new_base + (wasm_memory_reference() - old_base);
DCHECK(new_base <= updated_reference &&
updated_reference < new_base + new_size);
Memory::Address_at(pc_) = updated_reference;
} else if (IsWasmMemorySizeReference(rmode_)) {
uint32_t updated_size_reference;
DCHECK(wasm_memory_size_reference() <= old_size);
updated_size_reference =
new_size + (wasm_memory_size_reference() - old_size);
DCHECK(updated_size_reference <= new_size);
Memory::uint32_at(pc_) = updated_size_reference;
} else {
UNREACHABLE();
}
if (icache_flush_mode != SKIP_ICACHE_FLUSH) {
Assembler::FlushICache(isolate_, pc_, sizeof(int64_t));
}
void RelocInfo::unchecked_update_wasm_memory_reference(
Address address, ICacheFlushMode flush_mode) {
Memory::Address_at(pc_) = address;
}
void RelocInfo::update_wasm_global_reference(
Address old_base, Address new_base, ICacheFlushMode icache_flush_mode) {
DCHECK(IsWasmGlobalReference(rmode_));
Address updated_reference;
DCHECK(old_base <= wasm_global_reference());
updated_reference = new_base + (wasm_global_reference() - old_base);
DCHECK(new_base <= updated_reference);
Memory::Address_at(pc_) = updated_reference;
if (icache_flush_mode != SKIP_ICACHE_FLUSH) {
Assembler::FlushICache(isolate_, pc_, sizeof(int64_t));
}
void RelocInfo::unchecked_update_wasm_memory_size(uint32_t size,
ICacheFlushMode flush_mode) {
Memory::uint32_at(pc_) = size;
}
// -----------------------------------------------------------------------------
......@@ -617,12 +587,9 @@ void Assembler::immediate_arithmetic_op(byte subcode,
int size) {
EnsureSpace ensure_space(this);
emit_rex(dst, size);
if (is_int8(src.value_)) {
if (is_int8(src.value_) && RelocInfo::IsNone(src.rmode_)) {
emit(0x83);
emit_modrm(subcode, dst);
if (!RelocInfo::IsNone(src.rmode_)) {
RecordRelocInfo(src.rmode_);
}
emit(src.value_);
} else if (dst.is(rax)) {
emit(0x05 | (subcode << 3));
......
......@@ -84,7 +84,6 @@ class TestingModule : public ModuleEnv {
module_.globals_size = kMaxGlobalsSize;
instance->mem_start = nullptr;
instance->mem_size = 0;
linker = nullptr;
origin = kWasmOrigin;
memset(global_data, 0, sizeof(global_data));
}
......
......@@ -1156,7 +1156,6 @@ class TestModuleEnv : public ModuleEnv {
TestModuleEnv() {
instance = nullptr;
module = &mod;
linker = nullptr;
}
byte AddGlobal(MachineType mem_type) {
mod.globals.push_back({0, 0, mem_type, 0, false});
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment