Reviewers: Vyacheslav Egorov,
Message:
Only for ia32, ports to x64 and ARM will follow shortly.
Description:
Implement clearing of CompareICs.
This allows CompareICs to be cleared during garbage collection to avoid
cross-context garbage retention through maps stored in CompareIC stubs
for the KNOWN_OBJECTS state.
[email protected]
BUG=v8:2102
Please review this at https://chromiumcodereview.appspot.com/10263008/
SVN Base: https://v8.googlecode.com/svn/branches/bleeding_edge
Affected files:
M src/code-stubs.h
M src/ia32/assembler-ia32.h
M src/ia32/ic-ia32.cc
M src/ic.h
M src/ic.cc
M src/objects-inl.h
M src/objects.h
M src/objects.cc
Index: src/code-stubs.h
diff --git a/src/code-stubs.h b/src/code-stubs.h
index
b67e961ac78a48614ffd5ed84c5b5a77f90810a5..5c8717838f8da0ac6b919e70bbb300d3966612dc
100644
--- a/src/code-stubs.h
+++ b/src/code-stubs.h
@@ -498,6 +498,7 @@ class ICCompareStub: public CodeStub {
virtual void FinishCode(Handle<Code> code) {
code->set_compare_state(state_);
+ code->set_compare_operation(op_);
}
virtual CodeStub::Major MajorKey() { return CompareIC; }
Index: src/ia32/assembler-ia32.h
diff --git a/src/ia32/assembler-ia32.h b/src/ia32/assembler-ia32.h
index
929b485ebfb9eedbef085c061aadc572fd28334e..9dc637b754c286c814187bdc68a95f7d7b9568ec
100644
--- a/src/ia32/assembler-ia32.h
+++ b/src/ia32/assembler-ia32.h
@@ -640,6 +640,8 @@ class Assembler : public AssemblerBase {
static const byte kJccShortPrefix = 0x70;
static const byte kJncShortOpcode = kJccShortPrefix | not_carry;
static const byte kJcShortOpcode = kJccShortPrefix | carry;
+ static const byte kJnzShortOpcode = kJccShortPrefix | not_zero;
+ static const byte kJzShortOpcode = kJccShortPrefix | zero;
//
---------------------------------------------------------------------------
// Code generation
Index: src/ia32/ic-ia32.cc
diff --git a/src/ia32/ic-ia32.cc b/src/ia32/ic-ia32.cc
index
33f247a349e0641b60c57bb56c67f80ed831d6aa..3a7ba4c9a793ff0f2d89bcb59ec26d38ed2712e0
100644
--- a/src/ia32/ic-ia32.cc
+++ b/src/ia32/ic-ia32.cc
@@ -1735,12 +1735,12 @@ void CompareIC::UpdateCaches(Handle<Object> x,
Handle<Object> y) {
// Activate inlined smi code.
if (previous_state == UNINITIALIZED) {
- PatchInlinedSmiCode(address());
+ PatchInlinedSmiCode(address(), ENABLE_INLINED_SMI_CHECK);
}
}
-void PatchInlinedSmiCode(Address address) {
+void PatchInlinedSmiCode(Address address, InlinedSmiCheck check) {
// The address of the instruction following the call.
Address test_instruction_address =
address + Assembler::kCallTargetAddressOffset;
@@ -1761,14 +1761,18 @@ void PatchInlinedSmiCode(Address address) {
address, test_instruction_address, delta);
}
- // Patch with a short conditional jump. There must be a
- // short jump-if-carry/not-carry at this position.
+ // Patch with a short conditional jump. Enabling means switching from a
short
+ // jump-if-carry/not-carry to jump-if-zero/not-zero, whereas disabling
is the
+ // reverse operation of that.
Address jmp_address = test_instruction_address - delta;
- ASSERT(*jmp_address == Assembler::kJncShortOpcode ||
- *jmp_address == Assembler::kJcShortOpcode);
- Condition cc = *jmp_address == Assembler::kJncShortOpcode
- ? not_zero
- : zero;
+ ASSERT((check == ENABLE_INLINED_SMI_CHECK)
+ ? (*jmp_address == Assembler::kJncShortOpcode ||
+ *jmp_address == Assembler::kJcShortOpcode)
+ : (*jmp_address == Assembler::kJnzShortOpcode ||
+ *jmp_address == Assembler::kJzShortOpcode));
+ Condition cc = (check == ENABLE_INLINED_SMI_CHECK)
+ ? (*jmp_address == Assembler::kJncShortOpcode ? not_zero : zero)
+ : (*jmp_address == Assembler::kJnzShortOpcode ? not_carry : carry);
*jmp_address = static_cast<byte>(Assembler::kJccShortPrefix | cc);
}
Index: src/ic.cc
diff --git a/src/ic.cc b/src/ic.cc
index
643fa884139fa1d041d94d7d7092feb748a508d9..1f46f0ee6668ae5621e49c729c7c59a517eafa88
100644
--- a/src/ic.cc
+++ b/src/ic.cc
@@ -352,9 +352,9 @@ void IC::Clear(Address address) {
return KeyedStoreIC::Clear(address, target);
case Code::CALL_IC: return CallIC::Clear(address, target);
case Code::KEYED_CALL_IC: return KeyedCallIC::Clear(address, target);
+ case Code::COMPARE_IC: return CompareIC::Clear(address, target);
case Code::UNARY_OP_IC:
case Code::BINARY_OP_IC:
- case Code::COMPARE_IC:
case Code::TO_BOOLEAN_IC:
// Clearing these is tricky and does not
// make any performance difference.
@@ -365,9 +365,8 @@ void IC::Clear(Address address) {
void CallICBase::Clear(Address address, Code* target) {
+ if (target->ic_state() == UNINITIALIZED) return;
bool contextual =
CallICBase::Contextual::decode(target->extra_ic_state());
- State state = target->ic_state();
- if (state == UNINITIALIZED) return;
Code* code =
Isolate::Current()->stub_cache()->FindCallInitialize(
target->arguments_count(),
@@ -410,6 +409,16 @@ void KeyedStoreIC::Clear(Address address, Code*
target) {
}
+void CompareIC::Clear(Address address, Code* target) {
+ // Only clear ICCompareStubs, we currently cannot clear generic
CompareStubs.
+ if (target->major_key() != CodeStub::CompareIC) return;
+ if (target->compare_state() == UNINITIALIZED) return;
+ Token::Value op = CompareIC::ComputeOperation(target);
+ SetTargetAtAddress(address, initialize_stub(op));
+ PatchInlinedSmiCode(address, DISABLE_INLINED_SMI_CHECK);
+}
+
+
static bool HasInterceptorGetter(JSObject* object) {
return !object->GetNamedInterceptor()->getter()->IsUndefined();
}
@@ -2396,7 +2405,7 @@ RUNTIME_FUNCTION(MaybeObject*, BinaryOp_Patch) {
// Activate inlined smi code.
if (previous_type == BinaryOpIC::UNINITIALIZED) {
- PatchInlinedSmiCode(ic.address());
+ PatchInlinedSmiCode(ic.address(), ENABLE_INLINED_SMI_CHECK);
}
}
@@ -2457,6 +2466,14 @@ RUNTIME_FUNCTION(MaybeObject*, BinaryOp_Patch) {
}
+Code* CompareIC::initialize_stub(Token::Value op) {
+ ICCompareStub stub(op, UNINITIALIZED);
+ Code* code = NULL;
+ CHECK(stub.FindCodeInCache(&code));
+ return code;
+}
+
+
Handle<Code> CompareIC::GetUninitialized(Token::Value op) {
ICCompareStub stub(op, UNINITIALIZED);
return stub.GetCode();
@@ -2471,6 +2488,12 @@ CompareIC::State CompareIC::ComputeState(Code*
target) {
}
+Token::Value CompareIC::ComputeOperation(Code* target) {
+ ASSERT(target->major_key() == CodeStub::CompareIC);
+ return static_cast<Token::Value>(target->compare_operation());
+}
+
+
const char* CompareIC::GetStateName(State state) {
switch (state) {
case UNINITIALIZED: return "UNINITIALIZED";
Index: src/ic.h
diff --git a/src/ic.h b/src/ic.h
index
56625525d472c9e633b55a124eb468c5ca6dccef..a822927c4ff399a9e17e8a10384ddb31cb5607eb
100644
--- a/src/ic.h
+++ b/src/ic.h
@@ -794,6 +794,9 @@ class CompareIC: public IC {
// Helper function for determining the state of a compare IC.
static State ComputeState(Code* target);
+ // Helper function for determining the operation a compare IC is for.
+ static Token::Value ComputeOperation(Code* target);
+
static const char* GetStateName(State state);
private:
@@ -804,7 +807,13 @@ class CompareIC: public IC {
Condition GetCondition() const { return ComputeCondition(op_); }
State GetState() { return ComputeState(target()); }
+ static Code* initialize_stub(Token::Value op);
+
+ static void Clear(Address address, Code* target);
+
Token::Value op_;
+
+ friend class IC;
};
@@ -817,7 +826,8 @@ class ToBooleanIC: public IC {
// Helper for BinaryOpIC and CompareIC.
-void PatchInlinedSmiCode(Address address);
+enum InlinedSmiCheck { ENABLE_INLINED_SMI_CHECK, DISABLE_INLINED_SMI_CHECK
};
+void PatchInlinedSmiCode(Address address, InlinedSmiCheck check);
} } // namespace v8::internal
Index: src/objects-inl.h
diff --git a/src/objects-inl.h b/src/objects-inl.h
index
15bdc5221ebf221e1a05c9d7a65a4c268243daa8..922552c10f2fd878a6315f0460acae70b98845c9
100644
--- a/src/objects-inl.h
+++ b/src/objects-inl.h
@@ -3191,6 +3191,18 @@ void Code::set_compare_state(byte value) {
}
+byte Code::compare_operation() {
+ ASSERT(is_compare_ic_stub());
+ return READ_BYTE_FIELD(this, kCompareOperationOffset);
+}
+
+
+void Code::set_compare_operation(byte value) {
+ ASSERT(is_compare_ic_stub());
+ WRITE_BYTE_FIELD(this, kCompareOperationOffset, value);
+}
+
+
byte Code::to_boolean_state() {
ASSERT(is_to_boolean_ic_stub());
return READ_BYTE_FIELD(this, kToBooleanTypeOffset);
Index: src/objects.cc
diff --git a/src/objects.cc b/src/objects.cc
index
96b42286e88f03c1772e204d04497c22f38456ab..e2b1b753328672fb9d164d975a331717de20d3b6
100644
--- a/src/objects.cc
+++ b/src/objects.cc
@@ -8379,6 +8379,10 @@ void Code::Disassemble(const char* name, FILE* out) {
CompareIC::State state = CompareIC::ComputeState(this);
PrintF(out, "compare_state = %s\n", CompareIC::GetStateName(state));
}
+ if (is_compare_ic_stub() && major_key() == CodeStub::CompareIC) {
+ Token::Value op = CompareIC::ComputeOperation(this);
+ PrintF(out, "compare_operation = %s\n", Token::Name(op));
+ }
}
if ((name != NULL) && (name[0] != '\0')) {
PrintF(out, "name = %s\n", name);
Index: src/objects.h
diff --git a/src/objects.h b/src/objects.h
index
3ec9428ab255d48da40b5537a8961cc559186906..fbd368fb268939381c69996aac4aa9eed3cd8dc0
100644
--- a/src/objects.h
+++ b/src/objects.h
@@ -4291,6 +4291,11 @@ class Code: public HeapObject {
inline byte compare_state();
inline void set_compare_state(byte value);
+ // [compare_operation]: For kind COMPARE_IC tells what compare operation
the
+ // stub was generated for.
+ inline byte compare_operation();
+ inline void set_compare_operation(byte value);
+
// [to_boolean_foo]: For kind TO_BOOLEAN_IC tells what state the stub is
in.
inline byte to_boolean_state();
inline void set_to_boolean_state(byte value);
@@ -4474,6 +4479,8 @@ class Code: public HeapObject {
static const int kBinaryOpReturnTypeOffset = kBinaryOpTypeOffset + 1;
+ static const int kCompareOperationOffset = kCompareStateOffset + 1;
+
static const int kAllowOSRAtLoopNestingLevelOffset = kFullCodeFlags + 1;
static const int kProfilerTicksOffset =
kAllowOSRAtLoopNestingLevelOffset + 1;
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev