diff options
Diffstat (limited to 'deps/v8/src/ic.cc')
-rw-r--r-- | deps/v8/src/ic.cc | 341 |
1 files changed, 208 insertions, 133 deletions
diff --git a/deps/v8/src/ic.cc b/deps/v8/src/ic.cc index b902b5386d..bf2a649f7f 100644 --- a/deps/v8/src/ic.cc +++ b/deps/v8/src/ic.cc @@ -158,7 +158,7 @@ Address IC::OriginalCodeAddress() const { // Get the address of the call site in the active code. This is the // place where the call to DebugBreakXXX is and where the IC // normally would be. - Address addr = pc() - Assembler::kCallTargetAddressOffset; + Address addr = Assembler::target_address_from_return_address(pc()); // Return the address in the original code. This is the place where // the call which has been overwritten by the DebugBreakXXX resides // and the place where the inline cache system should look. @@ -310,7 +310,8 @@ void IC::PostPatching(Address address, Code* target, Code* old_target) { if (FLAG_type_info_threshold == 0 && !FLAG_watch_ic_patching) { return; } - Code* host = target->GetHeap()->isolate()-> + Isolate* isolate = target->GetHeap()->isolate(); + Code* host = isolate-> inner_pointer_to_code_cache()->GetCacheEntry(address)->code; if (host->kind() != Code::FUNCTION) return; @@ -333,7 +334,7 @@ void IC::PostPatching(Address address, Code* target, Code* old_target) { } if (FLAG_watch_ic_patching) { host->set_profiler_ticks(0); - Isolate::Current()->runtime_profiler()->NotifyICChanged(); + isolate->runtime_profiler()->NotifyICChanged(); } // TODO(2029): When an optimized function is patched, it would // be nice to propagate the corresponding type information to its @@ -414,11 +415,13 @@ 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; + ASSERT(target->major_key() == CodeStub::CompareIC); + CompareIC::State handler_state; + Token::Value op; + ICCompareStub::DecodeMinorKey(target->stub_info(), NULL, NULL, + &handler_state, &op); // Only clear CompareICs that can retain objects. - if (target->compare_state() != KNOWN_OBJECTS) return; - Token::Value op = CompareIC::ComputeOperation(target); + if (handler_state != KNOWN_OBJECTS) return; SetTargetAtAddress(address, GetRawUninitialized(op)); PatchInlinedSmiCode(address, DISABLE_INLINED_SMI_CHECK); } @@ -646,7 +649,7 @@ Handle<Code> CallICBase::ComputeMonomorphicStub(LookupResult* lookup, Handle<JSObject> holder(lookup->holder()); switch (lookup->type()) { case FIELD: { - int index = lookup->GetFieldIndex(); + PropertyIndex index = lookup->GetFieldIndex(); return isolate()->stub_cache()->ComputeCallField( argc, kind_, extra_state, name, object, holder, index); } @@ -1377,6 +1380,11 @@ MaybeObject* StoreIC::Store(State state, return *value; } + // Observed objects are always modified through the runtime. + if (FLAG_harmony_observation && receiver->map()->is_observed()) { + return receiver->SetProperty(*name, *value, NONE, strict_mode); + } + // Use specialized code for setting the length of arrays with fast // properties. Slow properties might indicate redefinition of the // length property. @@ -1462,11 +1470,9 @@ void StoreIC::UpdateCaches(LookupResult* lookup, Handle<Code> code; switch (type) { case FIELD: - code = isolate()->stub_cache()->ComputeStoreField(name, - receiver, - lookup->GetFieldIndex(), - Handle<Map>::null(), - strict_mode); + code = isolate()->stub_cache()->ComputeStoreField( + name, receiver, lookup->GetFieldIndex().field_index(), + Handle<Map>::null(), strict_mode); break; case NORMAL: if (receiver->IsGlobalObject()) { @@ -1902,7 +1908,8 @@ MaybeObject* KeyedStoreIC::Store(State state, } // Update inline cache and stub cache. - if (FLAG_use_ic && !receiver->IsJSGlobalProxy()) { + if (FLAG_use_ic && !receiver->IsJSGlobalProxy() && + !(FLAG_harmony_observation && receiver->map()->is_observed())) { LookupResult lookup(isolate()); if (LookupForWrite(receiver, name, &lookup)) { UpdateCaches(&lookup, state, strict_mode, receiver, name, value); @@ -1914,8 +1921,10 @@ MaybeObject* KeyedStoreIC::Store(State state, } // Do not use ICs for objects that require access checks (including - // the global object). - bool use_ic = FLAG_use_ic && !object->IsAccessCheckNeeded(); + // the global object), or are observed. + bool use_ic = FLAG_use_ic && !object->IsAccessCheckNeeded() && + !(FLAG_harmony_observation && object->IsJSObject() && + JSObject::cast(*object)->map()->is_observed()); ASSERT(!(use_ic && object->IsJSGlobalProxy())); if (use_ic) { @@ -1973,7 +1982,7 @@ void KeyedStoreIC::UpdateCaches(LookupResult* lookup, switch (type) { case FIELD: code = isolate()->stub_cache()->ComputeKeyedStoreField( - name, receiver, lookup->GetFieldIndex(), + name, receiver, lookup->GetFieldIndex().field_index(), Handle<Map>::null(), strict_mode); break; case TRANSITION: { @@ -2307,11 +2316,10 @@ const char* BinaryOpIC::GetName(TypeInfo type_info) { switch (type_info) { case UNINITIALIZED: return "Uninitialized"; case SMI: return "SMI"; - case INT32: return "Int32s"; - case HEAP_NUMBER: return "HeapNumbers"; + case INT32: return "Int32"; + case HEAP_NUMBER: return "HeapNumber"; case ODDBALL: return "Oddball"; - case BOTH_STRING: return "BothStrings"; - case STRING: return "Strings"; + case STRING: return "String"; case GENERIC: return "Generic"; default: return "Invalid"; } @@ -2326,7 +2334,6 @@ BinaryOpIC::State BinaryOpIC::ToState(TypeInfo type_info) { case INT32: case HEAP_NUMBER: case ODDBALL: - case BOTH_STRING: case STRING: return MONOMORPHIC; case GENERIC: @@ -2337,58 +2344,6 @@ BinaryOpIC::State BinaryOpIC::ToState(TypeInfo type_info) { } -BinaryOpIC::TypeInfo BinaryOpIC::JoinTypes(BinaryOpIC::TypeInfo x, - BinaryOpIC::TypeInfo y) { - if (x == UNINITIALIZED) return y; - if (y == UNINITIALIZED) return x; - if (x == y) return x; - if (x == BOTH_STRING && y == STRING) return STRING; - if (x == STRING && y == BOTH_STRING) return STRING; - if (x == STRING || x == BOTH_STRING || y == STRING || y == BOTH_STRING) { - return GENERIC; - } - if (x > y) return x; - return y; -} - - -BinaryOpIC::TypeInfo BinaryOpIC::GetTypeInfo(Handle<Object> left, - Handle<Object> right) { - ::v8::internal::TypeInfo left_type = - ::v8::internal::TypeInfo::TypeFromValue(left); - ::v8::internal::TypeInfo right_type = - ::v8::internal::TypeInfo::TypeFromValue(right); - - if (left_type.IsSmi() && right_type.IsSmi()) { - return SMI; - } - - if (left_type.IsInteger32() && right_type.IsInteger32()) { - // Platforms with 32-bit Smis have no distinct INT32 type. - if (kSmiValueSize == 32) return SMI; - return INT32; - } - - if (left_type.IsNumber() && right_type.IsNumber()) { - return HEAP_NUMBER; - } - - // Patching for fast string ADD makes sense even if only one of the - // arguments is a string. - if (left_type.IsString()) { - return right_type.IsString() ? BOTH_STRING : STRING; - } else if (right_type.IsString()) { - return STRING; - } - - // Check for oddball objects. - if (left->IsUndefined() && right->IsNumber()) return ODDBALL; - if (left->IsNumber() && right->IsUndefined()) return ODDBALL; - - return GENERIC; -} - - RUNTIME_FUNCTION(MaybeObject*, UnaryOp_Patch) { ASSERT(args.length() == 4); @@ -2440,25 +2395,72 @@ RUNTIME_FUNCTION(MaybeObject*, UnaryOp_Patch) { return *result; } + +static BinaryOpIC::TypeInfo TypeInfoFromValue(Handle<Object> value, + Token::Value op) { + ::v8::internal::TypeInfo type = + ::v8::internal::TypeInfo::TypeFromValue(value); + if (type.IsSmi()) return BinaryOpIC::SMI; + if (type.IsInteger32()) { + if (kSmiValueSize == 32) return BinaryOpIC::SMI; + return BinaryOpIC::INT32; + } + if (type.IsNumber()) return BinaryOpIC::HEAP_NUMBER; + if (type.IsString()) return BinaryOpIC::STRING; + if (value->IsUndefined()) { + if (op == Token::BIT_AND || + op == Token::BIT_OR || + op == Token::BIT_XOR || + op == Token::SAR || + op == Token::SHL || + op == Token::SHR) { + if (kSmiValueSize == 32) return BinaryOpIC::SMI; + return BinaryOpIC::INT32; + } + return BinaryOpIC::ODDBALL; + } + return BinaryOpIC::GENERIC; +} + + +static BinaryOpIC::TypeInfo InputState(BinaryOpIC::TypeInfo old_type, + Handle<Object> value, + Token::Value op) { + BinaryOpIC::TypeInfo new_type = TypeInfoFromValue(value, op); + if (old_type == BinaryOpIC::STRING) { + if (new_type == BinaryOpIC::STRING) return new_type; + return BinaryOpIC::GENERIC; + } + return Max(old_type, new_type); +} + + RUNTIME_FUNCTION(MaybeObject*, BinaryOp_Patch) { - ASSERT(args.length() == 5); + ASSERT(args.length() == 3); HandleScope scope(isolate); Handle<Object> left = args.at<Object>(0); Handle<Object> right = args.at<Object>(1); int key = args.smi_at(2); - Token::Value op = static_cast<Token::Value>(args.smi_at(3)); - BinaryOpIC::TypeInfo previous_type = - static_cast<BinaryOpIC::TypeInfo>(args.smi_at(4)); + Token::Value op = BinaryOpStub::decode_op_from_minor_key(key); + BinaryOpIC::TypeInfo previous_left, previous_right, unused_previous_result; + BinaryOpStub::decode_types_from_minor_key( + key, &previous_left, &previous_right, &unused_previous_result); - BinaryOpIC::TypeInfo type = BinaryOpIC::GetTypeInfo(left, right); - type = BinaryOpIC::JoinTypes(type, previous_type); + BinaryOpIC::TypeInfo new_left = InputState(previous_left, left, op); + BinaryOpIC::TypeInfo new_right = InputState(previous_right, right, op); BinaryOpIC::TypeInfo result_type = BinaryOpIC::UNINITIALIZED; - if ((type == BinaryOpIC::STRING || type == BinaryOpIC::BOTH_STRING) && + + // STRING is only used for ADD operations. + if ((new_left == BinaryOpIC::STRING || new_right == BinaryOpIC::STRING) && op != Token::ADD) { - type = BinaryOpIC::GENERIC; + new_left = new_right = BinaryOpIC::GENERIC; } - if (type == BinaryOpIC::SMI && previous_type == BinaryOpIC::SMI) { + + BinaryOpIC::TypeInfo new_overall = Max(new_left, new_right); + BinaryOpIC::TypeInfo previous_overall = Max(previous_left, previous_right); + + if (new_overall == BinaryOpIC::SMI && previous_overall == BinaryOpIC::SMI) { if (op == Token::DIV || op == Token::MUL || op == Token::SHR || @@ -2473,26 +2475,35 @@ RUNTIME_FUNCTION(MaybeObject*, BinaryOp_Patch) { result_type = BinaryOpIC::INT32; } } - if (type == BinaryOpIC::INT32 && previous_type == BinaryOpIC::INT32) { - // We must be here because an operation on two INT32 types overflowed. - result_type = BinaryOpIC::HEAP_NUMBER; + if (new_overall == BinaryOpIC::INT32 && + previous_overall == BinaryOpIC::INT32) { + if (new_left == previous_left && new_right == previous_right) { + result_type = BinaryOpIC::HEAP_NUMBER; + } } - BinaryOpStub stub(key, type, result_type); + BinaryOpStub stub(key, new_left, new_right, result_type); Handle<Code> code = stub.GetCode(); if (!code.is_null()) { +#ifdef DEBUG if (FLAG_trace_ic) { - PrintF("[BinaryOpIC (%s->(%s->%s))#%s]\n", - BinaryOpIC::GetName(previous_type), - BinaryOpIC::GetName(type), + PrintF("[BinaryOpIC in "); + JavaScriptFrame::PrintTop(stdout, false, true); + PrintF(" ((%s+%s)->((%s+%s)->%s))#%s @ %p]\n", + BinaryOpIC::GetName(previous_left), + BinaryOpIC::GetName(previous_right), + BinaryOpIC::GetName(new_left), + BinaryOpIC::GetName(new_right), BinaryOpIC::GetName(result_type), - Token::Name(op)); + Token::Name(op), + static_cast<void*>(*code)); } +#endif BinaryOpIC ic(isolate); ic.patch(*code); // Activate inlined smi code. - if (previous_type == BinaryOpIC::UNINITIALIZED) { + if (previous_overall == BinaryOpIC::UNINITIALIZED) { PatchInlinedSmiCode(ic.address(), ENABLE_INLINED_SMI_CHECK); } } @@ -2555,43 +2566,28 @@ RUNTIME_FUNCTION(MaybeObject*, BinaryOp_Patch) { Code* CompareIC::GetRawUninitialized(Token::Value op) { - ICCompareStub stub(op, UNINITIALIZED); + ICCompareStub stub(op, UNINITIALIZED, UNINITIALIZED, UNINITIALIZED); Code* code = NULL; - CHECK(stub.FindCodeInCache(&code)); + CHECK(stub.FindCodeInCache(&code, Isolate::Current())); return code; } Handle<Code> CompareIC::GetUninitialized(Token::Value op) { - ICCompareStub stub(op, UNINITIALIZED); + ICCompareStub stub(op, UNINITIALIZED, UNINITIALIZED, UNINITIALIZED); return stub.GetCode(); } -CompareIC::State CompareIC::ComputeState(Code* target) { - int key = target->major_key(); - if (key == CodeStub::Compare) return GENERIC; - ASSERT(key == CodeStub::CompareIC); - return static_cast<State>(target->compare_state()); -} - - -Token::Value CompareIC::ComputeOperation(Code* target) { - ASSERT(target->major_key() == CodeStub::CompareIC); - return static_cast<Token::Value>( - target->compare_operation() + Token::EQ); -} - - const char* CompareIC::GetStateName(State state) { switch (state) { case UNINITIALIZED: return "UNINITIALIZED"; - case SMIS: return "SMIS"; - case HEAP_NUMBERS: return "HEAP_NUMBERS"; - case OBJECTS: return "OBJECTS"; + case SMI: return "SMI"; + case HEAP_NUMBER: return "HEAP_NUMBER"; + case OBJECT: return "OBJECTS"; case KNOWN_OBJECTS: return "KNOWN_OBJECTS"; - case SYMBOLS: return "SYMBOLS"; - case STRINGS: return "STRINGS"; + case SYMBOL: return "SYMBOL"; + case STRING: return "STRING"; case GENERIC: return "GENERIC"; default: UNREACHABLE(); @@ -2600,28 +2596,67 @@ const char* CompareIC::GetStateName(State state) { } -CompareIC::State CompareIC::TargetState(State state, +static CompareIC::State InputState(CompareIC::State old_state, + Handle<Object> value) { + switch (old_state) { + case CompareIC::UNINITIALIZED: + if (value->IsSmi()) return CompareIC::SMI; + if (value->IsHeapNumber()) return CompareIC::HEAP_NUMBER; + if (value->IsSymbol()) return CompareIC::SYMBOL; + if (value->IsString()) return CompareIC::STRING; + if (value->IsJSObject()) return CompareIC::OBJECT; + break; + case CompareIC::SMI: + if (value->IsSmi()) return CompareIC::SMI; + if (value->IsHeapNumber()) return CompareIC::HEAP_NUMBER; + break; + case CompareIC::HEAP_NUMBER: + if (value->IsNumber()) return CompareIC::HEAP_NUMBER; + break; + case CompareIC::SYMBOL: + if (value->IsSymbol()) return CompareIC::SYMBOL; + if (value->IsString()) return CompareIC::STRING; + break; + case CompareIC::STRING: + if (value->IsSymbol() || value->IsString()) return CompareIC::STRING; + break; + case CompareIC::OBJECT: + if (value->IsJSObject()) return CompareIC::OBJECT; + break; + case CompareIC::GENERIC: + break; + case CompareIC::KNOWN_OBJECTS: + UNREACHABLE(); + break; + } + return CompareIC::GENERIC; +} + + +CompareIC::State CompareIC::TargetState(State old_state, + State old_left, + State old_right, bool has_inlined_smi_code, Handle<Object> x, Handle<Object> y) { - switch (state) { + switch (old_state) { case UNINITIALIZED: - if (x->IsSmi() && y->IsSmi()) return SMIS; - if (x->IsNumber() && y->IsNumber()) return HEAP_NUMBERS; + if (x->IsSmi() && y->IsSmi()) return SMI; + if (x->IsNumber() && y->IsNumber()) return HEAP_NUMBER; if (Token::IsOrderedRelationalCompareOp(op_)) { // Ordered comparisons treat undefined as NaN, so the // HEAP_NUMBER stub will do the right thing. if ((x->IsNumber() && y->IsUndefined()) || (y->IsNumber() && x->IsUndefined())) { - return HEAP_NUMBERS; + return HEAP_NUMBER; } } if (x->IsSymbol() && y->IsSymbol()) { // We compare symbols as strings if we need to determine // the order in a non-equality compare. - return Token::IsEqualityOp(op_) ? SYMBOLS : STRINGS; + return Token::IsEqualityOp(op_) ? SYMBOL : STRING; } - if (x->IsString() && y->IsString()) return STRINGS; + if (x->IsString() && y->IsString()) return STRING; if (!Token::IsEqualityOp(op_)) return GENERIC; if (x->IsJSObject() && y->IsJSObject()) { if (Handle<JSObject>::cast(x)->map() == @@ -2629,30 +2664,70 @@ CompareIC::State CompareIC::TargetState(State state, Token::IsEqualityOp(op_)) { return KNOWN_OBJECTS; } else { - return OBJECTS; + return OBJECT; } } return GENERIC; - case SMIS: - return has_inlined_smi_code && x->IsNumber() && y->IsNumber() - ? HEAP_NUMBERS + case SMI: + return x->IsNumber() && y->IsNumber() + ? HEAP_NUMBER : GENERIC; - case SYMBOLS: + case SYMBOL: ASSERT(Token::IsEqualityOp(op_)); - return x->IsString() && y->IsString() ? STRINGS : GENERIC; - case HEAP_NUMBERS: - case STRINGS: - case OBJECTS: + return x->IsString() && y->IsString() ? STRING : GENERIC; + case HEAP_NUMBER: + if (old_left == SMI && x->IsHeapNumber()) return HEAP_NUMBER; + if (old_right == SMI && y->IsHeapNumber()) return HEAP_NUMBER; + case STRING: + case OBJECT: case KNOWN_OBJECTS: case GENERIC: return GENERIC; } UNREACHABLE(); - return GENERIC; + return GENERIC; // Make the compiler happy. +} + + +void CompareIC::UpdateCaches(Handle<Object> x, Handle<Object> y) { + HandleScope scope; + State previous_left, previous_right, previous_state; + ICCompareStub::DecodeMinorKey(target()->stub_info(), &previous_left, + &previous_right, &previous_state, NULL); + State new_left = InputState(previous_left, x); + State new_right = InputState(previous_right, y); + State state = TargetState(previous_state, previous_left, previous_right, + HasInlinedSmiCode(address()), x, y); + ICCompareStub stub(op_, new_left, new_right, state); + if (state == KNOWN_OBJECTS) { + stub.set_known_map(Handle<Map>(Handle<JSObject>::cast(x)->map())); + } + set_target(*stub.GetCode()); + +#ifdef DEBUG + if (FLAG_trace_ic) { + PrintF("[CompareIC in "); + JavaScriptFrame::PrintTop(stdout, false, true); + PrintF(" ((%s+%s=%s)->(%s+%s=%s))#%s @ %p]\n", + GetStateName(previous_left), + GetStateName(previous_right), + GetStateName(previous_state), + GetStateName(new_left), + GetStateName(new_right), + GetStateName(state), + Token::Name(op_), + static_cast<void*>(*stub.GetCode())); + } +#endif + + // Activate inlined smi code. + if (previous_state == UNINITIALIZED) { + PatchInlinedSmiCode(address(), ENABLE_INLINED_SMI_CHECK); + } } -// Used from ic_<arch>.cc. +// Used from ICCompareStub::GenerateMiss in code-stubs-<arch>.cc. RUNTIME_FUNCTION(Code*, CompareIC_Miss) { NoHandleAllocation na; ASSERT(args.length() == 3); |