Store both major and minor key on code stubs.

R=jkummerow@chromium.org

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

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@22505 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
yangguo@chromium.org 2014-07-21 13:10:14 +00:00
parent bc6ed15a5a
commit 3b9f5e86d4
14 changed files with 78 additions and 132 deletions

View File

@ -189,7 +189,7 @@ Handle<Code> CodeStub::GetCode() {
HandleScope scope(isolate());
Handle<Code> new_object = GenerateCode();
new_object->set_major_key(MajorKey());
new_object->set_stub_key(GetKey());
FinishCode(new_object);
RecordCodeGeneration(new_object);
@ -371,8 +371,8 @@ bool ICCompareStub::FindCodeInSpecialCache(Code** code_out) {
*code_out = Code::cast(*probe);
#ifdef DEBUG
Token::Value cached_op;
ICCompareStub::DecodeMinorKey((*code_out)->stub_info(), NULL, NULL, NULL,
&cached_op);
ICCompareStub::DecodeKey((*code_out)->stub_key(), NULL, NULL, NULL,
&cached_op);
ASSERT(op_ == cached_op);
#endif
return true;
@ -389,11 +389,11 @@ int ICCompareStub::MinorKey() const {
}
void ICCompareStub::DecodeMinorKey(int minor_key,
CompareIC::State* left_state,
CompareIC::State* right_state,
CompareIC::State* handler_state,
Token::Value* op) {
void ICCompareStub::DecodeKey(uint32_t stub_key, CompareIC::State* left_state,
CompareIC::State* right_state,
CompareIC::State* handler_state,
Token::Value* op) {
int minor_key = MinorKeyFromKey(stub_key);
if (left_state) {
*left_state =
static_cast<CompareIC::State>(LeftStateField::decode(minor_key));

View File

@ -154,9 +154,11 @@ class CodeStub BASE_EMBEDDED {
// Gets the major key from a code object that is a code stub or binary op IC.
static Major GetMajorKey(Code* code_stub) {
return static_cast<Major>(code_stub->major_key());
return MajorKeyFromKey(code_stub->stub_key());
}
static uint32_t NoCacheKey() { return MajorKeyBits::encode(NoCache); }
static const char* MajorName(Major major_key, bool allow_unknown_keys);
explicit CodeStub(Isolate* isolate) : isolate_(isolate) { }
@ -207,6 +209,12 @@ class CodeStub BASE_EMBEDDED {
virtual void PrintBaseName(OStream& os) const; // NOLINT
virtual void PrintState(OStream& os) const { ; } // NOLINT
// Computes the key based on major and minor.
uint32_t GetKey() {
ASSERT(static_cast<int>(MajorKey()) < NUMBER_OF_IDS);
return MinorKeyBits::encode(MinorKey()) | MajorKeyBits::encode(MajorKey());
}
private:
// Perform bookkeeping required after code generation when stub code is
// initially generated.
@ -235,13 +243,6 @@ class CodeStub BASE_EMBEDDED {
// If a stub uses a special cache override this.
virtual bool UseSpecialCache() { return false; }
// Computes the key based on major and minor.
uint32_t GetKey() {
ASSERT(static_cast<int>(MajorKey()) < NUMBER_OF_IDS);
return MinorKeyBits::encode(MinorKey()) |
MajorKeyBits::encode(MajorKey());
}
STATIC_ASSERT(NUMBER_OF_IDS < (1 << kStubMajorKeyBits));
class MajorKeyBits: public BitField<uint32_t, 0, kStubMajorKeyBits> {};
class MinorKeyBits: public BitField<uint32_t,
@ -830,15 +831,10 @@ class ICStub: public PlatformCodeStub {
virtual Code::Kind GetCodeKind() const { return kind_; }
virtual InlineCacheState GetICState() { return MONOMORPHIC; }
bool Describes(Code* code) {
return GetMajorKey(code) == MajorKey() && code->stub_info() == MinorKey();
}
bool Describes(Code* code) { return code->stub_key() == GetKey(); }
protected:
class KindBits: public BitField<Code::Kind, 0, 4> {};
virtual void FinishCode(Handle<Code> code) {
code->set_stub_info(MinorKey());
}
Code::Kind kind() const { return kind_; }
virtual int MinorKey() const { return KindBits::encode(kind_); }
@ -1366,11 +1362,9 @@ class ICCompareStub: public PlatformCodeStub {
void set_known_map(Handle<Map> map) { known_map_ = map; }
static void DecodeMinorKey(int minor_key,
CompareIC::State* left_state,
CompareIC::State* right_state,
CompareIC::State* handler_state,
Token::Value* op);
static void DecodeKey(uint32_t stub_key, CompareIC::State* left_state,
CompareIC::State* right_state,
CompareIC::State* handler_state, Token::Value* op);
virtual InlineCacheState GetICState();
@ -1380,10 +1374,6 @@ class ICCompareStub: public PlatformCodeStub {
class RightStateField: public BitField<int, 7, 4> { };
class HandlerStateField: public BitField<int, 11, 4> { };
virtual void FinishCode(Handle<Code> code) {
code->set_stub_info(MinorKey());
}
virtual CodeStub::Major MajorKey() const { return CompareIC; }
virtual int MinorKey() const;

View File

@ -373,7 +373,7 @@ bool BreakLocationIterator::IsStepInLocation(Isolate* isolate) {
Address target = original_rinfo()->target_address();
Handle<Code> target_code(Code::GetCodeFromTargetAddress(target));
if (target_code->kind() == Code::STUB) {
return target_code->major_key() == CodeStub::CallFunction;
return CodeStub::GetMajorKey(*target_code) == CodeStub::CallFunction;
}
return target_code->is_call_stub();
}
@ -398,7 +398,8 @@ void BreakLocationIterator::PrepareStepIn(Isolate* isolate) {
}
bool is_call_function_stub =
(maybe_call_function_stub->kind() == Code::STUB &&
maybe_call_function_stub->major_key() == CodeStub::CallFunction);
CodeStub::GetMajorKey(*maybe_call_function_stub) ==
CodeStub::CallFunction);
// Step in through construct call requires no changes to the running code.
// Step in through getters/setters should already be prepared as well
@ -475,7 +476,7 @@ static Handle<Code> DebugBreakForIC(Handle<Code> code, RelocInfo::Mode mode) {
}
}
if (code->kind() == Code::STUB) {
ASSERT(code->major_key() == CodeStub::CallFunction);
ASSERT(CodeStub::GetMajorKey(*code) == CodeStub::CallFunction);
return isolate->builtins()->CallFunctionStub_DebugBreak();
}
@ -1419,7 +1420,8 @@ void Debug::PrepareStep(StepAction step_action,
Code::GetCodeFromTargetAddress(original_target);
}
if ((maybe_call_function_stub->kind() == Code::STUB &&
maybe_call_function_stub->major_key() == CodeStub::CallFunction) ||
CodeStub::GetMajorKey(maybe_call_function_stub) ==
CodeStub::CallFunction) ||
maybe_call_function_stub->kind() == Code::CALL_IC) {
// Save reference to the code as we may need it to find out arguments
// count for 'step in' later.
@ -1499,7 +1501,8 @@ void Debug::PrepareStep(StepAction step_action,
CodeStub::MinorKeyFromKey(key));
ASSERT(is_call_ic ||
call_function_stub->major_key() == CodeStub::MajorKeyFromKey(key));
CodeStub::GetMajorKey(*call_function_stub) ==
CodeStub::MajorKeyFromKey(key));
// Find target function on the expression stack.
// Expression stack looks like this (top to bottom):

View File

@ -1549,7 +1549,7 @@ void Deoptimizer::DoComputeCompiledStubFrame(TranslationIterator* iterator,
//
CHECK(compiled_code_->is_hydrogen_stub());
int major_key = compiled_code_->major_key();
int major_key = CodeStub::GetMajorKey(compiled_code_);
CodeStubInterfaceDescriptor* descriptor =
isolate_->code_stub_interface_descriptor(major_key);

View File

@ -1499,8 +1499,8 @@ void V8HeapExplorer::TagBuiltinCodeObject(Code* code, const char* name) {
void V8HeapExplorer::TagCodeObject(Code* code) {
if (code->kind() == Code::STUB) {
TagObject(code, names_->GetFormatted(
"(%s code)", CodeStub::MajorName(
static_cast<CodeStub::Major>(code->major_key()), true)));
"(%s code)", CodeStub::MajorName(
CodeStub::GetMajorKey(code), true)));
}
}

View File

@ -514,11 +514,10 @@ void CompareIC::Clear(Isolate* isolate,
Address address,
Code* target,
ConstantPoolArray* constant_pool) {
ASSERT(target->major_key() == CodeStub::CompareIC);
ASSERT(CodeStub::GetMajorKey(target) == CodeStub::CompareIC);
CompareIC::State handler_state;
Token::Value op;
ICCompareStub::DecodeMinorKey(target->stub_info(), NULL, NULL,
&handler_state, &op);
ICCompareStub::DecodeKey(target->stub_key(), NULL, NULL, &handler_state, &op);
// Only clear CompareICs that can retain objects.
if (handler_state != KNOWN_OBJECT) return;
SetTargetAtAddress(address, GetRawUninitialized(isolate, op), constant_pool);
@ -2756,15 +2755,12 @@ Type* CompareIC::StateToType(
}
void CompareIC::StubInfoToType(int stub_minor_key,
Type** left_type,
Type** right_type,
Type** overall_type,
Handle<Map> map,
Zone* zone) {
void CompareIC::StubInfoToType(uint32_t stub_key, Type** left_type,
Type** right_type, Type** overall_type,
Handle<Map> map, Zone* zone) {
State left_state, right_state, handler_state;
ICCompareStub::DecodeMinorKey(stub_minor_key, &left_state, &right_state,
&handler_state, NULL);
ICCompareStub::DecodeKey(stub_key, &left_state, &right_state, &handler_state,
NULL);
*left_type = StateToType(zone, left_state);
*right_type = StateToType(zone, right_state);
*overall_type = StateToType(zone, handler_state, map);
@ -2880,8 +2876,8 @@ CompareIC::State CompareIC::TargetState(State old_state,
Code* CompareIC::UpdateCaches(Handle<Object> x, Handle<Object> y) {
HandleScope scope(isolate());
State previous_left, previous_right, previous_state;
ICCompareStub::DecodeMinorKey(target()->stub_info(), &previous_left,
&previous_right, &previous_state, NULL);
ICCompareStub::DecodeKey(target()->stub_key(), &previous_left,
&previous_right, &previous_state, NULL);
State new_left = NewInputState(previous_left, x);
State new_right = NewInputState(previous_right, y);
State state = TargetState(previous_state, previous_left, previous_right,

View File

@ -951,12 +951,9 @@ class CompareIC: public IC {
State state,
Handle<Map> map = Handle<Map>());
static void StubInfoToType(int stub_minor_key,
Type** left_type,
Type** right_type,
Type** overall_type,
Handle<Map> map,
Zone* zone);
static void StubInfoToType(uint32_t stub_key, Type** left_type,
Type** right_type, Type** overall_type,
Handle<Map> map, Zone* zone);
CompareIC(Isolate* isolate, Token::Value op)
: IC(EXTRA_CALL_FRAME, isolate), op_(op) { }

View File

@ -1638,7 +1638,7 @@ static const char* DropFrames(Vector<StackFrame*> frames,
isolate->builtins()->builtin(Builtins::kReturn_DebugBreak)) {
*mode = LiveEdit::FRAME_DROPPED_IN_RETURN_CALL;
} else if (pre_top_frame_code->kind() == Code::STUB &&
pre_top_frame_code->major_key() == CodeStub::CEntry) {
CodeStub::GetMajorKey(pre_top_frame_code) == CodeStub::CEntry) {
// Entry from our unit tests on 'debugger' statement.
// It's fine, we support this case.
*mode = LiveEdit::FRAME_DROPPED_IN_DIRECT_CALL;

View File

@ -639,6 +639,8 @@ void Code::CodeVerify() {
last_gc_pc = it.rinfo()->pc();
}
}
CHECK(raw_type_feedback_info()->IsUndefined() ||
raw_type_feedback_info()->IsSmi() == IsCodeStubOrIC());
}

View File

@ -4621,6 +4621,15 @@ Code::Kind Code::kind() {
}
bool Code::IsCodeStubOrIC() {
return kind() == STUB || kind() == HANDLER || kind() == LOAD_IC ||
kind() == KEYED_LOAD_IC || kind() == CALL_IC || kind() == STORE_IC ||
kind() == KEYED_STORE_IC || kind() == BINARY_OP_IC ||
kind() == COMPARE_IC || kind() == COMPARE_NIL_IC ||
kind() == TO_BOOLEAN_IC;
}
InlineCacheState Code::ic_state() {
InlineCacheState result = ExtractICStateFromFlags(flags());
// Only allow uninitialized or debugger states for non-IC code
@ -4673,37 +4682,6 @@ inline void Code::set_is_crankshafted(bool value) {
}
int Code::major_key() {
ASSERT(has_major_key());
return StubMajorKeyField::decode(
READ_UINT32_FIELD(this, kKindSpecificFlags2Offset));
}
void Code::set_major_key(int major) {
ASSERT(has_major_key());
ASSERT(0 <= major && major < 256);
int previous = READ_UINT32_FIELD(this, kKindSpecificFlags2Offset);
int updated = StubMajorKeyField::update(previous, major);
WRITE_UINT32_FIELD(this, kKindSpecificFlags2Offset, updated);
}
bool Code::has_major_key() {
return kind() == STUB ||
kind() == HANDLER ||
kind() == BINARY_OP_IC ||
kind() == COMPARE_IC ||
kind() == COMPARE_NIL_IC ||
kind() == LOAD_IC ||
kind() == KEYED_LOAD_IC ||
kind() == STORE_IC ||
kind() == CALL_IC ||
kind() == KEYED_STORE_IC ||
kind() == TO_BOOLEAN_IC;
}
bool Code::optimizable() {
ASSERT_EQ(FUNCTION, kind());
return READ_BYTE_FIELD(this, kOptimizableOffset) == 1;
@ -6130,7 +6108,7 @@ void Code::WipeOutHeader() {
WRITE_FIELD(this, kHandlerTableOffset, NULL);
WRITE_FIELD(this, kDeoptimizationDataOffset, NULL);
WRITE_FIELD(this, kConstantPoolOffset, NULL);
// Do not wipe out e.g. a minor key.
// Do not wipe out major/minor keys on a code stub or IC
if (!READ_FIELD(this, kTypeFeedbackInfoOffset)->IsSmi()) {
WRITE_FIELD(this, kTypeFeedbackInfoOffset, NULL);
}
@ -6151,24 +6129,15 @@ void Code::set_type_feedback_info(Object* value, WriteBarrierMode mode) {
}
int Code::stub_info() {
ASSERT(kind() == COMPARE_IC || kind() == COMPARE_NIL_IC ||
kind() == BINARY_OP_IC || kind() == LOAD_IC || kind() == CALL_IC);
return Smi::cast(raw_type_feedback_info())->value();
uint32_t Code::stub_key() {
ASSERT(IsCodeStubOrIC());
return Smi::cast(raw_type_feedback_info())->value() - Smi::kMinValue;
}
void Code::set_stub_info(int value) {
ASSERT(kind() == COMPARE_IC ||
kind() == COMPARE_NIL_IC ||
kind() == BINARY_OP_IC ||
kind() == STUB ||
kind() == LOAD_IC ||
kind() == CALL_IC ||
kind() == KEYED_LOAD_IC ||
kind() == STORE_IC ||
kind() == KEYED_STORE_IC);
set_raw_type_feedback_info(Smi::FromInt(value));
void Code::set_stub_key(uint32_t key) {
ASSERT(IsCodeStubOrIC());
set_raw_type_feedback_info(Smi::FromInt(key + Smi::kMinValue));
}

View File

@ -11438,7 +11438,7 @@ void Code::PrintExtraICState(OStream& os, // NOLINT
void Code::Disassemble(const char* name, OStream& os) { // NOLINT
os << "kind = " << Kind2String(kind()) << "\n";
if (has_major_key()) {
if (IsCodeStubOrIC()) {
const char* n = CodeStub::MajorName(CodeStub::GetMajorKey(this), true);
os << "major_key = " << (n == NULL ? "null" : n) << "\n";
}
@ -11449,11 +11449,11 @@ void Code::Disassemble(const char* name, OStream& os) { // NOLINT
os << "type = " << StubType2String(type()) << "\n";
}
if (is_compare_ic_stub()) {
ASSERT(major_key() == CodeStub::CompareIC);
ASSERT(CodeStub::GetMajorKey(this) == CodeStub::CompareIC);
CompareIC::State left_state, right_state, handler_state;
Token::Value op;
ICCompareStub::DecodeMinorKey(stub_info(), &left_state, &right_state,
&handler_state, &op);
ICCompareStub::DecodeKey(stub_key(), &left_state, &right_state,
&handler_state, &op);
os << "compare_state = " << CompareIC::GetStateName(left_state) << "*"
<< CompareIC::GetStateName(right_state) << " -> "
<< CompareIC::GetStateName(handler_state) << "\n";

View File

@ -5460,13 +5460,13 @@ class Code: public HeapObject {
// [raw_type_feedback_info]: This field stores various things, depending on
// the kind of the code object.
// FUNCTION => type feedback information.
// STUB => various things, e.g. a SMI
// STUB and ICs => major/minor key as Smi.
DECL_ACCESSORS(raw_type_feedback_info, Object)
inline Object* type_feedback_info();
inline void set_type_feedback_info(
Object* value, WriteBarrierMode mode = UPDATE_WRITE_BARRIER);
inline int stub_info();
inline void set_stub_info(int info);
inline uint32_t stub_key();
inline void set_stub_key(uint32_t key);
// [next_code_link]: Link for lists of optimized or deoptimized code.
// Note that storage for this field is overlapped with typefeedback_info.
@ -5530,14 +5530,11 @@ class Code: public HeapObject {
ic_state() == MONOMORPHIC;
}
inline bool IsCodeStubOrIC();
inline void set_raw_kind_specific_flags1(int value);
inline void set_raw_kind_specific_flags2(int value);
// [major_key]: For kind STUB or BINARY_OP_IC, the major key.
inline int major_key();
inline void set_major_key(int value);
inline bool has_major_key();
// For kind STUB or ICs, tells whether or not a code object was generated by
// the optimizing compiler (but it may not be an optimized function).
bool is_crankshafted();
@ -5808,6 +5805,7 @@ class Code: public HeapObject {
static const int kHandlerTableOffset = kRelocationInfoOffset + kPointerSize;
static const int kDeoptimizationDataOffset =
kHandlerTableOffset + kPointerSize;
// For FUNCTION kind, we store the type feedback info here.
static const int kTypeFeedbackInfoOffset =
kDeoptimizationDataOffset + kPointerSize;
static const int kNextCodeLinkOffset = kTypeFeedbackInfoOffset + kPointerSize;
@ -5890,22 +5888,16 @@ class Code: public HeapObject {
kIsCrankshaftedBit, 1> {}; // NOLINT
// KindSpecificFlags2 layout (STUB and OPTIMIZED_FUNCTION)
static const int kStubMajorKeyFirstBit = kIsCrankshaftedBit + 1;
static const int kSafepointTableOffsetFirstBit =
kStubMajorKeyFirstBit + kStubMajorKeyBits;
static const int kSafepointTableOffsetFirstBit = kIsCrankshaftedBit + 1;
static const int kSafepointTableOffsetBitCount = 24;
STATIC_ASSERT(kStubMajorKeyFirstBit + kStubMajorKeyBits <= 32);
STATIC_ASSERT(kSafepointTableOffsetFirstBit +
kSafepointTableOffsetBitCount <= 32);
STATIC_ASSERT(1 + kStubMajorKeyBits +
kSafepointTableOffsetBitCount <= 32);
STATIC_ASSERT(1 + kSafepointTableOffsetBitCount <= 32);
class SafepointTableOffsetField: public BitField<int,
kSafepointTableOffsetFirstBit,
kSafepointTableOffsetBitCount> {}; // NOLINT
class StubMajorKeyField: public BitField<int,
kStubMajorKeyFirstBit, kStubMajorKeyBits> {}; // NOLINT
// KindSpecificFlags2 layout (FUNCTION)
class BackEdgeTableOffsetField: public BitField<int,

View File

@ -704,9 +704,7 @@ Handle<Code> StubCompiler::GetCodeWithFlags(Code::Flags flags,
CodeDesc desc;
masm_.GetCode(&desc);
Handle<Code> code = factory()->NewCode(desc, flags, masm_.CodeObject());
if (code->has_major_key()) {
code->set_major_key(CodeStub::NoCache);
}
if (code->IsCodeStubOrIC()) code->set_stub_key(CodeStub::NoCacheKey());
#ifdef ENABLE_DISASSEMBLER
if (FLAG_print_code_stubs) {
OFStream os(stdout);

View File

@ -207,9 +207,8 @@ void TypeFeedbackOracle::CompareType(TypeFeedbackId id,
}
if (code->is_compare_ic_stub()) {
int stub_minor_key = code->stub_info();
CompareIC::StubInfoToType(
stub_minor_key, left_type, right_type, combined_type, map, zone());
CompareIC::StubInfoToType(code->stub_key(), left_type, right_type,
combined_type, map, zone());
} else if (code->is_compare_nil_ic_stub()) {
CompareNilICStub stub(isolate(), code->extra_ic_state());
*combined_type = stub.GetType(zone(), map);