diff options
Diffstat (limited to 'deps/v8/src/ic.cc')
-rw-r--r-- | deps/v8/src/ic.cc | 218 |
1 files changed, 164 insertions, 54 deletions
diff --git a/deps/v8/src/ic.cc b/deps/v8/src/ic.cc index 0f76a9a06c..d5056a9ce8 100644 --- a/deps/v8/src/ic.cc +++ b/deps/v8/src/ic.cc @@ -167,7 +167,7 @@ static bool HasNormalObjectsInPrototypeChain(Isolate* isolate, LookupResult* lookup, Object* receiver) { Object* end = lookup->IsProperty() - ? lookup->holder() : isolate->heap()->null_value(); + ? lookup->holder() : Object::cast(isolate->heap()->null_value()); for (Object* current = receiver; current != end; current = current->GetPrototype()) { @@ -1084,14 +1084,22 @@ MaybeObject* KeyedLoadIC::GetElementStubWithoutMapCheck( } -MaybeObject* KeyedLoadIC::ConstructMegamorphicStub( +MaybeObject* KeyedLoadIC::ComputePolymorphicStub( MapList* receiver_maps, - CodeList* targets, StrictModeFlag strict_mode) { + CodeList handler_ics(receiver_maps->length()); + for (int i = 0; i < receiver_maps->length(); ++i) { + Map* receiver_map(receiver_maps->at(i)); + MaybeObject* maybe_cached_stub = ComputeMonomorphicStubWithoutMapCheck( + receiver_map, strict_mode); + Code* cached_stub; + if (!maybe_cached_stub->To(&cached_stub)) return maybe_cached_stub; + handler_ics.Add(cached_stub); + } Object* object; KeyedLoadStubCompiler compiler; - MaybeObject* maybe_code = compiler.CompileLoadMegamorphic(receiver_maps, - targets); + MaybeObject* maybe_code = compiler.CompileLoadPolymorphic(receiver_maps, + &handler_ics); if (!maybe_code->ToObject(&object)) return maybe_code; isolate()->counters()->keyed_load_polymorphic_stubs()->Increment(); PROFILE(isolate(), CodeCreateEvent( @@ -1243,7 +1251,7 @@ MaybeObject* KeyedLoadIC::Load(State state, stub = indexed_interceptor_stub(); } else if (key->IsSmi() && (target() != non_strict_arguments_stub())) { MaybeObject* maybe_stub = ComputeStub(receiver, - false, + LOAD, kNonStrictMode, stub); stub = maybe_stub->IsFailure() ? @@ -1351,7 +1359,7 @@ static bool StoreICableLookup(LookupResult* lookup) { } -static bool LookupForWrite(JSReceiver* receiver, +static bool LookupForWrite(JSObject* receiver, String* name, LookupResult* lookup) { receiver->LocalLookup(name, lookup); @@ -1359,12 +1367,10 @@ static bool LookupForWrite(JSReceiver* receiver, return false; } - if (lookup->type() == INTERCEPTOR) { - JSObject* object = JSObject::cast(receiver); - if (object->GetNamedInterceptor()->setter()->IsUndefined()) { - object->LocalLookupRealNamedProperty(name, lookup); - return StoreICableLookup(lookup); - } + if (lookup->type() == INTERCEPTOR && + receiver->GetNamedInterceptor()->setter()->IsUndefined()) { + receiver->LocalLookupRealNamedProperty(name, lookup); + return StoreICableLookup(lookup); } return true; @@ -1376,28 +1382,28 @@ MaybeObject* StoreIC::Store(State state, Handle<Object> object, Handle<String> name, Handle<Object> value) { - // If the object is undefined or null it's illegal to try to set any - // properties on it; throw a TypeError in that case. - if (object->IsUndefined() || object->IsNull()) { - return TypeError("non_object_property_store", object, name); - } + if (!object->IsJSObject()) { + // Handle proxies. + if (object->IsJSProxy()) { + return JSProxy::cast(*object)-> + SetProperty(*name, *value, NONE, strict_mode); + } + + // If the object is undefined or null it's illegal to try to set any + // properties on it; throw a TypeError in that case. + if (object->IsUndefined() || object->IsNull()) { + return TypeError("non_object_property_store", object, name); + } - if (!object->IsJSReceiver()) { // The length property of string values is read-only. Throw in strict mode. if (strict_mode == kStrictMode && object->IsString() && name->Equals(isolate()->heap()->length_symbol())) { return TypeError("strict_read_only_property", object, name); } - // Ignore stores where the receiver is not a JSObject. + // Ignore other stores where the receiver is not a JSObject. return *value; } - // Handle proxies. - if (object->IsJSProxy()) { - return JSReceiver::cast(*object)-> - SetProperty(*name, *value, NONE, strict_mode); - } - Handle<JSObject> receiver = Handle<JSObject>::cast(object); // Check if the given name is an array index. @@ -1595,14 +1601,15 @@ void KeyedIC::GetReceiverMapsForStub(Code* stub, MapList* result) { MaybeObject* KeyedIC::ComputeStub(JSObject* receiver, - bool is_store, + StubKind stub_kind, StrictModeFlag strict_mode, Code* generic_stub) { State ic_state = target()->ic_state(); - if (ic_state == UNINITIALIZED || ic_state == PREMONOMORPHIC) { + if ((ic_state == UNINITIALIZED || ic_state == PREMONOMORPHIC) && + !IsTransitionStubKind(stub_kind)) { Code* monomorphic_stub; MaybeObject* maybe_stub = ComputeMonomorphicStub(receiver, - is_store, + stub_kind, strict_mode, generic_stub); if (!maybe_stub->To(&monomorphic_stub)) return maybe_stub; @@ -1621,9 +1628,21 @@ MaybeObject* KeyedIC::ComputeStub(JSObject* receiver, // Determine the list of receiver maps that this call site has seen, // adding the map that was just encountered. MapList target_receiver_maps; - GetReceiverMapsForStub(target(), &target_receiver_maps); - if (!AddOneReceiverMapIfMissing(&target_receiver_maps, receiver->map())) { - // If the miss wasn't due to an unseen map, a MEGAMORPHIC stub + if (ic_state == UNINITIALIZED || ic_state == PREMONOMORPHIC) { + target_receiver_maps.Add(receiver->map()); + } else { + GetReceiverMapsForStub(target(), &target_receiver_maps); + } + bool map_added = + AddOneReceiverMapIfMissing(&target_receiver_maps, receiver->map()); + if (IsTransitionStubKind(stub_kind)) { + MaybeObject* maybe_map = ComputeTransitionedMap(receiver, stub_kind); + Map* new_map = NULL; + if (!maybe_map->To(&new_map)) return maybe_map; + map_added |= AddOneReceiverMapIfMissing(&target_receiver_maps, new_map); + } + if (!map_added) { + // If the miss wasn't due to an unseen map, a polymorphic stub // won't help, use the generic stub. return generic_stub; } @@ -1644,21 +1663,9 @@ MaybeObject* KeyedIC::ComputeStub(JSObject* receiver, ASSERT(maybe_cached_stub->IsCode()); return Code::cast(maybe_cached_stub); } - // Collect MONOMORPHIC stubs for all target_receiver_maps. - CodeList handler_ics(target_receiver_maps.length()); - for (int i = 0; i < target_receiver_maps.length(); ++i) { - Map* receiver_map(target_receiver_maps.at(i)); - MaybeObject* maybe_cached_stub = ComputeMonomorphicStubWithoutMapCheck( - receiver_map, strict_mode); - Code* cached_stub; - if (!maybe_cached_stub->To(&cached_stub)) return maybe_cached_stub; - handler_ics.Add(cached_stub); - } - // Build the MEGAMORPHIC stub. + MaybeObject* maybe_stub = + ComputePolymorphicStub(&target_receiver_maps, strict_mode); Code* stub; - MaybeObject* maybe_stub = ConstructMegamorphicStub(&target_receiver_maps, - &handler_ics, - strict_mode); if (!maybe_stub->To(&stub)) return maybe_stub; MaybeObject* maybe_update = cache->Update(&target_receiver_maps, flags, stub); if (maybe_update->IsFailure()) return maybe_update; @@ -1675,6 +1682,7 @@ MaybeObject* KeyedIC::ComputeMonomorphicStubWithoutMapCheck( } else { ASSERT(receiver_map->has_dictionary_elements() || receiver_map->has_fast_elements() || + receiver_map->has_fast_smi_only_elements() || receiver_map->has_fast_double_elements() || receiver_map->has_external_array_elements()); bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE; @@ -1685,17 +1693,18 @@ MaybeObject* KeyedIC::ComputeMonomorphicStubWithoutMapCheck( MaybeObject* KeyedIC::ComputeMonomorphicStub(JSObject* receiver, - bool is_store, + StubKind stub_kind, StrictModeFlag strict_mode, Code* generic_stub) { Code* result = NULL; if (receiver->HasFastElements() || + receiver->HasFastSmiOnlyElements() || receiver->HasExternalArrayElements() || receiver->HasFastDoubleElements() || receiver->HasDictionaryElements()) { MaybeObject* maybe_stub = isolate()->stub_cache()->ComputeKeyedLoadOrStoreElement( - receiver, is_store, strict_mode); + receiver, stub_kind, strict_mode); if (!maybe_stub->To(&result)) return maybe_stub; } else { result = generic_stub; @@ -1704,6 +1713,21 @@ MaybeObject* KeyedIC::ComputeMonomorphicStub(JSObject* receiver, } +MaybeObject* KeyedIC::ComputeTransitionedMap(JSObject* receiver, + StubKind stub_kind) { + switch (stub_kind) { + case KeyedIC::STORE_TRANSITION_SMI_TO_OBJECT: + case KeyedIC::STORE_TRANSITION_DOUBLE_TO_OBJECT: + return receiver->GetElementsTransitionMap(FAST_ELEMENTS); + case KeyedIC::STORE_TRANSITION_SMI_TO_DOUBLE: + return receiver->GetElementsTransitionMap(FAST_DOUBLE_ELEMENTS); + default: + UNREACHABLE(); + return NULL; + } +} + + MaybeObject* KeyedStoreIC::GetElementStubWithoutMapCheck( bool is_js_array, ElementsKind elements_kind) { @@ -1711,14 +1735,88 @@ MaybeObject* KeyedStoreIC::GetElementStubWithoutMapCheck( } -MaybeObject* KeyedStoreIC::ConstructMegamorphicStub( +// If |map| is contained in |maps_list|, returns |map|; otherwise returns NULL. +Map* GetMapIfPresent(Map* map, MapList* maps_list) { + for (int i = 0; i < maps_list->length(); ++i) { + if (maps_list->at(i) == map) return map; + } + return NULL; +} + + +// Returns the most generic transitioned map for |map| that's found in +// |maps_list|, or NULL if no transitioned map for |map| is found at all. +Map* GetTransitionedMap(Map* map, MapList* maps_list) { + ElementsKind elements_kind = map->elements_kind(); + if (elements_kind == FAST_ELEMENTS) { + return NULL; + } + if (elements_kind == FAST_DOUBLE_ELEMENTS) { + bool dummy = true; + Map* fast_map = map->LookupElementsTransitionMap(FAST_ELEMENTS, &dummy); + if (fast_map == NULL) return NULL; + return GetMapIfPresent(fast_map, maps_list); + } + if (elements_kind == FAST_SMI_ONLY_ELEMENTS) { + bool dummy = true; + Map* double_map = map->LookupElementsTransitionMap(FAST_DOUBLE_ELEMENTS, + &dummy); + // In the current implementation, if the DOUBLE map doesn't exist, the + // FAST map can't exist either. + if (double_map == NULL) return NULL; + Map* fast_map = map->LookupElementsTransitionMap(FAST_ELEMENTS, &dummy); + if (fast_map == NULL) { + return GetMapIfPresent(double_map, maps_list); + } + // Both double_map and fast_map are non-NULL. Return fast_map if it's in + // maps_list, double_map otherwise. + Map* fast_map_present = GetMapIfPresent(fast_map, maps_list); + if (fast_map_present != NULL) return fast_map_present; + return GetMapIfPresent(double_map, maps_list); + } + return NULL; +} + + +MaybeObject* KeyedStoreIC::ComputePolymorphicStub( MapList* receiver_maps, - CodeList* targets, StrictModeFlag strict_mode) { + // TODO(yangguo): <remove> + Code* generic_stub = (strict_mode == kStrictMode) + ? isolate()->builtins()->builtin(Builtins::kKeyedStoreIC_Generic_Strict) + : isolate()->builtins()->builtin(Builtins::kKeyedStoreIC_Generic); + // </remove> + + // Collect MONOMORPHIC stubs for all target_receiver_maps. + CodeList handler_ics(receiver_maps->length()); + MapList transitioned_maps(receiver_maps->length()); + for (int i = 0; i < receiver_maps->length(); ++i) { + Map* receiver_map(receiver_maps->at(i)); + MaybeObject* maybe_cached_stub = NULL; + Map* transitioned_map = GetTransitionedMap(receiver_map, receiver_maps); + if (transitioned_map != NULL) { + // TODO(yangguo): Enable this code! + // maybe_cached_stub = FastElementsConversionStub( + // receiver_map->elements_kind(), // original elements_kind + // transitioned_map->elements_kind(), + // receiver_map->instance_type() == JS_ARRAY_TYPE, // is_js_array + // strict_mode_).TryGetCode(); + // TODO(yangguo): <remove> + maybe_cached_stub = generic_stub; + // </remove> + } else { + maybe_cached_stub = ComputeMonomorphicStubWithoutMapCheck( + receiver_map, strict_mode); + } + Code* cached_stub; + if (!maybe_cached_stub->To(&cached_stub)) return maybe_cached_stub; + handler_ics.Add(cached_stub); + transitioned_maps.Add(transitioned_map); + } Object* object; KeyedStoreStubCompiler compiler(strict_mode); - MaybeObject* maybe_code = compiler.CompileStoreMegamorphic(receiver_maps, - targets); + MaybeObject* maybe_code = compiler.CompileStorePolymorphic( + receiver_maps, &handler_ics, &transitioned_maps); if (!maybe_code->ToObject(&object)) return maybe_code; isolate()->counters()->keyed_store_polymorphic_stubs()->Increment(); PROFILE(isolate(), CodeCreateEvent( @@ -1786,9 +1884,21 @@ MaybeObject* KeyedStoreIC::Store(State state, stub = non_strict_arguments_stub(); } else if (!force_generic) { if (key->IsSmi() && (target() != non_strict_arguments_stub())) { + StubKind stub_kind = STORE_NO_TRANSITION; + if (receiver->GetElementsKind() == FAST_SMI_ONLY_ELEMENTS) { + if (value->IsHeapNumber()) { + stub_kind = STORE_TRANSITION_SMI_TO_DOUBLE; + } else if (value->IsHeapObject()) { + stub_kind = STORE_TRANSITION_SMI_TO_OBJECT; + } + } else if (receiver->GetElementsKind() == FAST_DOUBLE_ELEMENTS) { + if (!value->IsSmi() && !value->IsHeapNumber()) { + stub_kind = STORE_TRANSITION_DOUBLE_TO_OBJECT; + } + } HandleScope scope(isolate()); MaybeObject* maybe_stub = ComputeStub(receiver, - true, + stub_kind, strict_mode, stub); stub = maybe_stub->IsFailure() ? @@ -2402,7 +2512,7 @@ RUNTIME_FUNCTION(MaybeObject*, BinaryOp_Patch) { Handle<JSFunction> builtin_function(JSFunction::cast(builtin), isolate); bool caught_exception; - Object** builtin_args[] = { right.location() }; + Handle<Object> builtin_args[] = { right }; Handle<Object> result = Execution::Call(builtin_function, left, ARRAY_SIZE(builtin_args), |