Simplify and fix code aging.

Making the code size predictable is hard, and to make things even more
complicated, the start of a function can contain various stuff like calls to a
profiling hook, receiver adjustment or dynamic frame alignment. Instead of
tackling all these problems separately, we now simply record the offset where
patching should happen later in the Code object itself.

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

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@13081 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
svenpanne@chromium.org 2012-11-29 07:38:00 +00:00
parent 50dcf96e63
commit 5a4e0f1c79
23 changed files with 68 additions and 202 deletions

View File

@ -615,29 +615,6 @@ static byte* GetNoCodeAgeSequence(uint32_t* length) {
}
byte* Code::FindPlatformCodeAgeSequence() {
byte* start = instruction_start();
uint32_t young_length;
byte* young_sequence = GetNoCodeAgeSequence(&young_length);
if (!memcmp(start, young_sequence, young_length) ||
Memory::uint32_at(start) == kCodeAgePatchFirstInstruction) {
return start;
} else {
byte* start_after_strict = NULL;
if (kind() == FUNCTION) {
start_after_strict = start + kSizeOfFullCodegenStrictModePrologue;
} else {
ASSERT(kind() == OPTIMIZED_FUNCTION);
start_after_strict = start + kSizeOfOptimizedStrictModePrologue;
}
ASSERT(!memcmp(start_after_strict, young_sequence, young_length) ||
Memory::uint32_at(start_after_strict) ==
kCodeAgePatchFirstInstruction);
return start_after_strict;
}
}
bool Code::IsYoungSequence(byte* sequence) {
uint32_t young_length;
byte* young_sequence = GetNoCodeAgeSequence(&young_length);

View File

@ -34,9 +34,6 @@
namespace v8 {
namespace internal {
static const int kSizeOfFullCodegenStrictModePrologue = 16;
static const int kSizeOfOptimizedStrictModePrologue = 16;
// Forward declarations
class CompilationInfo;

View File

@ -149,15 +149,12 @@ void FullCodeGenerator::Generate() {
// function calls.
if (!info->is_classic_mode() || info->is_native()) {
Label ok;
Label begin;
__ bind(&begin);
__ cmp(r5, Operand(0));
__ b(eq, &ok);
int receiver_offset = info->scope()->num_parameters() * kPointerSize;
__ LoadRoot(r2, Heap::kUndefinedValueRootIndex);
__ str(r2, MemOperand(sp, receiver_offset));
__ bind(&ok);
ASSERT_EQ(kSizeOfFullCodegenStrictModePrologue, ok.pos() - begin.pos());
}
// Open a frame scope to indicate that there is a frame on the stack. The
@ -167,6 +164,7 @@ void FullCodeGenerator::Generate() {
int locals_count = info->scope()->num_stack_slots();
info->set_prologue_offset(masm_->pc_offset());
// The following four instructions must remain together and unmodified for
// code aging to work properly.
__ stm(db_w, sp, r1.bit() | cp.bit() | fp.bit() | lr.bit());

View File

@ -138,17 +138,16 @@ bool LCodeGen::GeneratePrologue() {
// function calls.
if (!info_->is_classic_mode() || info_->is_native()) {
Label ok;
Label begin;
__ bind(&begin);
__ cmp(r5, Operand(0));
__ b(eq, &ok);
int receiver_offset = scope()->num_parameters() * kPointerSize;
__ LoadRoot(r2, Heap::kUndefinedValueRootIndex);
__ str(r2, MemOperand(sp, receiver_offset));
__ bind(&ok);
ASSERT_EQ(kSizeOfOptimizedStrictModePrologue, ok.pos() - begin.pos());
}
info()->set_prologue_offset(masm_->pc_offset());
// The following three instructions must remain together and unmodified for
// code aging to work properly.
__ stm(db_w, sp, r1.bit() | cp.bit() | fp.bit() | lr.bit());

View File

@ -107,6 +107,7 @@ Handle<Code> CodeGenerator::MakeCodeEpilogue(MacroAssembler* masm,
if (!code.is_null()) {
isolate->counters()->total_compiled_code_size()->Increment(
code->instruction_size());
code->set_prologue_offset(info->prologue_offset());
}
return code;
}

View File

@ -52,57 +52,53 @@ namespace internal {
CompilationInfo::CompilationInfo(Handle<Script> script, Zone* zone)
: isolate_(script->GetIsolate()),
flags_(LanguageModeField::encode(CLASSIC_MODE)),
function_(NULL),
scope_(NULL),
global_scope_(NULL),
: flags_(LanguageModeField::encode(CLASSIC_MODE)),
script_(script),
extension_(NULL),
pre_parse_data_(NULL),
osr_ast_id_(BailoutId::None()),
zone_(zone),
deferred_handles_(NULL) {
Initialize(BASE);
osr_ast_id_(BailoutId::None()) {
Initialize(zone);
}
CompilationInfo::CompilationInfo(Handle<SharedFunctionInfo> shared_info,
Zone* zone)
: isolate_(shared_info->GetIsolate()),
flags_(LanguageModeField::encode(CLASSIC_MODE) |
IsLazy::encode(true)),
function_(NULL),
scope_(NULL),
global_scope_(NULL),
: flags_(LanguageModeField::encode(CLASSIC_MODE) | IsLazy::encode(true)),
shared_info_(shared_info),
script_(Handle<Script>(Script::cast(shared_info->script()))),
extension_(NULL),
pre_parse_data_(NULL),
osr_ast_id_(BailoutId::None()),
zone_(zone),
deferred_handles_(NULL) {
Initialize(BASE);
osr_ast_id_(BailoutId::None()) {
Initialize(zone);
}
CompilationInfo::CompilationInfo(Handle<JSFunction> closure, Zone* zone)
: isolate_(closure->GetIsolate()),
flags_(LanguageModeField::encode(CLASSIC_MODE) |
IsLazy::encode(true)),
function_(NULL),
scope_(NULL),
global_scope_(NULL),
: flags_(LanguageModeField::encode(CLASSIC_MODE) | IsLazy::encode(true)),
closure_(closure),
shared_info_(Handle<SharedFunctionInfo>(closure->shared())),
script_(Handle<Script>(Script::cast(shared_info_->script()))),
extension_(NULL),
pre_parse_data_(NULL),
context_(closure->context()),
osr_ast_id_(BailoutId::None()),
zone_(zone),
deferred_handles_(NULL) {
Initialize(BASE);
osr_ast_id_(BailoutId::None()) {
Initialize(zone);
}
void CompilationInfo::Initialize(Zone* zone) {
isolate_ = script_->GetIsolate();
function_ = NULL;
scope_ = NULL;
global_scope_ = NULL;
extension_ = NULL;
pre_parse_data_ = NULL;
zone_ = zone;
deferred_handles_ = NULL;
prologue_offset_ = kPrologueOffsetNotSet;
mode_ = V8::UseCrankshaft() ? BASE : NONOPT;
if (script_->type()->value() == Script::TYPE_NATIVE) {
MarkAsNative();
}
if (!shared_info_.is_null()) {
ASSERT(language_mode() == CLASSIC_MODE);
SetLanguageMode(shared_info_->language_mode());
}
set_bailout_reason("unknown");
}

View File

@ -35,6 +35,8 @@
namespace v8 {
namespace internal {
static const int kPrologueOffsetNotSet = -1;
class ScriptDataImpl;
// CompilationInfo encapsulates some information known at compile time. It
@ -186,6 +188,16 @@ class CompilationInfo {
const char* bailout_reason() const { return bailout_reason_; }
void set_bailout_reason(const char* reason) { bailout_reason_ = reason; }
int prologue_offset() const {
ASSERT_NE(kPrologueOffsetNotSet, prologue_offset_);
return prologue_offset_;
}
void set_prologue_offset(int prologue_offset) {
ASSERT_EQ(kPrologueOffsetNotSet, prologue_offset_);
prologue_offset_ = prologue_offset;
}
private:
Isolate* isolate_;
@ -200,18 +212,7 @@ class CompilationInfo {
NONOPT
};
void Initialize(Mode mode) {
mode_ = V8::UseCrankshaft() ? mode : NONOPT;
ASSERT(!script_.is_null());
if (script_->type()->value() == Script::TYPE_NATIVE) {
MarkAsNative();
}
if (!shared_info_.is_null()) {
ASSERT(language_mode() == CLASSIC_MODE);
SetLanguageMode(shared_info_->language_mode());
}
set_bailout_reason("unknown");
}
void Initialize(Zone* zone);
void SetMode(Mode mode) {
ASSERT(V8::UseCrankshaft());
@ -285,6 +286,8 @@ class CompilationInfo {
const char* bailout_reason_;
int prologue_offset_;
DISALLOW_COPY_AND_ASSIGN(CompilationInfo);
};

View File

@ -3795,6 +3795,7 @@ MaybeObject* Heap::CreateCode(const CodeDesc& desc,
code->set_handler_table(empty_fixed_array(), SKIP_WRITE_BARRIER);
code->set_gc_metadata(Smi::FromInt(0));
code->set_ic_age(global_ic_age_);
code->set_prologue_offset(kPrologueOffsetNotSet);
// Allow self references to created code object by patching the handle to
// point to the newly allocated Code object.
if (!self_reference.is_null()) {

View File

@ -872,42 +872,6 @@ static byte* GetNoCodeAgeSequence(uint32_t* length) {
}
byte* Code::FindPlatformCodeAgeSequence() {
byte* start = instruction_start();
uint32_t young_length;
byte* young_sequence = GetNoCodeAgeSequence(&young_length);
if (!memcmp(start, young_sequence, young_length) ||
*start == kCallOpcode) {
return start;
} else {
if (kind() == FUNCTION) {
byte* start_after_strict =
start + kSizeOfFullCodegenStrictModePrologue;
ASSERT(!memcmp(start_after_strict, young_sequence, young_length) ||
start[kSizeOfFullCodegenStrictModePrologue] == kCallOpcode);
return start_after_strict;
} else {
ASSERT(kind() == OPTIMIZED_FUNCTION);
start = instruction_start() + kSizeOfOptimizedStrictModePrologue;
if (!memcmp(start, young_sequence, young_length) ||
*start == kCallOpcode) {
return start;
}
start = instruction_start() + kSizeOfOptimizedAlignStackPrologue;
if (!memcmp(start, young_sequence, young_length) ||
*start == kCallOpcode) {
return start;
}
start = instruction_start() + kSizeOfOptimizedAlignStackPrologue +
kSizeOfOptimizedStrictModePrologue;
ASSERT(!memcmp(start, young_sequence, young_length) ||
*start == kCallOpcode);
return start;
}
}
}
bool Code::IsYoungSequence(byte* sequence) {
uint32_t young_length;
byte* young_sequence = GetNoCodeAgeSequence(&young_length);

View File

@ -37,10 +37,6 @@ namespace internal {
// Forward declarations
class CompilationInfo;
static const int kSizeOfFullCodegenStrictModePrologue = 34;
static const int kSizeOfOptimizedStrictModePrologue = 12;
static const int kSizeOfOptimizedAlignStackPrologue = 44;
// -------------------------------------------------------------------------
// CodeGenerator

View File

@ -138,8 +138,6 @@ void FullCodeGenerator::Generate() {
// function calls.
if (!info->is_classic_mode() || info->is_native()) {
Label ok;
Label start;
__ bind(&start);
__ test(ecx, ecx);
__ j(zero, &ok, Label::kNear);
// +1 for return address.
@ -151,8 +149,6 @@ void FullCodeGenerator::Generate() {
__ mov(Operand(esp, receiver_offset),
Immediate(isolate()->factory()->undefined_value()));
__ bind(&ok);
ASSERT(!FLAG_age_code ||
(kSizeOfFullCodegenStrictModePrologue == ok.pos() - start.pos()));
}
// Open a frame scope to indicate that there is a frame on the stack. The
@ -160,6 +156,7 @@ void FullCodeGenerator::Generate() {
// the frame (that is done below).
FrameScope frame_scope(masm_, StackFrame::MANUAL);
info->set_prologue_offset(masm_->pc_offset());
__ push(ebp); // Caller's frame pointer.
__ mov(ebp, esp);
__ push(esi); // Callee's context.

View File

@ -140,8 +140,6 @@ bool LCodeGen::GeneratePrologue() {
// receiver object). ecx is zero for method calls and non-zero for
// function calls.
if (!info_->is_classic_mode() || info_->is_native()) {
Label begin;
__ bind(&begin);
Label ok;
__ test(ecx, Operand(ecx));
__ j(zero, &ok, Label::kNear);
@ -150,14 +148,10 @@ bool LCodeGen::GeneratePrologue() {
__ mov(Operand(esp, receiver_offset),
Immediate(isolate()->factory()->undefined_value()));
__ bind(&ok);
ASSERT(!FLAG_age_code ||
(kSizeOfOptimizedStrictModePrologue == ok.pos() - begin.pos()));
}
if (dynamic_frame_alignment_) {
Label begin;
__ bind(&begin);
// Move state of dynamic frame alignment into edx.
__ mov(edx, Immediate(kNoAlignmentPadding));
@ -180,11 +174,9 @@ bool LCodeGen::GeneratePrologue() {
__ j(not_zero, &align_loop, Label::kNear);
__ mov(Operand(ebx, 0), Immediate(kAlignmentZapValue));
__ bind(&do_not_pad);
ASSERT(!FLAG_age_code ||
(kSizeOfOptimizedAlignStackPrologue ==
do_not_pad.pos() - begin.pos()));
}
info()->set_prologue_offset(masm_->pc_offset());
__ push(ebp); // Caller's frame pointer.
__ mov(ebp, esp);
__ push(esi); // Callee's context.

View File

@ -467,29 +467,6 @@ static byte* GetNoCodeAgeSequence(uint32_t* length) {
}
byte* Code::FindPlatformCodeAgeSequence() {
byte* start = instruction_start();
uint32_t young_length;
byte* young_sequence = GetNoCodeAgeSequence(&young_length);
if (!memcmp(start, young_sequence, young_length) ||
Memory::uint32_at(start) == kCodeAgePatchFirstInstruction) {
return start;
} else {
byte* start_after_strict = NULL;
if (kind() == FUNCTION) {
start_after_strict = start + kSizeOfFullCodegenStrictModePrologue;
} else {
ASSERT(kind() == OPTIMIZED_FUNCTION);
start_after_strict = start + kSizeOfOptimizedStrictModePrologue;
}
ASSERT(!memcmp(start_after_strict, young_sequence, young_length) ||
Memory::uint32_at(start_after_strict) ==
kCodeAgePatchFirstInstruction);
return start_after_strict;
}
}
bool Code::IsYoungSequence(byte* sequence) {
uint32_t young_length;
byte* young_sequence = GetNoCodeAgeSequence(&young_length);

View File

@ -36,9 +36,6 @@
namespace v8 {
namespace internal {
static const int kSizeOfFullCodegenStrictModePrologue = 16;
static const int kSizeOfOptimizedStrictModePrologue = 16;
// Forward declarations
class CompilationInfo;

View File

@ -158,14 +158,11 @@ void FullCodeGenerator::Generate() {
// function calls.
if (!info->is_classic_mode() || info->is_native()) {
Label ok;
Label begin;
__ bind(&begin);
__ Branch(&ok, eq, t1, Operand(zero_reg));
int receiver_offset = info->scope()->num_parameters() * kPointerSize;
__ LoadRoot(a2, Heap::kUndefinedValueRootIndex);
__ sw(a2, MemOperand(sp, receiver_offset));
__ bind(&ok);
ASSERT_EQ(kSizeOfFullCodegenStrictModePrologue, ok.pos() - begin.pos());
}
// Open a frame scope to indicate that there is a frame on the stack. The
@ -175,6 +172,7 @@ void FullCodeGenerator::Generate() {
int locals_count = info->scope()->num_stack_slots();
info->set_prologue_offset(masm_->pc_offset());
// The following three instructions must remain together and unmodified for
// code aging to work properly.
__ Push(ra, fp, cp, a1);

View File

@ -136,17 +136,15 @@ bool LCodeGen::GeneratePrologue() {
// function calls.
if (!info_->is_classic_mode() || info_->is_native()) {
Label ok;
Label begin;
__ bind(&begin);
__ Branch(&ok, eq, t1, Operand(zero_reg));
int receiver_offset = scope()->num_parameters() * kPointerSize;
__ LoadRoot(a2, Heap::kUndefinedValueRootIndex);
__ sw(a2, MemOperand(sp, receiver_offset));
__ bind(&ok);
ASSERT_EQ(kSizeOfOptimizedStrictModePrologue, ok.pos() - begin.pos());
}
info()->set_prologue_offset(masm_->pc_offset());
// The following three instructions must remain together and unmodified for
// code aging to work properly.
__ Push(ra, fp, cp, a1);

View File

@ -4578,6 +4578,7 @@ JSMessageObject* JSMessageObject::cast(Object* obj) {
INT_ACCESSORS(Code, instruction_size, kInstructionSizeOffset)
INT_ACCESSORS(Code, prologue_offset, kPrologueOffset)
ACCESSORS(Code, relocation_info, ByteArray, kRelocationInfoOffset)
ACCESSORS(Code, handler_table, FixedArray, kHandlerTableOffset)
ACCESSORS(Code, deoptimization_data, FixedArray, kDeoptimizationDataOffset)

View File

@ -8875,11 +8875,10 @@ bool Code::IsOld() {
byte* Code::FindCodeAgeSequence() {
return FLAG_age_code &&
strlen(FLAG_stop_at) == 0 &&
!ProfileEntryHookStub::HasEntryHook() &&
prologue_offset() != kPrologueOffsetNotSet &&
(kind() == OPTIMIZED_FUNCTION ||
(kind() == FUNCTION && !has_debug_break_slots()))
? FindPlatformCodeAgeSequence()
? instruction_start() + prologue_offset()
: NULL;
}

View File

@ -4325,6 +4325,11 @@ class Code: public HeapObject {
inline void set_ic_age(int count);
inline int ic_age();
// [prologue_offset]: Offset of the function prologue, used for aging
// FUNCTIONs and OPTIMIZED_FUNCTIONs.
inline int prologue_offset();
inline void set_prologue_offset(int offset);
// Unchecked accessors to be used during GC.
inline ByteArray* unchecked_relocation_info();
inline FixedArray* unchecked_deoptimization_data();
@ -4593,8 +4598,10 @@ class Code: public HeapObject {
static const int kKindSpecificFlags1Offset = kFlagsOffset + kIntSize;
static const int kKindSpecificFlags2Offset =
kKindSpecificFlags1Offset + kIntSize;
// Note: We might be able to squeeze this into the flags above.
static const int kPrologueOffset = kKindSpecificFlags2Offset + kIntSize;
static const int kHeaderPaddingStart = kKindSpecificFlags2Offset + kIntSize;
static const int kHeaderPaddingStart = kPrologueOffset + kIntSize;
// Add padding to align the instruction start following right after
// the Code object header.
@ -4688,7 +4695,6 @@ class Code: public HeapObject {
static Code* GetCodeAgeStub(Age age, MarkingParity parity);
// Code aging -- platform-specific
byte* FindPlatformCodeAgeSequence();
static void PatchPlatformCodeAge(byte* sequence, Age age,
MarkingParity parity);

View File

@ -681,28 +681,6 @@ static byte* GetNoCodeAgeSequence(uint32_t* length) {
}
byte* Code::FindPlatformCodeAgeSequence() {
byte* start = instruction_start();
uint32_t young_length;
byte* young_sequence = GetNoCodeAgeSequence(&young_length);
if (!memcmp(start, young_sequence, young_length) ||
*start == kCallOpcode) {
return start;
} else {
byte* start_after_strict = NULL;
if (kind() == FUNCTION) {
start_after_strict = start + kSizeOfFullCodegenStrictModePrologue;
} else {
ASSERT(kind() == OPTIMIZED_FUNCTION);
start_after_strict = start + kSizeOfOptimizedStrictModePrologue;
}
ASSERT(!memcmp(start_after_strict, young_sequence, young_length) ||
*start_after_strict == kCallOpcode);
return start_after_strict;
}
}
bool Code::IsYoungSequence(byte* sequence) {
uint32_t young_length;
byte* young_sequence = GetNoCodeAgeSequence(&young_length);

View File

@ -39,9 +39,6 @@ class CompilationInfo;
enum TypeofState { INSIDE_TYPEOF, NOT_INSIDE_TYPEOF };
static const int kSizeOfFullCodegenStrictModePrologue = 14;
static const int kSizeOfOptimizedStrictModePrologue = 14;
// -------------------------------------------------------------------------
// CodeGenerator

View File

@ -138,8 +138,6 @@ void FullCodeGenerator::Generate() {
// function calls.
if (!info->is_classic_mode() || info->is_native()) {
Label ok;
Label begin;
__ bind(&begin);
__ testq(rcx, rcx);
__ j(zero, &ok, Label::kNear);
// +1 for return address.
@ -147,8 +145,6 @@ void FullCodeGenerator::Generate() {
__ LoadRoot(kScratchRegister, Heap::kUndefinedValueRootIndex);
__ movq(Operand(rsp, receiver_offset), kScratchRegister);
__ bind(&ok);
ASSERT(!FLAG_age_code ||
(kSizeOfFullCodegenStrictModePrologue == ok.pos() - begin.pos()));
}
// Open a frame scope to indicate that there is a frame on the stack. The
@ -156,6 +152,7 @@ void FullCodeGenerator::Generate() {
// the frame (that is done below).
FrameScope frame_scope(masm_, StackFrame::MANUAL);
info->set_prologue_offset(masm_->pc_offset());
__ push(rbp); // Caller's frame pointer.
__ movq(rbp, rsp);
__ push(rsi); // Callee's context.

View File

@ -133,8 +133,6 @@ bool LCodeGen::GeneratePrologue() {
// object). rcx is zero for method calls and non-zero for function
// calls.
if (!info_->is_classic_mode() || info_->is_native()) {
Label begin;
__ bind(&begin);
Label ok;
__ testq(rcx, rcx);
__ j(zero, &ok, Label::kNear);
@ -143,10 +141,9 @@ bool LCodeGen::GeneratePrologue() {
__ LoadRoot(kScratchRegister, Heap::kUndefinedValueRootIndex);
__ movq(Operand(rsp, receiver_offset), kScratchRegister);
__ bind(&ok);
ASSERT(!FLAG_age_code ||
(kSizeOfOptimizedStrictModePrologue == ok.pos() - begin.pos()));
}
info()->set_prologue_offset(masm_->pc_offset());
__ push(rbp); // Caller's frame pointer.
__ movq(rbp, rsp);
__ push(rsi); // Callee's context.