Commit 7f622cff authored by rmcilroy@chromium.org's avatar rmcilroy@chromium.org

Introduce FrameAndConstantPoolScope and ConstantPoolUnavailableScope.

Adds FrameAndConstantPoolScope and ConstantPoolUnavailableScope to enable
scoped management of constant pool availability.  Also load constant pool
pointer when entering an internal frame scope.

R=rodolph.perfetta@arm.com, ulan@chromium.org

Review URL: https://codereview.chromium.org/190793002

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@19858 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 6b864014
......@@ -530,6 +530,8 @@ Assembler::Assembler(Isolate* isolate, void* buffer, int buffer_size)
first_const_pool_32_use_ = -1;
first_const_pool_64_use_ = -1;
last_bound_pos_ = 0;
constant_pool_available_ = !FLAG_enable_ool_constant_pool;
constant_pool_full_ = false;
ClearRecordedAstId();
}
......
......@@ -1458,6 +1458,14 @@ class Assembler : public AssemblerBase {
// Check if is time to emit a constant pool.
void CheckConstPool(bool force_emit, bool require_jump);
bool can_use_constant_pool() const {
return is_constant_pool_available() && !constant_pool_full_;
}
void set_constant_pool_full() {
constant_pool_full_ = true;
}
protected:
// Relocation for a type-recording IC has the AST id added to it. This
// member variable is a way to pass the information from the call site to
......@@ -1511,6 +1519,14 @@ class Assembler : public AssemblerBase {
(pc_offset() < no_const_pool_before_);
}
bool is_constant_pool_available() const {
return constant_pool_available_;
}
void set_constant_pool_available(bool available) {
constant_pool_available_ = available;
}
private:
int next_buffer_check_; // pc offset of next buffer check
......@@ -1571,6 +1587,13 @@ class Assembler : public AssemblerBase {
// The bound position, before this we cannot do instruction elimination.
int last_bound_pos_;
// Indicates whether the constant pool can be accessed, which is only possible
// if the pp register points to the current code object's constant pool.
bool constant_pool_available_;
// Indicates whether the constant pool is too full to accept new entries due
// to the ldr instruction's limitted immediate offset range.
bool constant_pool_full_;
// Code emission
inline void CheckBuffer();
void GrowBuffer();
......@@ -1607,6 +1630,8 @@ class Assembler : public AssemblerBase {
friend class RelocInfo;
friend class CodePatcher;
friend class BlockConstPoolScope;
friend class FrameAndConstantPoolScope;
friend class ConstantPoolUnavailableScope;
PositionsRecorder positions_recorder_;
friend class PositionsRecorder;
......
......@@ -261,7 +261,7 @@ void Builtins::Generate_StringConstructCode(MacroAssembler* masm) {
__ push(function); // Preserve the function.
__ IncrementCounter(counters->string_ctor_conversions(), 1, r3, r4);
{
FrameScope scope(masm, StackFrame::INTERNAL);
FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
__ push(r0);
__ InvokeBuiltin(Builtins::TO_STRING, CALL_FUNCTION);
}
......@@ -281,7 +281,7 @@ void Builtins::Generate_StringConstructCode(MacroAssembler* masm) {
__ bind(&gc_required);
__ IncrementCounter(counters->string_ctor_gc_required(), 1, r3, r4);
{
FrameScope scope(masm, StackFrame::INTERNAL);
FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
__ push(argument);
__ CallRuntime(Runtime::kNewStringWrapper, 1);
}
......@@ -291,7 +291,7 @@ void Builtins::Generate_StringConstructCode(MacroAssembler* masm) {
static void CallRuntimePassFunction(
MacroAssembler* masm, Runtime::FunctionId function_id) {
FrameScope scope(masm, StackFrame::INTERNAL);
FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
// Push a copy of the function onto the stack.
__ push(r1);
// Push function as parameter to the runtime call.
......@@ -353,7 +353,7 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
// Enter a construct frame.
{
FrameScope scope(masm, StackFrame::CONSTRUCT);
FrameAndConstantPoolScope scope(masm, StackFrame::CONSTRUCT);
// Preserve the two incoming parameters on the stack.
__ SmiTag(r0);
......@@ -773,7 +773,7 @@ void Builtins::Generate_CompileUnoptimized(MacroAssembler* masm) {
static void CallCompileOptimized(MacroAssembler* masm, bool concurrent) {
FrameScope scope(masm, StackFrame::INTERNAL);
FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
// Push a copy of the function onto the stack.
__ push(r1);
// Push function as parameter to the runtime call.
......@@ -869,7 +869,7 @@ void Builtins::Generate_MarkCodeAsExecutedTwice(MacroAssembler* masm) {
static void Generate_NotifyStubFailureHelper(MacroAssembler* masm,
SaveFPRegsMode save_doubles) {
{
FrameScope scope(masm, StackFrame::INTERNAL);
FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
// Preserve registers across notification, this is important for compiled
// stubs that tail call the runtime on deopts passing their parameters in
......@@ -898,7 +898,7 @@ void Builtins::Generate_NotifyStubFailureSaveDoubles(MacroAssembler* masm) {
static void Generate_NotifyDeoptimizedHelper(MacroAssembler* masm,
Deoptimizer::BailoutType type) {
{
FrameScope scope(masm, StackFrame::INTERNAL);
FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
// Pass the function and deoptimization type to the runtime system.
__ mov(r0, Operand(Smi::FromInt(static_cast<int>(type))));
__ push(r0);
......@@ -946,7 +946,7 @@ void Builtins::Generate_OnStackReplacement(MacroAssembler* masm) {
// Lookup the function in the JavaScript frame.
__ ldr(r0, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
{
FrameScope scope(masm, StackFrame::INTERNAL);
FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
// Pass function as argument.
__ push(r0);
__ CallRuntime(Runtime::kCompileForOnStackReplacement, 1);
......@@ -986,7 +986,7 @@ void Builtins::Generate_OsrAfterStackCheck(MacroAssembler* masm) {
__ cmp(sp, Operand(ip));
__ b(hs, &ok);
{
FrameScope scope(masm, StackFrame::INTERNAL);
FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
__ CallRuntime(Runtime::kStackGuard, 0);
}
__ Jump(masm->isolate()->builtins()->OnStackReplacement(),
......@@ -1061,7 +1061,7 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
{
// Enter an internal frame in order to preserve argument count.
FrameScope scope(masm, StackFrame::INTERNAL);
FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
__ SmiTag(r0);
__ push(r0);
......@@ -1188,7 +1188,7 @@ void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
const int kFunctionOffset = 4 * kPointerSize;
{
FrameScope frame_scope(masm, StackFrame::INTERNAL);
FrameAndConstantPoolScope frame_scope(masm, StackFrame::INTERNAL);
__ ldr(r0, MemOperand(fp, kFunctionOffset)); // get the function
__ push(r0);
......
......@@ -490,7 +490,7 @@ void HydrogenCodeStub::GenerateLightweightMiss(MacroAssembler* masm) {
int param_count = descriptor->register_param_count_;
{
// Call the runtime system in a fresh internal frame.
FrameScope scope(masm, StackFrame::INTERNAL);
FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
ASSERT(descriptor->register_param_count_ == 0 ||
r0.is(descriptor->register_params_[param_count - 1]));
// Push arguments
......@@ -1606,14 +1606,15 @@ void CEntryStub::GenerateCore(MacroAssembler* masm,
JumpIfOOM(masm, r0, ip, throw_out_of_memory_exception);
// Clear the pending exception.
__ mov(r3, Operand(isolate->factory()->the_hole_value()));
__ LoadRoot(r3, Heap::kTheHoleValueRootIndex);
__ mov(ip, Operand(ExternalReference(Isolate::kPendingExceptionAddress,
isolate)));
__ str(r3, MemOperand(ip));
// Special handling of termination exceptions which are uncatchable
// by javascript code.
__ cmp(r0, Operand(isolate->factory()->termination_exception()));
__ LoadRoot(r3, Heap::kTerminationExceptionRootIndex);
__ cmp(r0, r3);
__ b(eq, throw_termination_exception);
// Handle normal exception.
......@@ -1645,7 +1646,7 @@ void CEntryStub::Generate(MacroAssembler* masm) {
__ sub(r6, r6, Operand(kPointerSize));
// Enter the exit frame that transitions from JavaScript to C++.
FrameScope scope(masm, StackFrame::MANUAL);
FrameAndConstantPoolScope scope(masm, StackFrame::MANUAL);
__ EnterExitFrame(save_doubles_);
// Set up argc and the builtin function in callee-saved registers.
......@@ -2057,7 +2058,7 @@ void InstanceofStub::Generate(MacroAssembler* masm) {
__ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION);
} else {
{
FrameScope scope(masm, StackFrame::INTERNAL);
FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
__ Push(r0, r1);
__ InvokeBuiltin(Builtins::INSTANCE_OF, CALL_FUNCTION);
}
......@@ -3066,7 +3067,7 @@ static void GenerateRecordCallTarget(MacroAssembler* masm) {
// The target function is the Array constructor,
// Create an AllocationSite if we don't already have it, store it in the slot.
{
FrameScope scope(masm, StackFrame::INTERNAL);
FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
// Arguments register must be smi-tagged to call out.
__ SmiTag(r0);
......@@ -3189,7 +3190,7 @@ void CallFunctionStub::Generate(MacroAssembler* masm) {
if (CallAsMethod()) {
__ bind(&wrap);
// Wrap the receiver and patch it back onto the stack.
{ FrameScope frame_scope(masm, StackFrame::INTERNAL);
{ FrameAndConstantPoolScope frame_scope(masm, StackFrame::INTERNAL);
__ Push(r1, r3);
__ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
__ pop(r1);
......@@ -4474,7 +4475,7 @@ void ICCompareStub::GenerateMiss(MacroAssembler* masm) {
ExternalReference miss =
ExternalReference(IC_Utility(IC::kCompareIC_Miss), masm->isolate());
FrameScope scope(masm, StackFrame::INTERNAL);
FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
__ Push(r1, r0);
__ Push(lr, r1, r0);
__ mov(ip, Operand(Smi::FromInt(op_)));
......@@ -5496,7 +5497,7 @@ void CallApiFunctionStub::Generate(MacroAssembler* masm) {
// it's not controlled by GC.
const int kApiStackSpace = 4;
FrameScope frame_scope(masm, StackFrame::MANUAL);
FrameAndConstantPoolScope frame_scope(masm, StackFrame::MANUAL);
__ EnterExitFrame(false, kApiStackSpace);
ASSERT(!api_function_address.is(r0) && !scratch.is(r0));
......@@ -5556,7 +5557,7 @@ void CallApiGetterStub::Generate(MacroAssembler* masm) {
__ add(r1, r0, Operand(1 * kPointerSize)); // r1 = PCA
const int kApiStackSpace = 1;
FrameScope frame_scope(masm, StackFrame::MANUAL);
FrameAndConstantPoolScope frame_scope(masm, StackFrame::MANUAL);
__ EnterExitFrame(false, kApiStackSpace);
// Create PropertyAccessorInfo instance on the stack above the exit frame with
......
......@@ -117,7 +117,7 @@ static void Generate_DebugBreakCallHelper(MacroAssembler* masm,
RegList object_regs,
RegList non_object_regs) {
{
FrameScope scope(masm, StackFrame::INTERNAL);
FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
// Store the registers containing live values on the expression stack to
// make sure that these are correctly updated during GC. Non object values
......
......@@ -171,7 +171,6 @@ void FullCodeGenerator::Generate() {
info->set_prologue_offset(masm_->pc_offset());
__ Prologue(BUILD_FUNCTION_FRAME);
info->AddNoFrameRange(0, masm_->pc_offset());
__ LoadConstantPoolPointerRegister();
{ Comment cmnt(masm_, "[ Allocate locals");
int locals_count = info->scope()->num_stack_slots();
......
......@@ -173,7 +173,6 @@ bool LCodeGen::GeneratePrologue() {
__ Prologue(info()->IsStub() ? BUILD_STUB_FRAME : BUILD_FUNCTION_FRAME);
frame_is_built_ = true;
info_->AddNoFrameRange(0, masm_->pc_offset());
__ LoadConstantPoolPointerRegister();
}
// Reserve space for the stack slots needed by the code.
......
......@@ -888,6 +888,16 @@ void MacroAssembler::VmovLow(DwVfpRegister dst, Register src) {
}
void MacroAssembler::LoadConstantPoolPointerRegister() {
if (FLAG_enable_ool_constant_pool) {
int constant_pool_offset = Code::kConstantPoolOffset - Code::kHeaderSize -
pc_offset() - Instruction::kPCReadOffset;
ASSERT(ImmediateFitsAddrMode2Instruction(constant_pool_offset));
ldr(pp, MemOperand(pc, constant_pool_offset));
}
}
void MacroAssembler::Prologue(PrologueFrameMode frame_mode) {
if (frame_mode == BUILD_STUB_FRAME) {
PushFixedFrame();
......@@ -912,22 +922,20 @@ void MacroAssembler::Prologue(PrologueFrameMode frame_mode) {
add(fp, sp, Operand(StandardFrameConstants::kFixedFrameSizeFromFp));
}
}
}
void MacroAssembler::LoadConstantPoolPointerRegister() {
if (FLAG_enable_ool_constant_pool) {
int constant_pool_offset =
Code::kConstantPoolOffset - Code::kHeaderSize - pc_offset() - 8;
ASSERT(ImmediateFitsAddrMode2Instruction(constant_pool_offset));
ldr(pp, MemOperand(pc, constant_pool_offset));
LoadConstantPoolPointerRegister();
set_constant_pool_available(true);
}
}
void MacroAssembler::EnterFrame(StackFrame::Type type) {
void MacroAssembler::EnterFrame(StackFrame::Type type,
bool load_constant_pool) {
// r0-r3: preserved
PushFixedFrame();
if (FLAG_enable_ool_constant_pool && load_constant_pool) {
LoadConstantPoolPointerRegister();
}
mov(ip, Operand(Smi::FromInt(type)));
push(ip);
mov(ip, Operand(CodeObject()));
......@@ -975,6 +983,7 @@ void MacroAssembler::EnterExitFrame(bool save_doubles, int stack_space) {
}
if (FLAG_enable_ool_constant_pool) {
str(pp, MemOperand(fp, ExitFrameConstants::kConstantPoolOffset));
LoadConstantPoolPointerRegister();
}
mov(ip, Operand(CodeObject()));
str(ip, MemOperand(fp, ExitFrameConstants::kCodeOffset));
......
......@@ -540,9 +540,6 @@ class MacroAssembler: public Assembler {
// Generates function and stub prologue code.
void Prologue(PrologueFrameMode frame_mode);
// Loads the constant pool pointer (pp) register.
void LoadConstantPoolPointerRegister();
// Enter exit frame.
// stack_space - extra stack space, used for alignment before call to C.
void EnterExitFrame(bool save_doubles, int stack_space = 0);
......@@ -1387,7 +1384,7 @@ class MacroAssembler: public Assembler {
}
// Activation support.
void EnterFrame(StackFrame::Type type);
void EnterFrame(StackFrame::Type type, bool load_constant_pool = false);
// Returns the pc offset at which the frame ends.
int LeaveFrame(StackFrame::Type type);
......@@ -1464,6 +1461,9 @@ class MacroAssembler: public Assembler {
MemOperand SafepointRegisterSlot(Register reg);
MemOperand SafepointRegistersAndDoublesSlot(Register reg);
// Loads the constant pool pointer (pp) register.
void LoadConstantPoolPointerRegister();
bool generating_stub_;
bool has_frame_;
// This handle will be patched with the code object on installation.
......@@ -1513,6 +1513,70 @@ class CodePatcher {
};
class FrameAndConstantPoolScope {
public:
FrameAndConstantPoolScope(MacroAssembler* masm, StackFrame::Type type)
: masm_(masm),
type_(type),
old_has_frame_(masm->has_frame()),
old_constant_pool_available_(masm->is_constant_pool_available()) {
masm->set_has_frame(true);
masm->set_constant_pool_available(true);
if (type_ != StackFrame::MANUAL && type_ != StackFrame::NONE) {
masm->EnterFrame(type, !old_constant_pool_available_);
}
}
~FrameAndConstantPoolScope() {
masm_->LeaveFrame(type_);
masm_->set_has_frame(old_has_frame_);
masm_->set_constant_pool_available(old_constant_pool_available_);
}
// Normally we generate the leave-frame code when this object goes
// out of scope. Sometimes we may need to generate the code somewhere else
// in addition. Calling this will achieve that, but the object stays in
// scope, the MacroAssembler is still marked as being in a frame scope, and
// the code will be generated again when it goes out of scope.
void GenerateLeaveFrame() {
ASSERT(type_ != StackFrame::MANUAL && type_ != StackFrame::NONE);
masm_->LeaveFrame(type_);
}
private:
MacroAssembler* masm_;
StackFrame::Type type_;
bool old_has_frame_;
bool old_constant_pool_available_;
DISALLOW_IMPLICIT_CONSTRUCTORS(FrameAndConstantPoolScope);
};
// Class for scoping the the unavailability of constant pool access.
class ConstantPoolUnavailableScope {
public:
explicit ConstantPoolUnavailableScope(MacroAssembler* masm)
: masm_(masm),
old_constant_pool_available_(masm->is_constant_pool_available()) {
if (FLAG_enable_ool_constant_pool) {
masm_->set_constant_pool_available(false);
}
}
~ConstantPoolUnavailableScope() {
if (FLAG_enable_ool_constant_pool) {
masm_->set_constant_pool_available(old_constant_pool_available_);
}
}
private:
MacroAssembler* masm_;
int old_constant_pool_available_;
DISALLOW_IMPLICIT_CONSTRUCTORS(ConstantPoolUnavailableScope);
};
// -----------------------------------------------------------------------------
// Static helper functions.
......
......@@ -1162,7 +1162,7 @@ void LoadStubCompiler::GenerateLoadInterceptor(
// Save necessary data before invoking an interceptor.
// Requires a frame to make GC aware of pushed pointers.
{
FrameScope frame_scope(masm(), StackFrame::INTERNAL);
FrameAndConstantPoolScope frame_scope(masm(), StackFrame::INTERNAL);
if (must_preserve_receiver_reg) {
__ Push(receiver(), holder_reg, this->name());
} else {
......@@ -1262,7 +1262,7 @@ void StoreStubCompiler::GenerateStoreViaSetter(
// -- lr : return address
// -----------------------------------
{
FrameScope scope(masm, StackFrame::INTERNAL);
FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
// Save value register, so we can restore it later.
__ push(value());
......@@ -1377,7 +1377,7 @@ void LoadStubCompiler::GenerateLoadViaGetter(MacroAssembler* masm,
// -- lr : return address
// -----------------------------------
{
FrameScope scope(masm, StackFrame::INTERNAL);
FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
if (!getter.is_null()) {
// Call the JavaScript getter with the receiver on the stack.
......
......@@ -124,6 +124,7 @@ class FrameScope {
// scope, the MacroAssembler is still marked as being in a frame scope, and
// the code will be generated again when it goes out of scope.
void GenerateLeaveFrame() {
ASSERT(type_ != StackFrame::MANUAL && type_ != StackFrame::NONE);
masm_->LeaveFrame(type_);
}
......
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