Index: src/ic.cc |
=================================================================== |
--- src/ic.cc (revision 3980) |
+++ src/ic.cc (working copy) |
@@ -222,6 +222,7 @@ |
case Code::STORE_IC: return StoreIC::Clear(address, target); |
case Code::KEYED_STORE_IC: return KeyedStoreIC::Clear(address, target); |
case Code::CALL_IC: return CallIC::Clear(address, target); |
+ case Code::BINARY_OP_IC: return BinaryOpIC::Clear(address, target); |
default: UNREACHABLE(); |
} |
} |
@@ -1416,6 +1417,112 @@ |
} |
+void BinaryOpIC::patch(Code* code) { |
+ set_target(code); |
+} |
+ |
+ |
+void BinaryOpIC::Clear(Address address, Code* target) { |
+ if (target->ic_state() == UNINITIALIZED) return; |
+ |
+ // At the end of a fast case stub there should be a reference to |
+ // a corresponding UNINITIALIZED stub, so look for the last reloc info item. |
+ RelocInfo* rinfo = NULL; |
+ for (RelocIterator it(target, RelocInfo::kCodeTargetMask); |
+ !it.done(); it.next()) { |
+ rinfo = it.rinfo(); |
+ } |
+ |
+ ASSERT(rinfo != NULL); |
+ Code* uninit_stub = Code::GetCodeFromTargetAddress(rinfo->target_address()); |
+ ASSERT(uninit_stub->ic_state() == UNINITIALIZED && |
+ uninit_stub->kind() == Code::BINARY_OP_IC); |
+ SetTargetAtAddress(address, uninit_stub); |
+} |
+ |
+ |
+const char* BinaryOpIC::GetName(TypeInfo type_info) { |
+ switch (type_info) { |
+ case DEFAULT: return "Default"; |
+ case GENERIC: return "Generic"; |
+ case HEAP_NUMBERS: return "HeapNumbers"; |
+ case STRINGS: return "Strings"; |
+ default: return "Invalid"; |
+ } |
+} |
+ |
+ |
+BinaryOpIC::State BinaryOpIC::ToState(TypeInfo type_info) { |
+ switch (type_info) { |
+ // DEFAULT is mapped to UNINITIALIZED so that calls to DEFAULT stubs |
+ // are not cleared at GC. |
+ case DEFAULT: return UNINITIALIZED; |
+ |
+ // Could have mapped GENERIC to MONOMORPHIC just as well but MEGAMORPHIC is |
+ // conceptually closer. |
+ case GENERIC: return MEGAMORPHIC; |
+ |
+ default: return MONOMORPHIC; |
+ } |
+} |
+ |
+ |
+BinaryOpIC::TypeInfo BinaryOpIC::GetTypeInfo(Object* left, |
+ Object* right) { |
+ // Patching is never requested for the two smis. |
+ ASSERT(!left->IsSmi() || !right->IsSmi()); |
+ |
+ if (left->IsNumber() && right->IsNumber()) { |
+ return HEAP_NUMBERS; |
+ } |
+ |
+ if (left->IsString() || right->IsString()) { |
+ // Patching for fast string ADD makes sense even if only one of the |
+ // arguments is a string. |
+ return STRINGS; |
+ } |
+ |
+ return GENERIC; |
+} |
+ |
+ |
+// defined in codegen-<arch>.cc |
+Handle<Code> GetBinaryOpStub(int key, BinaryOpIC::TypeInfo type_info); |
+ |
+ |
+Object* BinaryOp_Patch(Arguments args) { |
+ ASSERT(args.length() == 6); |
+ |
+ HandleScope scope; |
+ Handle<Object> left = args.at<Object>(0); |
+ Handle<Object> right = args.at<Object>(1); |
+ Handle<Object> result = args.at<Object>(2); |
+ int key = Smi::cast(args[3])->value(); |
+#ifdef DEBUG |
+ Token::Value op = static_cast<Token::Value>(Smi::cast(args[4])->value()); |
+ BinaryOpIC::TypeInfo prev_type_info = |
+ static_cast<BinaryOpIC::TypeInfo>(Smi::cast(args[5])->value()); |
+#endif // DEBUG |
+ |
+ BinaryOpIC::TypeInfo type_info = BinaryOpIC::GetTypeInfo(*left, *right); |
+ Handle<Code> code = GetBinaryOpStub(key, type_info); |
+ if (!code.is_null()) { |
+ BinaryOpIC ic; |
+ ic.patch(*code); |
+#ifdef DEBUG |
+ if (FLAG_trace_ic) { |
+ PrintF("[BinaryOpIC (%s->%s)#%s]\n", |
+ BinaryOpIC::GetName(prev_type_info), |
+ BinaryOpIC::GetName(type_info), |
+ Token::Name(op)); |
+ } |
+#endif // DEBUG |
+ } |
+ |
+ return *result; |
+} |
+ |
+ |
static Address IC_utilities[] = { |
#define ADDR(name) FUNCTION_ADDR(name), |
IC_UTIL_LIST(ADDR) |