Commit 943b5d02 authored by Junliang Yan's avatar Junliang Yan Committed by Commit Bot

PPC/s390: [assembler] Allow to pass custom buffer implementations

Port 1a3aab51

Original Commit Message:

    When generating an Assembler, you currently have two choices: Either
    let the Assembler allocate a growable internal buffer, which is owned
    by the Assembler. Or provide an externally allocated buffer, which
    cannot grow.
    This CL changes this interface to allow providing any implementation of
    a buffer. The provided buffer can be a view to an externally owned
    buffer, which still can grow.
    This will be used to split WebAssembly compilation and code submission.
    The buffer needs to be able to grow, but cannot be owned by the
    Assembler because it has to survive until the code is submitted.

R=clemensh@chromium.org, joransiu@ca.ibm.com, michael_dawson@ca.ibm.com
BUG=
LOG=N

Change-Id: Id9383db813b13ea1d9eab485724aeb55b08cdfee
Reviewed-on: https://chromium-review.googlesource.com/c/1416310Reviewed-by: 's avatarJoran Siu <joransiu@ca.ibm.com>
Commit-Queue: Junliang Yan <jyan@ca.ibm.com>
Cr-Commit-Position: refs/heads/master@{#58865}
parent 9378c6d1
...@@ -376,7 +376,7 @@ int Assembler::GetConstantPoolOffset(Address pc, ...@@ -376,7 +376,7 @@ int Assembler::GetConstantPoolOffset(Address pc,
void Assembler::PatchConstantPoolAccessInstruction( void Assembler::PatchConstantPoolAccessInstruction(
int pc_offset, int offset, ConstantPoolEntry::Access access, int pc_offset, int offset, ConstantPoolEntry::Access access,
ConstantPoolEntry::Type type) { ConstantPoolEntry::Type type) {
Address pc = reinterpret_cast<Address>(buffer_) + pc_offset; Address pc = reinterpret_cast<Address>(buffer_start_) + pc_offset;
bool overflowed = (access == ConstantPoolEntry::OVERFLOWED); bool overflowed = (access == ConstantPoolEntry::OVERFLOWED);
CHECK(overflowed != is_int16(offset)); CHECK(overflowed != is_int16(offset));
#ifdef DEBUG #ifdef DEBUG
......
...@@ -217,7 +217,7 @@ void Assembler::AllocateAndInstallRequestedHeapObjects(Isolate* isolate) { ...@@ -217,7 +217,7 @@ void Assembler::AllocateAndInstallRequestedHeapObjects(Isolate* isolate) {
break; break;
} }
} }
Address pc = reinterpret_cast<Address>(buffer_) + request.offset(); Address pc = reinterpret_cast<Address>(buffer_start_) + request.offset();
Address constant_pool = kNullAddress; Address constant_pool = kNullAddress;
set_target_address_at(pc, constant_pool, object.address(), set_target_address_at(pc, constant_pool, object.address(),
SKIP_ICACHE_FLUSH); SKIP_ICACHE_FLUSH);
...@@ -227,11 +227,11 @@ void Assembler::AllocateAndInstallRequestedHeapObjects(Isolate* isolate) { ...@@ -227,11 +227,11 @@ void Assembler::AllocateAndInstallRequestedHeapObjects(Isolate* isolate) {
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// Specific instructions, constants, and masks. // Specific instructions, constants, and masks.
Assembler::Assembler(const AssemblerOptions& options, void* buffer, Assembler::Assembler(const AssemblerOptions& options,
int buffer_size) std::unique_ptr<AssemblerBuffer> buffer)
: AssemblerBase(options, buffer, buffer_size), : AssemblerBase(options, std::move(buffer)),
constant_pool_builder_(kLoadPtrMaxReachBits, kLoadDoubleMaxReachBits) { constant_pool_builder_(kLoadPtrMaxReachBits, kLoadDoubleMaxReachBits) {
reloc_info_writer.Reposition(buffer_ + buffer_size_, pc_); reloc_info_writer.Reposition(buffer_start_ + buffer_->size(), pc_);
no_trampoline_pool_before_ = 0; no_trampoline_pool_before_ = 0;
trampoline_pool_blocked_nesting_ = 0; trampoline_pool_blocked_nesting_ = 0;
...@@ -256,10 +256,11 @@ void Assembler::GetCode(Isolate* isolate, CodeDesc* desc) { ...@@ -256,10 +256,11 @@ void Assembler::GetCode(Isolate* isolate, CodeDesc* desc) {
AllocateAndInstallRequestedHeapObjects(isolate); AllocateAndInstallRequestedHeapObjects(isolate);
// Set up code descriptor. // Set up code descriptor.
desc->buffer = buffer_; desc->buffer = buffer_start_;
desc->buffer_size = buffer_size_; desc->buffer_size = buffer_->size();
desc->instr_size = pc_offset(); desc->instr_size = pc_offset();
desc->reloc_size = (buffer_ + buffer_size_) - reloc_info_writer.pos(); desc->reloc_size =
(buffer_start_ + desc->buffer_size) - reloc_info_writer.pos();
desc->constant_pool_size = constant_pool_size; desc->constant_pool_size = constant_pool_size;
desc->origin = this; desc->origin = this;
desc->unwinding_info_size = 0; desc->unwinding_info_size = 0;
...@@ -489,7 +490,8 @@ void Assembler::target_at_put(int pos, int target_pos, bool* is_branch) { ...@@ -489,7 +490,8 @@ void Assembler::target_at_put(int pos, int target_pos, bool* is_branch) {
Register dst = Register::from_code(instr_at(pos + kInstrSize)); Register dst = Register::from_code(instr_at(pos + kInstrSize));
int32_t offset = target_pos + (Code::kHeaderSize - kHeapObjectTag); int32_t offset = target_pos + (Code::kHeaderSize - kHeapObjectTag);
PatchingAssembler patcher(options(), PatchingAssembler patcher(options(),
reinterpret_cast<byte*>(buffer_ + pos), 2); reinterpret_cast<byte*>(buffer_start_ + pos),
2);
patcher.bitwise_mov32(dst, offset); patcher.bitwise_mov32(dst, offset);
break; break;
} }
...@@ -504,7 +506,7 @@ void Assembler::target_at_put(int pos, int target_pos, bool* is_branch) { ...@@ -504,7 +506,7 @@ void Assembler::target_at_put(int pos, int target_pos, bool* is_branch) {
: (SIGN_EXT_IMM22(operands & kImm22Mask)); : (SIGN_EXT_IMM22(operands & kImm22Mask));
int32_t offset = target_pos + delta; int32_t offset = target_pos + delta;
PatchingAssembler patcher( PatchingAssembler patcher(
options(), reinterpret_cast<byte*>(buffer_ + pos), options(), reinterpret_cast<byte*>(buffer_start_ + pos),
2 + static_cast<int32_t>(opcode == kUnboundAddLabelLongOffsetOpcode)); 2 + static_cast<int32_t>(opcode == kUnboundAddLabelLongOffsetOpcode));
patcher.bitwise_add32(dst, base, offset); patcher.bitwise_add32(dst, base, offset);
if (opcode == kUnboundAddLabelLongOffsetOpcode) patcher.nop(); if (opcode == kUnboundAddLabelLongOffsetOpcode) patcher.nop();
...@@ -514,7 +516,7 @@ void Assembler::target_at_put(int pos, int target_pos, bool* is_branch) { ...@@ -514,7 +516,7 @@ void Assembler::target_at_put(int pos, int target_pos, bool* is_branch) {
// Load the address of the label in a register. // Load the address of the label in a register.
Register dst = Register::from_code(instr_at(pos + kInstrSize)); Register dst = Register::from_code(instr_at(pos + kInstrSize));
PatchingAssembler patcher(options(), PatchingAssembler patcher(options(),
reinterpret_cast<byte*>(buffer_ + pos), reinterpret_cast<byte*>(buffer_start_ + pos),
kMovInstructionsNoConstantPool); kMovInstructionsNoConstantPool);
// Keep internal references relative until EmitRelocations. // Keep internal references relative until EmitRelocations.
patcher.bitwise_mov(dst, target_pos); patcher.bitwise_mov(dst, target_pos);
...@@ -522,7 +524,7 @@ void Assembler::target_at_put(int pos, int target_pos, bool* is_branch) { ...@@ -522,7 +524,7 @@ void Assembler::target_at_put(int pos, int target_pos, bool* is_branch) {
} }
case kUnboundJumpTableEntryOpcode: { case kUnboundJumpTableEntryOpcode: {
PatchingAssembler patcher(options(), PatchingAssembler patcher(options(),
reinterpret_cast<byte*>(buffer_ + pos), reinterpret_cast<byte*>(buffer_start_ + pos),
kPointerSize / kInstrSize); kPointerSize / kInstrSize);
// Keep internal references relative until EmitRelocations. // Keep internal references relative until EmitRelocations.
patcher.dp(target_pos); patcher.dp(target_pos);
...@@ -1979,54 +1981,43 @@ bool Assembler::IsNop(Instr instr, int type) { ...@@ -1979,54 +1981,43 @@ bool Assembler::IsNop(Instr instr, int type) {
void Assembler::GrowBuffer(int needed) { void Assembler::GrowBuffer(int needed) {
if (!own_buffer_) FATAL("external code buffer is too small"); DCHECK_EQ(buffer_start_, buffer_->start());
// Compute new buffer size. // Compute new buffer size.
CodeDesc desc; // the new buffer int old_size = buffer_->size();
if (buffer_size_ < 4 * KB) { int new_size = std::min(2 * old_size, old_size + 1 * MB);
desc.buffer_size = 4 * KB; int space = buffer_space() + (new_size - old_size);
} else if (buffer_size_ < 1 * MB) { new_size += (space < needed) ? needed - space : 0;
desc.buffer_size = 2 * buffer_size_;
} else {
desc.buffer_size = buffer_size_ + 1 * MB;
}
int space = buffer_space() + (desc.buffer_size - buffer_size_);
if (space < needed) {
desc.buffer_size += needed - space;
}
// Some internal data structures overflow for very large buffers, // Some internal data structures overflow for very large buffers,
// they must ensure that kMaximalBufferSize is not too large. // they must ensure that kMaximalBufferSize is not too large.
if (desc.buffer_size > kMaximalBufferSize) { if (new_size > kMaximalBufferSize) {
V8::FatalProcessOutOfMemory(nullptr, "Assembler::GrowBuffer"); V8::FatalProcessOutOfMemory(nullptr, "Assembler::GrowBuffer");
} }
// Set up new buffer. // Set up new buffer.
desc.buffer = NewArray<byte>(desc.buffer_size); std::unique_ptr<AssemblerBuffer> new_buffer = buffer_->Grow(new_size);
desc.origin = this; DCHECK_EQ(new_size, new_buffer->size());
byte* new_start = new_buffer->start();
desc.instr_size = pc_offset();
desc.reloc_size = (buffer_ + buffer_size_) - reloc_info_writer.pos();
// Copy the data. // Copy the data.
intptr_t pc_delta = desc.buffer - buffer_; intptr_t pc_delta = new_start - buffer_start_;
intptr_t rc_delta = intptr_t rc_delta = (new_start + new_size) - (buffer_start_ + old_size);
(desc.buffer + desc.buffer_size) - (buffer_ + buffer_size_); size_t reloc_size = (buffer_start_ + old_size) - reloc_info_writer.pos();
memmove(desc.buffer, buffer_, desc.instr_size); MemMove(new_start, buffer_start_, pc_offset());
memmove(reloc_info_writer.pos() + rc_delta, reloc_info_writer.pos(), MemMove(reloc_info_writer.pos() + rc_delta, reloc_info_writer.pos(),
desc.reloc_size); reloc_size);
// Switch buffers. // Switch buffers.
DeleteArray(buffer_); buffer_ = std::move(new_buffer);
buffer_ = desc.buffer; buffer_start_ = new_start;
buffer_size_ = desc.buffer_size;
pc_ += pc_delta; pc_ += pc_delta;
reloc_info_writer.Reposition(reloc_info_writer.pos() + rc_delta, reloc_info_writer.Reposition(reloc_info_writer.pos() + rc_delta,
reloc_info_writer.last_pc() + pc_delta); reloc_info_writer.last_pc() + pc_delta);
// Nothing else to do here since we keep all internal references and // None of our relocation types are pc relative pointing outside the code
// deferred relocation entries relative to the buffer (until // buffer nor pc absolute pointing inside the code buffer, so there is no need
// EmitRelocations). // to relocate any emitted relocation entries.
} }
...@@ -2071,18 +2062,19 @@ void Assembler::EmitRelocations() { ...@@ -2071,18 +2062,19 @@ void Assembler::EmitRelocations() {
for (std::vector<DeferredRelocInfo>::iterator it = relocations_.begin(); for (std::vector<DeferredRelocInfo>::iterator it = relocations_.begin();
it != relocations_.end(); it++) { it != relocations_.end(); it++) {
RelocInfo::Mode rmode = it->rmode(); RelocInfo::Mode rmode = it->rmode();
Address pc = reinterpret_cast<Address>(buffer_) + it->position(); Address pc = reinterpret_cast<Address>(buffer_start_) + it->position();
RelocInfo rinfo(pc, rmode, it->data(), Code()); RelocInfo rinfo(pc, rmode, it->data(), Code());
// Fix up internal references now that they are guaranteed to be bound. // Fix up internal references now that they are guaranteed to be bound.
if (RelocInfo::IsInternalReference(rmode)) { if (RelocInfo::IsInternalReference(rmode)) {
// Jump table entry // Jump table entry
intptr_t pos = static_cast<intptr_t>(Memory<Address>(pc)); intptr_t pos = static_cast<intptr_t>(Memory<Address>(pc));
Memory<Address>(pc) = reinterpret_cast<Address>(buffer_) + pos; Memory<Address>(pc) = reinterpret_cast<Address>(buffer_start_) + pos;
} else if (RelocInfo::IsInternalReferenceEncoded(rmode)) { } else if (RelocInfo::IsInternalReferenceEncoded(rmode)) {
// mov sequence // mov sequence
intptr_t pos = static_cast<intptr_t>(target_address_at(pc, kNullAddress)); intptr_t pos = static_cast<intptr_t>(target_address_at(pc, kNullAddress));
set_target_address_at(pc, 0, reinterpret_cast<Address>(buffer_) + pos, set_target_address_at(pc, 0,
reinterpret_cast<Address>(buffer_start_) + pos,
SKIP_ICACHE_FLUSH); SKIP_ICACHE_FLUSH);
} }
...@@ -2129,14 +2121,15 @@ void Assembler::CheckTrampolinePool() { ...@@ -2129,14 +2121,15 @@ void Assembler::CheckTrampolinePool() {
PatchingAssembler::PatchingAssembler(const AssemblerOptions& options, PatchingAssembler::PatchingAssembler(const AssemblerOptions& options,
byte* address, int instructions) byte* address, int instructions)
: Assembler(options, address, instructions * kInstrSize + kGap) { : Assembler(options, ExternalAssemblerBuffer(
DCHECK_EQ(reloc_info_writer.pos(), buffer_ + buffer_size_); address, instructions * kInstrSize + kGap)) {
DCHECK_EQ(reloc_info_writer.pos(), buffer_start_ + buffer_->size());
} }
PatchingAssembler::~PatchingAssembler() { PatchingAssembler::~PatchingAssembler() {
// Check that the code was patched as expected. // Check that the code was patched as expected.
DCHECK_EQ(pc_, buffer_ + buffer_size_ - kGap); DCHECK_EQ(pc_, buffer_start_ + buffer_->size() - kGap);
DCHECK_EQ(reloc_info_writer.pos(), buffer_ + buffer_size_); DCHECK_EQ(reloc_info_writer.pos(), buffer_start_ + buffer_->size());
} }
} // namespace internal } // namespace internal
......
...@@ -181,6 +181,12 @@ class Assembler : public AssemblerBase { ...@@ -181,6 +181,12 @@ class Assembler : public AssemblerBase {
// for a detailed comment on the layout (globals.h). // for a detailed comment on the layout (globals.h).
// //
// If the provided buffer is nullptr, the assembler allocates and grows its // If the provided buffer is nullptr, the assembler allocates and grows its
// own buffer. Otherwise it takes ownership of the provided buffer.
explicit Assembler(const AssemblerOptions&,
std::unique_ptr<AssemblerBuffer> = {});
// Legacy constructor.
// If the provided buffer is nullptr, the assembler allocates and grows its
// own buffer, and buffer_size determines the initial buffer size. The buffer // own buffer, and buffer_size determines the initial buffer size. The buffer
// is owned by the assembler and deallocated upon destruction of the // is owned by the assembler and deallocated upon destruction of the
// assembler. // assembler.
...@@ -189,7 +195,14 @@ class Assembler : public AssemblerBase { ...@@ -189,7 +195,14 @@ class Assembler : public AssemblerBase {
// buffer for code generation and assumes its size to be buffer_size. If the // buffer for code generation and assumes its size to be buffer_size. If the
// buffer is too small, a fatal error occurs. No deallocation of the buffer is // buffer is too small, a fatal error occurs. No deallocation of the buffer is
// done upon destruction of the assembler. // done upon destruction of the assembler.
Assembler(const AssemblerOptions& options, void* buffer, int buffer_size); //
// TODO(clemensh): Remove this constructor, refactor all call sites to use the
// one above.
Assembler(const AssemblerOptions& options, void* buffer, int buffer_size)
: Assembler(options, buffer ? ExternalAssemblerBuffer(buffer, buffer_size)
: NewAssemblerBuffer(
buffer_size ? buffer_size
: kMinimalBufferSize)) {}
virtual ~Assembler() {} virtual ~Assembler() {}
// GetCode emits any pending (non-emitted) code and fills the descriptor // GetCode emits any pending (non-emitted) code and fills the descriptor
...@@ -1041,9 +1054,11 @@ class Assembler : public AssemblerBase { ...@@ -1041,9 +1054,11 @@ class Assembler : public AssemblerBase {
void dp(uintptr_t data); void dp(uintptr_t data);
// Read/patch instructions // Read/patch instructions
Instr instr_at(int pos) { return *reinterpret_cast<Instr*>(buffer_ + pos); } Instr instr_at(int pos) {
return *reinterpret_cast<Instr*>(buffer_start_ + pos);
}
void instr_at_put(int pos, Instr instr) { void instr_at_put(int pos, Instr instr) {
*reinterpret_cast<Instr*>(buffer_ + pos) = instr; *reinterpret_cast<Instr*>(buffer_start_ + pos) = instr;
} }
static Instr instr_at(Address pc) { return *reinterpret_cast<Instr*>(pc); } static Instr instr_at(Address pc) { return *reinterpret_cast<Instr*>(pc); }
static void instr_at_put(Address pc, Instr instr) { static void instr_at_put(Address pc, Instr instr) {
......
...@@ -317,7 +317,7 @@ void Assembler::AllocateAndInstallRequestedHeapObjects(Isolate* isolate) { ...@@ -317,7 +317,7 @@ void Assembler::AllocateAndInstallRequestedHeapObjects(Isolate* isolate) {
DCHECK_IMPLIES(isolate == nullptr, heap_object_requests_.empty()); DCHECK_IMPLIES(isolate == nullptr, heap_object_requests_.empty());
for (auto& request : heap_object_requests_) { for (auto& request : heap_object_requests_) {
Handle<HeapObject> object; Handle<HeapObject> object;
Address pc = reinterpret_cast<Address>(buffer_ + request.offset()); Address pc = reinterpret_cast<Address>(buffer_start_) + request.offset();
switch (request.kind()) { switch (request.kind()) {
case HeapObjectRequest::kHeapNumber: { case HeapObjectRequest::kHeapNumber: {
object = object =
...@@ -340,10 +340,10 @@ void Assembler::AllocateAndInstallRequestedHeapObjects(Isolate* isolate) { ...@@ -340,10 +340,10 @@ void Assembler::AllocateAndInstallRequestedHeapObjects(Isolate* isolate) {
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// Specific instructions, constants, and masks. // Specific instructions, constants, and masks.
Assembler::Assembler(const AssemblerOptions& options, void* buffer, Assembler::Assembler(const AssemblerOptions& options,
int buffer_size) std::unique_ptr<AssemblerBuffer> buffer)
: AssemblerBase(options, buffer, buffer_size) { : AssemblerBase(options, std::move(buffer)) {
reloc_info_writer.Reposition(buffer_ + buffer_size_, pc_); reloc_info_writer.Reposition(buffer_start_ + buffer_->size(), pc_);
ReserveCodeTargetSpace(100); ReserveCodeTargetSpace(100);
last_bound_pos_ = 0; last_bound_pos_ = 0;
relocations_.reserve(128); relocations_.reserve(128);
...@@ -357,10 +357,11 @@ void Assembler::GetCode(Isolate* isolate, CodeDesc* desc) { ...@@ -357,10 +357,11 @@ void Assembler::GetCode(Isolate* isolate, CodeDesc* desc) {
AllocateAndInstallRequestedHeapObjects(isolate); AllocateAndInstallRequestedHeapObjects(isolate);
// Set up code descriptor. // Set up code descriptor.
desc->buffer = buffer_; desc->buffer = buffer_start_;
desc->buffer_size = buffer_size_; desc->buffer_size = buffer_->size();
desc->instr_size = pc_offset(); desc->instr_size = pc_offset();
desc->reloc_size = (buffer_ + buffer_size_) - reloc_info_writer.pos(); desc->reloc_size =
(buffer_start_ + desc->buffer_size) - reloc_info_writer.pos();
desc->constant_pool_size = 0; desc->constant_pool_size = 0;
desc->origin = this; desc->origin = this;
desc->unwinding_info_size = 0; desc->unwinding_info_size = 0;
...@@ -422,7 +423,7 @@ const int kEndOfChain = -4; ...@@ -422,7 +423,7 @@ const int kEndOfChain = -4;
int Assembler::target_at(int pos) { int Assembler::target_at(int pos) {
SixByteInstr instr = instr_at(pos); SixByteInstr instr = instr_at(pos);
// check which type of branch this is 16 or 26 bit offset // check which type of branch this is 16 or 26 bit offset
Opcode opcode = Instruction::S390OpcodeValue(buffer_ + pos); Opcode opcode = Instruction::S390OpcodeValue(buffer_start_ + pos);
if (BRC == opcode || BRCT == opcode || BRCTG == opcode || BRXH == opcode) { if (BRC == opcode || BRCT == opcode || BRCTG == opcode || BRXH == opcode) {
int16_t imm16 = SIGN_EXT_IMM16((instr & kImm16Mask)); int16_t imm16 = SIGN_EXT_IMM16((instr & kImm16Mask));
...@@ -454,7 +455,7 @@ int Assembler::target_at(int pos) { ...@@ -454,7 +455,7 @@ int Assembler::target_at(int pos) {
// Update the target address of the current relative instruction. // Update the target address of the current relative instruction.
void Assembler::target_at_put(int pos, int target_pos, bool* is_branch) { void Assembler::target_at_put(int pos, int target_pos, bool* is_branch) {
SixByteInstr instr = instr_at(pos); SixByteInstr instr = instr_at(pos);
Opcode opcode = Instruction::S390OpcodeValue(buffer_ + pos); Opcode opcode = Instruction::S390OpcodeValue(buffer_start_ + pos);
if (is_branch != nullptr) { if (is_branch != nullptr) {
*is_branch = (opcode == BRC || opcode == BRCT || opcode == BRCTG || *is_branch = (opcode == BRC || opcode == BRCT || opcode == BRCTG ||
...@@ -497,7 +498,7 @@ void Assembler::target_at_put(int pos, int target_pos, bool* is_branch) { ...@@ -497,7 +498,7 @@ void Assembler::target_at_put(int pos, int target_pos, bool* is_branch) {
// Returns the maximum number of bits given instruction can address. // Returns the maximum number of bits given instruction can address.
int Assembler::max_reach_from(int pos) { int Assembler::max_reach_from(int pos) {
Opcode opcode = Instruction::S390OpcodeValue(buffer_ + pos); Opcode opcode = Instruction::S390OpcodeValue(buffer_start_ + pos);
// Check which type of instr. In theory, we can return // Check which type of instr. In theory, we can return
// the values below + 1, given offset is # of halfwords // the values below + 1, given offset is # of halfwords
if (BRC == opcode || BRCT == opcode || BRCTG == opcode|| BRXH == opcode || if (BRC == opcode || BRCT == opcode || BRCTG == opcode|| BRXH == opcode ||
...@@ -707,47 +708,36 @@ void Assembler::dumy(int r1, int x2, int b2, int d2) { ...@@ -707,47 +708,36 @@ void Assembler::dumy(int r1, int x2, int b2, int d2) {
} }
void Assembler::GrowBuffer(int needed) { void Assembler::GrowBuffer(int needed) {
if (!own_buffer_) FATAL("external code buffer is too small"); DCHECK_EQ(buffer_start_, buffer_->start());
// Compute new buffer size. // Compute new buffer size.
CodeDesc desc; // the new buffer int old_size = buffer_->size();
if (buffer_size_ < 4 * KB) { int new_size = std::min(2 * old_size, old_size + 1 * MB);
desc.buffer_size = 4 * KB; int space = buffer_space() + (new_size - old_size);
} else if (buffer_size_ < 1 * MB) { new_size += (space < needed) ? needed - space : 0;
desc.buffer_size = 2 * buffer_size_;
} else {
desc.buffer_size = buffer_size_ + 1 * MB;
}
int space = buffer_space() + (desc.buffer_size - buffer_size_);
if (space < needed) {
desc.buffer_size += needed - space;
}
// Some internal data structures overflow for very large buffers, // Some internal data structures overflow for very large buffers,
// they must ensure that kMaximalBufferSize is not too large. // they must ensure that kMaximalBufferSize is not too large.
if (desc.buffer_size > kMaximalBufferSize) { if (new_size > kMaximalBufferSize) {
V8::FatalProcessOutOfMemory(nullptr, "Assembler::GrowBuffer"); V8::FatalProcessOutOfMemory(nullptr, "Assembler::GrowBuffer");
} }
// Set up new buffer. // Set up new buffer.
desc.buffer = NewArray<byte>(desc.buffer_size); std::unique_ptr<AssemblerBuffer> new_buffer = buffer_->Grow(new_size);
desc.origin = this; DCHECK_EQ(new_size, new_buffer->size());
byte* new_start = new_buffer->start();
desc.instr_size = pc_offset();
desc.reloc_size = (buffer_ + buffer_size_) - reloc_info_writer.pos();
// Copy the data. // Copy the data.
intptr_t pc_delta = desc.buffer - buffer_; intptr_t pc_delta = new_start - buffer_start_;
intptr_t rc_delta = intptr_t rc_delta = (new_start + new_size) - (buffer_start_ + old_size);
(desc.buffer + desc.buffer_size) - (buffer_ + buffer_size_); size_t reloc_size = (buffer_start_ + old_size) - reloc_info_writer.pos();
memmove(desc.buffer, buffer_, desc.instr_size); MemMove(new_start, buffer_start_, pc_offset());
memmove(reloc_info_writer.pos() + rc_delta, reloc_info_writer.pos(), MemMove(reloc_info_writer.pos() + rc_delta, reloc_info_writer.pos(),
desc.reloc_size); reloc_size);
// Switch buffers. // Switch buffers.
DeleteArray(buffer_); buffer_ = std::move(new_buffer);
buffer_ = desc.buffer; buffer_start_ = new_start;
buffer_size_ = desc.buffer_size;
pc_ += pc_delta; pc_ += pc_delta;
reloc_info_writer.Reposition(reloc_info_writer.pos() + rc_delta, reloc_info_writer.Reposition(reloc_info_writer.pos() + rc_delta,
reloc_info_writer.last_pc() + pc_delta); reloc_info_writer.last_pc() + pc_delta);
...@@ -802,18 +792,19 @@ void Assembler::EmitRelocations() { ...@@ -802,18 +792,19 @@ void Assembler::EmitRelocations() {
for (std::vector<DeferredRelocInfo>::iterator it = relocations_.begin(); for (std::vector<DeferredRelocInfo>::iterator it = relocations_.begin();
it != relocations_.end(); it++) { it != relocations_.end(); it++) {
RelocInfo::Mode rmode = it->rmode(); RelocInfo::Mode rmode = it->rmode();
Address pc = reinterpret_cast<Address>(buffer_) + it->position(); Address pc = reinterpret_cast<Address>(buffer_start_) + it->position();
RelocInfo rinfo(pc, rmode, it->data(), Code()); RelocInfo rinfo(pc, rmode, it->data(), Code());
// Fix up internal references now that they are guaranteed to be bound. // Fix up internal references now that they are guaranteed to be bound.
if (RelocInfo::IsInternalReference(rmode)) { if (RelocInfo::IsInternalReference(rmode)) {
// Jump table entry // Jump table entry
Address pos = Memory<Address>(pc); Address pos = Memory<Address>(pc);
Memory<Address>(pc) = reinterpret_cast<Address>(buffer_) + pos; Memory<Address>(pc) = reinterpret_cast<Address>(buffer_start_) + pos;
} else if (RelocInfo::IsInternalReferenceEncoded(rmode)) { } else if (RelocInfo::IsInternalReferenceEncoded(rmode)) {
// mov sequence // mov sequence
Address pos = target_address_at(pc, 0); Address pos = target_address_at(pc, 0);
set_target_address_at(pc, 0, reinterpret_cast<Address>(buffer_) + pos, set_target_address_at(pc, 0,
reinterpret_cast<Address>(buffer_start_) + pos,
SKIP_ICACHE_FLUSH); SKIP_ICACHE_FLUSH);
} }
......
...@@ -220,6 +220,12 @@ class V8_EXPORT_PRIVATE Assembler : public AssemblerBase { ...@@ -220,6 +220,12 @@ class V8_EXPORT_PRIVATE Assembler : public AssemblerBase {
// for a detailed comment on the layout (globals.h). // for a detailed comment on the layout (globals.h).
// //
// If the provided buffer is nullptr, the assembler allocates and grows its // If the provided buffer is nullptr, the assembler allocates and grows its
// own buffer. Otherwise it takes ownership of the provided buffer.
explicit Assembler(const AssemblerOptions&,
std::unique_ptr<AssemblerBuffer> = {});
// Legacy constructor.
// If the provided buffer is nullptr, the assembler allocates and grows its
// own buffer, and buffer_size determines the initial buffer size. The buffer // own buffer, and buffer_size determines the initial buffer size. The buffer
// is owned by the assembler and deallocated upon destruction of the // is owned by the assembler and deallocated upon destruction of the
// assembler. // assembler.
...@@ -228,7 +234,14 @@ class V8_EXPORT_PRIVATE Assembler : public AssemblerBase { ...@@ -228,7 +234,14 @@ class V8_EXPORT_PRIVATE Assembler : public AssemblerBase {
// buffer for code generation and assumes its size to be buffer_size. If the // buffer for code generation and assumes its size to be buffer_size. If the
// buffer is too small, a fatal error occurs. No deallocation of the buffer is // buffer is too small, a fatal error occurs. No deallocation of the buffer is
// done upon destruction of the assembler. // done upon destruction of the assembler.
Assembler(const AssemblerOptions& options, void* buffer, int buffer_size); //
// TODO(clemensh): Remove this constructor, refactor all call sites to use the
// one above.
Assembler(const AssemblerOptions& options, void* buffer, int buffer_size)
: Assembler(options, buffer ? ExternalAssemblerBuffer(buffer, buffer_size)
: NewAssemblerBuffer(
buffer_size ? buffer_size
: kMinimalBufferSize)) {}
virtual ~Assembler() {} virtual ~Assembler() {}
// GetCode emits any pending (non-emitted) code and fills the descriptor // GetCode emits any pending (non-emitted) code and fills the descriptor
...@@ -1231,16 +1244,16 @@ inline void ss_a_format(Opcode op, int f1, int f2, int f3, int f4, int f5) { ...@@ -1231,16 +1244,16 @@ inline void ss_a_format(Opcode op, int f1, int f2, int f3, int f4, int f5) {
// Read/patch instructions // Read/patch instructions
SixByteInstr instr_at(int pos) { SixByteInstr instr_at(int pos) {
return Instruction::InstructionBits(buffer_ + pos); return Instruction::InstructionBits(buffer_start_ + pos);
} }
template <typename T> template <typename T>
void instr_at_put(int pos, T instr) { void instr_at_put(int pos, T instr) {
Instruction::SetInstructionBits<T>(buffer_ + pos, instr); Instruction::SetInstructionBits<T>(buffer_start_ + pos, instr);
} }
// Decodes instruction at pos, and returns its length // Decodes instruction at pos, and returns its length
int32_t instr_length_at(int pos) { int32_t instr_length_at(int pos) {
return Instruction::InstructionLength(buffer_ + pos); return Instruction::InstructionLength(buffer_start_ + pos);
} }
static SixByteInstr instr_at(byte* pc) { static SixByteInstr instr_at(byte* pc) {
...@@ -1271,7 +1284,7 @@ inline void ss_a_format(Opcode op, int f1, int f2, int f3, int f4, int f5) { ...@@ -1271,7 +1284,7 @@ inline void ss_a_format(Opcode op, int f1, int f2, int f3, int f4, int f5) {
void emit_label_addr(Label* label); void emit_label_addr(Label* label);
public: public:
byte* buffer_pos() const { return buffer_; } byte* buffer_pos() const { return buffer_start_; }
protected: protected:
int buffer_space() const { return reloc_info_writer.pos() - pc_; } int buffer_space() const { return reloc_info_writer.pos() - pc_; }
......
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