// Copyright 2012 the V8 project authors. All rights reserved. // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following // disclaimer in the documentation and/or other materials provided // with the distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived // from this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "v8.h" #include "ast.h" #include "code-stubs.h" #include "compiler.h" #include "ic.h" #include "macro-assembler.h" #include "stub-cache.h" #include "type-info.h" #include "ic-inl.h" #include "objects-inl.h" namespace v8 { namespace internal { TypeInfo TypeInfo::TypeFromValue(Handle value) { TypeInfo info; if (value->IsSmi()) { info = TypeInfo::Smi(); } else if (value->IsHeapNumber()) { info = TypeInfo::IsInt32Double(HeapNumber::cast(*value)->value()) ? TypeInfo::Integer32() : TypeInfo::Double(); } else if (value->IsString()) { info = TypeInfo::String(); } else { info = TypeInfo::Unknown(); } return info; } TypeFeedbackOracle::TypeFeedbackOracle(Handle code, Handle native_context, Isolate* isolate, Zone* zone) : native_context_(native_context), isolate_(isolate), zone_(zone) { BuildDictionary(code); ASSERT(dictionary_->IsDictionary()); } static uint32_t IdToKey(TypeFeedbackId ast_id) { return static_cast(ast_id.ToInt()); } Handle TypeFeedbackOracle::GetInfo(TypeFeedbackId ast_id) { int entry = dictionary_->FindEntry(IdToKey(ast_id)); if (entry != UnseededNumberDictionary::kNotFound) { Object* value = dictionary_->ValueAt(entry); if (value->IsCell()) { Cell* cell = Cell::cast(value); return Handle(cell->value(), isolate_); } else { return Handle(value, isolate_); } } return Handle::cast(isolate_->factory()->undefined_value()); } Handle TypeFeedbackOracle::GetInfoCell( TypeFeedbackId ast_id) { int entry = dictionary_->FindEntry(IdToKey(ast_id)); if (entry != UnseededNumberDictionary::kNotFound) { Cell* cell = Cell::cast(dictionary_->ValueAt(entry)); return Handle(cell, isolate_); } return Handle::null(); } bool TypeFeedbackOracle::LoadIsUninitialized(Property* expr) { Handle map_or_code = GetInfo(expr->PropertyFeedbackId()); if (map_or_code->IsMap()) return false; if (map_or_code->IsCode()) { Handle code = Handle::cast(map_or_code); return code->is_inline_cache_stub() && code->ic_state() == UNINITIALIZED; } return false; } bool TypeFeedbackOracle::LoadIsMonomorphicNormal(Property* expr) { Handle map_or_code = GetInfo(expr->PropertyFeedbackId()); if (map_or_code->IsMap()) return true; if (map_or_code->IsCode()) { Handle code = Handle::cast(map_or_code); bool preliminary_checks = code->is_keyed_load_stub() && code->ic_state() == MONOMORPHIC && Code::ExtractTypeFromFlags(code->flags()) == Code::NORMAL; if (!preliminary_checks) return false; Map* map = code->FindFirstMap(); if (map == NULL) return false; map = map->CurrentMapForDeprecated(); return map != NULL && !CanRetainOtherContext(map, *native_context_); } return false; } bool TypeFeedbackOracle::LoadIsPolymorphic(Property* expr) { Handle map_or_code = GetInfo(expr->PropertyFeedbackId()); if (map_or_code->IsCode()) { Handle code = Handle::cast(map_or_code); return code->is_keyed_load_stub() && code->ic_state() == POLYMORPHIC; } return false; } bool TypeFeedbackOracle::StoreIsMonomorphicNormal(TypeFeedbackId ast_id) { Handle map_or_code = GetInfo(ast_id); if (map_or_code->IsMap()) return true; if (map_or_code->IsCode()) { Handle code = Handle::cast(map_or_code); bool standard_store = FLAG_compiled_keyed_stores || (Code::GetKeyedAccessStoreMode(code->extra_ic_state()) == STANDARD_STORE); bool preliminary_checks = code->is_keyed_store_stub() && standard_store && code->ic_state() == MONOMORPHIC && Code::ExtractTypeFromFlags(code->flags()) == Code::NORMAL; if (!preliminary_checks) return false; Map* map = code->FindFirstMap(); if (map == NULL) return false; map = map->CurrentMapForDeprecated(); return map != NULL && !CanRetainOtherContext(map, *native_context_); } return false; } bool TypeFeedbackOracle::StoreIsPolymorphic(TypeFeedbackId ast_id) { Handle map_or_code = GetInfo(ast_id); if (map_or_code->IsCode()) { Handle code = Handle::cast(map_or_code); bool standard_store = FLAG_compiled_keyed_stores || (Code::GetKeyedAccessStoreMode(code->extra_ic_state()) == STANDARD_STORE); return code->is_keyed_store_stub() && standard_store && code->ic_state() == POLYMORPHIC; } return false; } bool TypeFeedbackOracle::CallIsMonomorphic(Call* expr) { Handle value = GetInfo(expr->CallFeedbackId()); return value->IsMap() || value->IsSmi() || value->IsJSFunction(); } bool TypeFeedbackOracle::CallNewIsMonomorphic(CallNew* expr) { Handle info = GetInfo(expr->CallNewFeedbackId()); return info->IsSmi() || info->IsJSFunction(); } bool TypeFeedbackOracle::ObjectLiteralStoreIsMonomorphic( ObjectLiteral::Property* prop) { Handle map_or_code = GetInfo(prop->key()->LiteralFeedbackId()); return map_or_code->IsMap(); } byte TypeFeedbackOracle::ForInType(ForInStatement* stmt) { Handle value = GetInfo(stmt->ForInFeedbackId()); return value->IsSmi() && Smi::cast(*value)->value() == TypeFeedbackCells::kForInFastCaseMarker ? ForInStatement::FAST_FOR_IN : ForInStatement::SLOW_FOR_IN; } Handle TypeFeedbackOracle::LoadMonomorphicReceiverType(Property* expr) { ASSERT(LoadIsMonomorphicNormal(expr)); Handle map_or_code = GetInfo(expr->PropertyFeedbackId()); if (map_or_code->IsCode()) { Handle code = Handle::cast(map_or_code); Map* map = code->FindFirstMap()->CurrentMapForDeprecated(); return map == NULL || CanRetainOtherContext(map, *native_context_) ? Handle::null() : Handle(map); } return Handle::cast(map_or_code); } Handle TypeFeedbackOracle::StoreMonomorphicReceiverType( TypeFeedbackId ast_id) { ASSERT(StoreIsMonomorphicNormal(ast_id)); Handle map_or_code = GetInfo(ast_id); if (map_or_code->IsCode()) { Handle code = Handle::cast(map_or_code); Map* map = code->FindFirstMap()->CurrentMapForDeprecated(); return map == NULL || CanRetainOtherContext(map, *native_context_) ? Handle::null() : Handle(map); } return Handle::cast(map_or_code); } Handle TypeFeedbackOracle::CompareNilMonomorphicReceiverType( CompareOperation* expr) { Handle maybe_code = GetInfo(expr->CompareOperationFeedbackId()); if (maybe_code->IsCode()) { Map* map = Handle::cast(maybe_code)->FindFirstMap(); if (map == NULL) return Handle(); map = map->CurrentMapForDeprecated(); return map == NULL || CanRetainOtherContext(map, *native_context_) ? Handle() : Handle(map); } else if (maybe_code->IsMap()) { ASSERT(!Handle::cast(maybe_code)->is_deprecated()); return Handle::cast(maybe_code); } return Handle(); } KeyedAccessStoreMode TypeFeedbackOracle::GetStoreMode( TypeFeedbackId ast_id) { Handle map_or_code = GetInfo(ast_id); if (map_or_code->IsCode()) { Handle code = Handle::cast(map_or_code); if (code->kind() == Code::KEYED_STORE_IC) { return Code::GetKeyedAccessStoreMode(code->extra_ic_state()); } } return STANDARD_STORE; } void TypeFeedbackOracle::LoadReceiverTypes(Property* expr, Handle name, SmallMapList* types) { Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC); CollectReceiverTypes(expr->PropertyFeedbackId(), name, flags, types); } void TypeFeedbackOracle::StoreReceiverTypes(Assignment* expr, Handle name, SmallMapList* types) { Code::Flags flags = Code::ComputeMonomorphicFlags(Code::STORE_IC); CollectReceiverTypes(expr->AssignmentFeedbackId(), name, flags, types); } void TypeFeedbackOracle::CallReceiverTypes(Call* expr, Handle name, CallKind call_kind, SmallMapList* types) { int arity = expr->arguments()->length(); // Note: Currently we do not take string extra ic data into account // here. Code::ExtraICState extra_ic_state = CallIC::Contextual::encode(call_kind == CALL_AS_FUNCTION); Code::Flags flags = Code::ComputeMonomorphicFlags(Code::CALL_IC, extra_ic_state, Code::NORMAL, arity, OWN_MAP); CollectReceiverTypes(expr->CallFeedbackId(), name, flags, types); } CheckType TypeFeedbackOracle::GetCallCheckType(Call* expr) { Handle value = GetInfo(expr->CallFeedbackId()); if (!value->IsSmi()) return RECEIVER_MAP_CHECK; CheckType check = static_cast(Smi::cast(*value)->value()); ASSERT(check != RECEIVER_MAP_CHECK); return check; } Handle TypeFeedbackOracle::GetCallTarget(Call* expr) { Handle info = GetInfo(expr->CallFeedbackId()); if (info->IsSmi()) { ASSERT(static_cast(Smi::cast(*info)->value()) <= LAST_FAST_ELEMENTS_KIND); return Handle(isolate_->global_context()->array_function()); } else { return Handle::cast(info); } } Handle TypeFeedbackOracle::GetCallNewTarget(CallNew* expr) { Handle info = GetInfo(expr->CallNewFeedbackId()); if (info->IsSmi()) { ASSERT(static_cast(Smi::cast(*info)->value()) <= LAST_FAST_ELEMENTS_KIND); return Handle(isolate_->global_context()->array_function()); } else { return Handle::cast(info); } } Handle TypeFeedbackOracle::GetCallNewAllocationInfoCell(CallNew* expr) { return GetInfoCell(expr->CallNewFeedbackId()); } Handle TypeFeedbackOracle::GetObjectLiteralStoreMap( ObjectLiteral::Property* prop) { ASSERT(ObjectLiteralStoreIsMonomorphic(prop)); return Handle::cast(GetInfo(prop->key()->LiteralFeedbackId())); } bool TypeFeedbackOracle::LoadIsBuiltin(Property* expr, Builtins::Name id) { return *GetInfo(expr->PropertyFeedbackId()) == isolate_->builtins()->builtin(id); } bool TypeFeedbackOracle::LoadIsStub(Property* expr, ICStub* stub) { Handle object = GetInfo(expr->PropertyFeedbackId()); if (!object->IsCode()) return false; Handle code = Handle::cast(object); if (!code->is_load_stub()) return false; if (code->ic_state() != MONOMORPHIC) return false; return stub->Describes(*code); } static TypeInfo TypeFromCompareType(CompareIC::State state) { switch (state) { case CompareIC::UNINITIALIZED: // Uninitialized means never executed. return TypeInfo::Uninitialized(); case CompareIC::SMI: return TypeInfo::Smi(); case CompareIC::NUMBER: return TypeInfo::Number(); case CompareIC::INTERNALIZED_STRING: return TypeInfo::InternalizedString(); case CompareIC::STRING: return TypeInfo::String(); case CompareIC::OBJECT: case CompareIC::KNOWN_OBJECT: // TODO(kasperl): We really need a type for JS objects here. return TypeInfo::NonPrimitive(); case CompareIC::GENERIC: default: return TypeInfo::Unknown(); } } void TypeFeedbackOracle::CompareType(CompareOperation* expr, TypeInfo* left_type, TypeInfo* right_type, TypeInfo* overall_type) { Handle object = GetInfo(expr->CompareOperationFeedbackId()); TypeInfo unknown = TypeInfo::Unknown(); if (!object->IsCode()) { *left_type = *right_type = *overall_type = unknown; return; } Handle code = Handle::cast(object); if (!code->is_compare_ic_stub()) { *left_type = *right_type = *overall_type = unknown; return; } int stub_minor_key = code->stub_info(); CompareIC::State left_state, right_state, handler_state; ICCompareStub::DecodeMinorKey(stub_minor_key, &left_state, &right_state, &handler_state, NULL); *left_type = TypeFromCompareType(left_state); *right_type = TypeFromCompareType(right_state); *overall_type = TypeFromCompareType(handler_state); } Handle TypeFeedbackOracle::GetCompareMap(CompareOperation* expr) { Handle object = GetInfo(expr->CompareOperationFeedbackId()); if (!object->IsCode()) return Handle::null(); Handle code = Handle::cast(object); if (!code->is_compare_ic_stub()) return Handle::null(); CompareIC::State state = ICCompareStub::CompareState(code->stub_info()); if (state != CompareIC::KNOWN_OBJECT) { return Handle::null(); } Map* map = code->FindFirstMap()->CurrentMapForDeprecated(); return map == NULL || CanRetainOtherContext(map, *native_context_) ? Handle::null() : Handle(map); } TypeInfo TypeFeedbackOracle::UnaryType(UnaryOperation* expr) { Handle object = GetInfo(expr->UnaryOperationFeedbackId()); TypeInfo unknown = TypeInfo::Unknown(); if (!object->IsCode()) return unknown; Handle code = Handle::cast(object); ASSERT(code->is_unary_op_stub()); UnaryOpIC::TypeInfo type = static_cast( code->unary_op_type()); switch (type) { case UnaryOpIC::SMI: return TypeInfo::Smi(); case UnaryOpIC::NUMBER: return TypeInfo::Double(); default: return unknown; } } static TypeInfo TypeFromBinaryOpType(BinaryOpIC::TypeInfo binary_type) { switch (binary_type) { // Uninitialized means never executed. case BinaryOpIC::UNINITIALIZED: return TypeInfo::Uninitialized(); case BinaryOpIC::SMI: return TypeInfo::Smi(); case BinaryOpIC::INT32: return TypeInfo::Integer32(); case BinaryOpIC::NUMBER: return TypeInfo::Double(); case BinaryOpIC::ODDBALL: return TypeInfo::Unknown(); case BinaryOpIC::STRING: return TypeInfo::String(); case BinaryOpIC::GENERIC: return TypeInfo::Unknown(); } UNREACHABLE(); return TypeInfo::Unknown(); } void TypeFeedbackOracle::BinaryType(BinaryOperation* expr, TypeInfo* left, TypeInfo* right, TypeInfo* result, bool* has_fixed_right_arg, int* fixed_right_arg_value) { Handle object = GetInfo(expr->BinaryOperationFeedbackId()); TypeInfo unknown = TypeInfo::Unknown(); if (!object->IsCode()) { *left = *right = *result = unknown; return; } Handle code = Handle::cast(object); if (code->is_binary_op_stub()) { int minor_key = code->stub_info(); BinaryOpIC::TypeInfo left_type, right_type, result_type; BinaryOpStub::decode_types_from_minor_key( minor_key, &left_type, &right_type, &result_type); *left = TypeFromBinaryOpType(left_type); *right = TypeFromBinaryOpType(right_type); *result = TypeFromBinaryOpType(result_type); *has_fixed_right_arg = BinaryOpStub::decode_has_fixed_right_arg_from_minor_key(minor_key); *fixed_right_arg_value = BinaryOpStub::decode_fixed_right_arg_value_from_minor_key(minor_key); return; } // Not a binary op stub. *left = *right = *result = unknown; } TypeInfo TypeFeedbackOracle::SwitchType(CaseClause* clause) { Handle object = GetInfo(clause->CompareId()); TypeInfo unknown = TypeInfo::Unknown(); if (!object->IsCode()) return unknown; Handle code = Handle::cast(object); if (!code->is_compare_ic_stub()) return unknown; CompareIC::State state = ICCompareStub::CompareState(code->stub_info()); return TypeFromCompareType(state); } TypeInfo TypeFeedbackOracle::IncrementType(CountOperation* expr) { Handle object = GetInfo(expr->CountBinOpFeedbackId()); TypeInfo unknown = TypeInfo::Unknown(); if (!object->IsCode()) return unknown; Handle code = Handle::cast(object); if (!code->is_binary_op_stub()) return unknown; BinaryOpIC::TypeInfo left_type, right_type, unused_result_type; BinaryOpStub::decode_types_from_minor_key(code->stub_info(), &left_type, &right_type, &unused_result_type); // CountOperations should always have +1 or -1 as their right input. ASSERT(right_type == BinaryOpIC::SMI || right_type == BinaryOpIC::UNINITIALIZED); switch (left_type) { case BinaryOpIC::UNINITIALIZED: case BinaryOpIC::SMI: return TypeInfo::Smi(); case BinaryOpIC::INT32: return TypeInfo::Integer32(); case BinaryOpIC::NUMBER: return TypeInfo::Double(); case BinaryOpIC::STRING: case BinaryOpIC::GENERIC: return unknown; default: return unknown; } UNREACHABLE(); return unknown; } void TypeFeedbackOracle::CollectPolymorphicMaps(Handle code, SmallMapList* types) { MapHandleList maps; code->FindAllMaps(&maps); types->Reserve(maps.length(), zone()); for (int i = 0; i < maps.length(); i++) { Handle map(maps.at(i)); if (!CanRetainOtherContext(*map, *native_context_)) { types->AddMapIfMissing(map, zone()); } } } void TypeFeedbackOracle::CollectReceiverTypes(TypeFeedbackId ast_id, Handle name, Code::Flags flags, SmallMapList* types) { Handle object = GetInfo(ast_id); if (object->IsUndefined() || object->IsSmi()) return; if (object.is_identical_to(isolate_->builtins()->StoreIC_GlobalProxy())) { // TODO(fschneider): We could collect the maps and signal that // we need a generic store (or load) here. ASSERT(Handle::cast(object)->ic_state() == GENERIC); } else if (object->IsMap()) { types->AddMapIfMissing(Handle::cast(object), zone()); } else if (Handle::cast(object)->ic_state() == POLYMORPHIC) { CollectPolymorphicMaps(Handle::cast(object), types); } else if (FLAG_collect_megamorphic_maps_from_stub_cache && Handle::cast(object)->ic_state() == MEGAMORPHIC) { types->Reserve(4, zone()); ASSERT(object->IsCode()); isolate_->stub_cache()->CollectMatchingMaps(types, name, flags, native_context_, zone()); } } // Check if a map originates from a given native context. We use this // information to filter out maps from different context to avoid // retaining objects from different tabs in Chrome via optimized code. bool TypeFeedbackOracle::CanRetainOtherContext(Map* map, Context* native_context) { Object* constructor = NULL; while (!map->prototype()->IsNull()) { constructor = map->constructor(); if (!constructor->IsNull()) { // If the constructor is not null or a JSFunction, we have to // conservatively assume that it may retain a native context. if (!constructor->IsJSFunction()) return true; // Check if the constructor directly references a foreign context. if (CanRetainOtherContext(JSFunction::cast(constructor), native_context)) { return true; } } map = HeapObject::cast(map->prototype())->map(); } constructor = map->constructor(); if (constructor->IsNull()) return false; JSFunction* function = JSFunction::cast(constructor); return CanRetainOtherContext(function, native_context); } bool TypeFeedbackOracle::CanRetainOtherContext(JSFunction* function, Context* native_context) { return function->context()->global_object() != native_context->global_object() && function->context()->global_object() != native_context->builtins(); } void TypeFeedbackOracle::CollectKeyedReceiverTypes(TypeFeedbackId ast_id, SmallMapList* types) { Handle object = GetInfo(ast_id); if (!object->IsCode()) return; Handle code = Handle::cast(object); if (code->kind() == Code::KEYED_LOAD_IC || code->kind() == Code::KEYED_STORE_IC) { CollectPolymorphicMaps(code, types); } } byte TypeFeedbackOracle::ToBooleanTypes(TypeFeedbackId id) { Handle object = GetInfo(id); return object->IsCode() ? Handle::cast(object)->to_boolean_state() : 0; } byte TypeFeedbackOracle::CompareNilTypes(CompareOperation* expr) { Handle object = GetInfo(expr->CompareOperationFeedbackId()); if (object->IsCode() && Handle::cast(object)->is_compare_nil_ic_stub()) { return Handle::cast(object)->compare_nil_types(); } else { return CompareNilICStub::Types::FullCompare().ToIntegral(); } } // Things are a bit tricky here: The iterator for the RelocInfos and the infos // themselves are not GC-safe, so we first get all infos, then we create the // dictionary (possibly triggering GC), and finally we relocate the collected // infos before we process them. void TypeFeedbackOracle::BuildDictionary(Handle code) { DisallowHeapAllocation no_allocation; ZoneList infos(16, zone()); HandleScope scope(isolate_); GetRelocInfos(code, &infos); CreateDictionary(code, &infos); ProcessRelocInfos(&infos); ProcessTypeFeedbackCells(code); // Allocate handle in the parent scope. dictionary_ = scope.CloseAndEscape(dictionary_); } void TypeFeedbackOracle::GetRelocInfos(Handle code, ZoneList* infos) { int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET_WITH_ID); for (RelocIterator it(*code, mask); !it.done(); it.next()) { infos->Add(*it.rinfo(), zone()); } } void TypeFeedbackOracle::CreateDictionary(Handle code, ZoneList* infos) { AllowHeapAllocation allocation_allowed; int cell_count = code->type_feedback_info()->IsTypeFeedbackInfo() ? TypeFeedbackInfo::cast(code->type_feedback_info())-> type_feedback_cells()->CellCount() : 0; int length = infos->length() + cell_count; byte* old_start = code->instruction_start(); dictionary_ = isolate()->factory()->NewUnseededNumberDictionary(length); byte* new_start = code->instruction_start(); RelocateRelocInfos(infos, old_start, new_start); } void TypeFeedbackOracle::RelocateRelocInfos(ZoneList* infos, byte* old_start, byte* new_start) { for (int i = 0; i < infos->length(); i++) { RelocInfo* info = &(*infos)[i]; info->set_pc(new_start + (info->pc() - old_start)); } } void TypeFeedbackOracle::ProcessRelocInfos(ZoneList* infos) { for (int i = 0; i < infos->length(); i++) { RelocInfo reloc_entry = (*infos)[i]; Address target_address = reloc_entry.target_address(); TypeFeedbackId ast_id = TypeFeedbackId(static_cast((*infos)[i].data())); Code* target = Code::GetCodeFromTargetAddress(target_address); switch (target->kind()) { case Code::LOAD_IC: case Code::STORE_IC: case Code::CALL_IC: case Code::KEYED_CALL_IC: if (target->ic_state() == MONOMORPHIC) { if (target->kind() == Code::CALL_IC && target->check_type() != RECEIVER_MAP_CHECK) { SetInfo(ast_id, Smi::FromInt(target->check_type())); } else { Object* map = target->FindFirstMap(); if (map == NULL) { SetInfo(ast_id, static_cast(target)); } else if (!CanRetainOtherContext(Map::cast(map), *native_context_)) { Map* feedback = Map::cast(map)->CurrentMapForDeprecated(); if (feedback != NULL) SetInfo(ast_id, feedback); } } } else { SetInfo(ast_id, target); } break; case Code::KEYED_LOAD_IC: case Code::KEYED_STORE_IC: if (target->ic_state() == MONOMORPHIC || target->ic_state() == POLYMORPHIC) { SetInfo(ast_id, target); } break; case Code::UNARY_OP_IC: case Code::BINARY_OP_IC: case Code::COMPARE_IC: case Code::TO_BOOLEAN_IC: case Code::COMPARE_NIL_IC: SetInfo(ast_id, target); break; default: break; } } } void TypeFeedbackOracle::ProcessTypeFeedbackCells(Handle code) { Object* raw_info = code->type_feedback_info(); if (!raw_info->IsTypeFeedbackInfo()) return; Handle cache( TypeFeedbackInfo::cast(raw_info)->type_feedback_cells()); for (int i = 0; i < cache->CellCount(); i++) { TypeFeedbackId ast_id = cache->AstId(i); Cell* cell = cache->GetCell(i); Object* value = cell->value(); if (value->IsSmi() || (value->IsJSFunction() && !CanRetainOtherContext(JSFunction::cast(value), *native_context_))) { SetInfo(ast_id, cell); } } } void TypeFeedbackOracle::SetInfo(TypeFeedbackId ast_id, Object* target) { ASSERT(dictionary_->FindEntry(IdToKey(ast_id)) == UnseededNumberDictionary::kNotFound); MaybeObject* maybe_result = dictionary_->AtNumberPut(IdToKey(ast_id), target); USE(maybe_result); #ifdef DEBUG Object* result = NULL; // Dictionary has been allocated with sufficient size for all elements. ASSERT(maybe_result->ToObject(&result)); ASSERT(*dictionary_ == result); #endif } } } // namespace v8::internal