| Index: src/ic.cc
|
| ===================================================================
|
| --- src/ic.cc (revision 8618)
|
| +++ src/ic.cc (working copy)
|
| @@ -578,13 +578,7 @@
|
| // out of bounds, update the state to record this fact.
|
| if (StringStubState::decode(*extra_ic_state) == DEFAULT_STRING_STUB &&
|
| argc >= 1 && args[1]->IsNumber()) {
|
| - double index;
|
| - if (args[1]->IsSmi()) {
|
| - index = Smi::cast(args[1])->value();
|
| - } else {
|
| - ASSERT(args[1]->IsHeapNumber());
|
| - index = DoubleToInteger(HeapNumber::cast(args[1])->value());
|
| - }
|
| + double index = DoubleToInteger(args.number_at(1));
|
| if (index < 0 || index >= string->length()) {
|
| *extra_ic_state =
|
| StringStubState::update(*extra_ic_state,
|
| @@ -799,18 +793,35 @@
|
| return TypeError("non_object_property_call", object, key);
|
| }
|
|
|
| - if (FLAG_use_ic && state != MEGAMORPHIC && !object->IsAccessCheckNeeded()) {
|
| + if (FLAG_use_ic && state != MEGAMORPHIC && object->IsHeapObject()) {
|
| int argc = target()->arguments_count();
|
| InLoopFlag in_loop = target()->ic_in_loop();
|
| - MaybeObject* maybe_code = isolate()->stub_cache()->ComputeCallMegamorphic(
|
| - argc, in_loop, Code::KEYED_CALL_IC, Code::kNoExtraICState);
|
| - Object* code;
|
| - if (maybe_code->ToObject(&code)) {
|
| - set_target(Code::cast(code));
|
| + Heap* heap = Handle<HeapObject>::cast(object)->GetHeap();
|
| + Map* map = heap->non_strict_arguments_elements_map();
|
| + if (object->IsJSObject() &&
|
| + Handle<JSObject>::cast(object)->elements()->map() == map) {
|
| + MaybeObject* maybe_code = isolate()->stub_cache()->ComputeCallArguments(
|
| + argc, in_loop, Code::KEYED_CALL_IC);
|
| + Object* code;
|
| + if (maybe_code->ToObject(&code)) {
|
| + set_target(Code::cast(code));
|
| #ifdef DEBUG
|
| - TraceIC(
|
| - "KeyedCallIC", key, state, target(), in_loop ? " (in-loop)" : "");
|
| + TraceIC(
|
| + "KeyedCallIC", key, state, target(), in_loop ? " (in-loop)" : "");
|
| #endif
|
| + }
|
| + } else if (FLAG_use_ic && state != MEGAMORPHIC &&
|
| + !object->IsAccessCheckNeeded()) {
|
| + MaybeObject* maybe_code = isolate()->stub_cache()->ComputeCallMegamorphic(
|
| + argc, in_loop, Code::KEYED_CALL_IC, Code::kNoExtraICState);
|
| + Object* code;
|
| + if (maybe_code->ToObject(&code)) {
|
| + set_target(Code::cast(code));
|
| +#ifdef DEBUG
|
| + TraceIC(
|
| + "KeyedCallIC", key, state, target(), in_loop ? " (in-loop)" : "");
|
| +#endif
|
| + }
|
| }
|
| }
|
|
|
| @@ -849,37 +860,40 @@
|
| }
|
|
|
| if (FLAG_use_ic) {
|
| - Code* non_monomorphic_stub =
|
| - (state == UNINITIALIZED) ? pre_monomorphic_stub() : megamorphic_stub();
|
| -
|
| // Use specialized code for getting the length of strings and
|
| // string wrapper objects. The length property of string wrapper
|
| // objects is read-only and therefore always returns the length of
|
| // the underlying string value. See ECMA-262 15.5.5.1.
|
| if ((object->IsString() || object->IsStringWrapper()) &&
|
| name->Equals(isolate()->heap()->length_symbol())) {
|
| - HandleScope scope(isolate());
|
| -#ifdef DEBUG
|
| - if (FLAG_trace_ic) PrintF("[LoadIC : +#length /string]\n");
|
| -#endif
|
| - if (state == PREMONOMORPHIC) {
|
| + AssertNoAllocation no_allocation;
|
| + Code* stub = NULL;
|
| + if (state == UNINITIALIZED) {
|
| + stub = pre_monomorphic_stub();
|
| + } else if (state == PREMONOMORPHIC) {
|
| if (object->IsString()) {
|
| - set_target(isolate()->builtins()->builtin(
|
| - Builtins::kLoadIC_StringLength));
|
| + stub = isolate()->builtins()->builtin(
|
| + Builtins::kLoadIC_StringLength);
|
| } else {
|
| - set_target(isolate()->builtins()->builtin(
|
| - Builtins::kLoadIC_StringWrapperLength));
|
| + stub = isolate()->builtins()->builtin(
|
| + Builtins::kLoadIC_StringWrapperLength);
|
| }
|
| } else if (state == MONOMORPHIC && object->IsStringWrapper()) {
|
| - set_target(isolate()->builtins()->builtin(
|
| - Builtins::kLoadIC_StringWrapperLength));
|
| - } else {
|
| - set_target(non_monomorphic_stub);
|
| + stub = isolate()->builtins()->builtin(
|
| + Builtins::kLoadIC_StringWrapperLength);
|
| + } else if (state != MEGAMORPHIC) {
|
| + stub = megamorphic_stub();
|
| }
|
| + if (stub != NULL) {
|
| + set_target(stub);
|
| +#ifdef DEBUG
|
| + if (FLAG_trace_ic) PrintF("[LoadIC : +#length /string]\n");
|
| +#endif
|
| + }
|
| // Get the string if we have a string wrapper object.
|
| if (object->IsJSValue()) {
|
| - object = Handle<Object>(Handle<JSValue>::cast(object)->value(),
|
| - isolate());
|
| + return Smi::FromInt(
|
| + String::cast(Handle<JSValue>::cast(object)->value())->length());
|
| }
|
| return Smi::FromInt(String::cast(*object)->length());
|
| }
|
| @@ -887,14 +901,21 @@
|
| // Use specialized code for getting the length of arrays.
|
| if (object->IsJSArray() &&
|
| name->Equals(isolate()->heap()->length_symbol())) {
|
| + AssertNoAllocation no_allocation;
|
| + Code* stub = NULL;
|
| + if (state == UNINITIALIZED) {
|
| + stub = pre_monomorphic_stub();
|
| + } else if (state == PREMONOMORPHIC) {
|
| + stub = isolate()->builtins()->builtin(
|
| + Builtins::kLoadIC_ArrayLength);
|
| + } else if (state != MEGAMORPHIC) {
|
| + stub = megamorphic_stub();
|
| + }
|
| + if (stub != NULL) {
|
| + set_target(stub);
|
| #ifdef DEBUG
|
| - if (FLAG_trace_ic) PrintF("[LoadIC : +#length /array]\n");
|
| + if (FLAG_trace_ic) PrintF("[LoadIC : +#length /array]\n");
|
| #endif
|
| - if (state == PREMONOMORPHIC) {
|
| - set_target(isolate()->builtins()->builtin(
|
| - Builtins::kLoadIC_ArrayLength));
|
| - } else {
|
| - set_target(non_monomorphic_stub);
|
| }
|
| return JSArray::cast(*object)->length();
|
| }
|
| @@ -903,14 +924,22 @@
|
| if (object->IsJSFunction() &&
|
| name->Equals(isolate()->heap()->prototype_symbol()) &&
|
| JSFunction::cast(*object)->should_have_prototype()) {
|
| + { AssertNoAllocation no_allocation;
|
| + Code* stub = NULL;
|
| + if (state == UNINITIALIZED) {
|
| + stub = pre_monomorphic_stub();
|
| + } else if (state == PREMONOMORPHIC) {
|
| + stub = isolate()->builtins()->builtin(
|
| + Builtins::kLoadIC_FunctionPrototype);
|
| + } else if (state != MEGAMORPHIC) {
|
| + stub = megamorphic_stub();
|
| + }
|
| + if (stub != NULL) {
|
| + set_target(stub);
|
| #ifdef DEBUG
|
| - if (FLAG_trace_ic) PrintF("[LoadIC : +#prototype /function]\n");
|
| + if (FLAG_trace_ic) PrintF("[LoadIC : +#prototype /function]\n");
|
| #endif
|
| - if (state == PREMONOMORPHIC) {
|
| - set_target(isolate()->builtins()->builtin(
|
| - Builtins::kLoadIC_FunctionPrototype));
|
| - } else {
|
| - set_target(non_monomorphic_stub);
|
| + }
|
| }
|
| return Accessors::FunctionGetPrototype(*object, 0);
|
| }
|
| @@ -927,7 +956,7 @@
|
|
|
| // If we did not find a property, check if we need to throw an exception.
|
| if (!lookup.IsProperty()) {
|
| - if (FLAG_strict || IsContextual(object)) {
|
| + if (IsContextual(object)) {
|
| return ReferenceError("not_defined", name);
|
| }
|
| LOG(isolate(), SuspectReadEvent(*name, *object));
|
| @@ -1068,28 +1097,13 @@
|
| }
|
|
|
|
|
| -String* KeyedLoadIC::GetStubNameForCache(IC::State ic_state) {
|
| - if (ic_state == MONOMORPHIC) {
|
| - return isolate()->heap()->KeyedLoadSpecializedMonomorphic_symbol();
|
| - } else {
|
| - ASSERT(ic_state == MEGAMORPHIC);
|
| - return isolate()->heap()->KeyedLoadSpecializedPolymorphic_symbol();
|
| - }
|
| +MaybeObject* KeyedLoadIC::GetElementStubWithoutMapCheck(
|
| + bool is_js_array,
|
| + JSObject::ElementsKind elements_kind) {
|
| + return KeyedLoadElementStub(elements_kind).TryGetCode();
|
| }
|
|
|
|
|
| -MaybeObject* KeyedLoadIC::GetFastElementStubWithoutMapCheck(
|
| - bool is_js_array) {
|
| - return KeyedLoadFastElementStub().TryGetCode();
|
| -}
|
| -
|
| -
|
| -MaybeObject* KeyedLoadIC::GetExternalArrayStubWithoutMapCheck(
|
| - ExternalArrayType array_type) {
|
| - return KeyedLoadExternalArrayStub(array_type).TryGetCode();
|
| -}
|
| -
|
| -
|
| MaybeObject* KeyedLoadIC::ConstructMegamorphicStub(
|
| MapList* receiver_maps,
|
| CodeList* targets,
|
| @@ -1201,10 +1215,8 @@
|
| LookupForRead(*object, *name, &lookup);
|
|
|
| // If we did not find a property, check if we need to throw an exception.
|
| - if (!lookup.IsProperty()) {
|
| - if (FLAG_strict || IsContextual(object)) {
|
| - return ReferenceError("not_defined", name);
|
| - }
|
| + if (!lookup.IsProperty() && IsContextual(object)) {
|
| + return ReferenceError("not_defined", name);
|
| }
|
|
|
| if (FLAG_use_ic) {
|
| @@ -1243,9 +1255,13 @@
|
| }
|
| } else if (object->IsJSObject()) {
|
| JSObject* receiver = JSObject::cast(*object);
|
| - if (receiver->HasIndexedInterceptor()) {
|
| + Heap* heap = Handle<JSObject>::cast(object)->GetHeap();
|
| + Map* elements_map = Handle<JSObject>::cast(object)->elements()->map();
|
| + if (elements_map == heap->non_strict_arguments_elements_map()) {
|
| + stub = non_strict_arguments_stub();
|
| + } else if (receiver->HasIndexedInterceptor()) {
|
| stub = indexed_interceptor_stub();
|
| - } else if (key->IsSmi()) {
|
| + } else if (key->IsSmi() && (target() != non_strict_arguments_stub())) {
|
| MaybeObject* maybe_stub = ComputeStub(receiver,
|
| false,
|
| kNonStrictMode,
|
| @@ -1355,15 +1371,16 @@
|
| }
|
|
|
|
|
| -static bool LookupForWrite(JSObject* object,
|
| +static bool LookupForWrite(JSReceiver* receiver,
|
| String* name,
|
| LookupResult* lookup) {
|
| - object->LocalLookup(name, lookup);
|
| + receiver->LocalLookup(name, lookup);
|
| if (!StoreICableLookup(lookup)) {
|
| return false;
|
| }
|
|
|
| if (lookup->type() == INTERCEPTOR) {
|
| + JSObject* object = JSObject::cast(receiver);
|
| if (object->GetNamedInterceptor()->setter()->IsUndefined()) {
|
| object->LocalLookupRealNamedProperty(name, lookup);
|
| return StoreICableLookup(lookup);
|
| @@ -1385,7 +1402,7 @@
|
| return TypeError("non_object_property_store", object, name);
|
| }
|
|
|
| - if (!object->IsJSObject()) {
|
| + 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())) {
|
| @@ -1395,6 +1412,12 @@
|
| 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.
|
| @@ -1409,7 +1432,7 @@
|
| // Use specialized code for setting the length of arrays.
|
| if (receiver->IsJSArray()
|
| && name->Equals(isolate()->heap()->length_symbol())
|
| - && receiver->AllowsSetElementsLength()) {
|
| + && JSArray::cast(*receiver)->AllowsSetElementsLength()) {
|
| #ifdef DEBUG
|
| if (FLAG_trace_ic) PrintF("[StoreIC : +#length /array]\n");
|
| #endif
|
| @@ -1596,18 +1619,14 @@
|
| StrictModeFlag strict_mode,
|
| Code* generic_stub) {
|
| State ic_state = target()->ic_state();
|
| - Code* monomorphic_stub;
|
| - // Always compute the MONOMORPHIC stub, even if the MEGAMORPHIC stub ends up
|
| - // being used. This is necessary because the megamorphic stub needs to have
|
| - // access to more information than what is stored in the receiver map in some
|
| - // cases (external arrays need the array type from the MONOMORPHIC stub).
|
| - MaybeObject* maybe_stub = ComputeMonomorphicStub(receiver,
|
| - is_store,
|
| - strict_mode,
|
| - generic_stub);
|
| - if (!maybe_stub->To(&monomorphic_stub)) return maybe_stub;
|
| -
|
| if (ic_state == UNINITIALIZED || ic_state == PREMONOMORPHIC) {
|
| + Code* monomorphic_stub;
|
| + MaybeObject* maybe_stub = ComputeMonomorphicStub(receiver,
|
| + is_store,
|
| + strict_mode,
|
| + generic_stub);
|
| + if (!maybe_stub->To(&monomorphic_stub)) return maybe_stub;
|
| +
|
| return monomorphic_stub;
|
| }
|
| ASSERT(target() != generic_stub);
|
| @@ -1629,79 +1648,40 @@
|
| return generic_stub;
|
| }
|
|
|
| - // TODO(1385): Currently MEGAMORPHIC stubs are cached in the receiver map stub
|
| - // cache, but that can put receiver types together from unrelated call sites
|
| - // into the same stub--they always handle the union of all receiver maps seen
|
| - // at all call sites involving the receiver map. This is only an
|
| - // approximation: ideally, there would be a global cache that mapped sets of
|
| - // receiver maps to MEGAMORPHIC stubs. The complexity of the MEGAMORPHIC stub
|
| - // computation also leads to direct manipulation of the stub cache from the IC
|
| - // code, which the global cache solution would avoid.
|
| - Code::Kind kind = this->kind();
|
| - Code::Flags flags = Code::ComputeFlags(kind,
|
| - NOT_IN_LOOP,
|
| - MEGAMORPHIC,
|
| - strict_mode);
|
| - String* megamorphic_name = GetStubNameForCache(MEGAMORPHIC);
|
| - Object* maybe_cached_stub = receiver->map()->FindInCodeCache(megamorphic_name,
|
| - flags);
|
| -
|
| - // Create a set of all receiver maps that have been seen at the IC call site
|
| - // and those seen by the MEGAMORPHIC cached stub, if that's the stub that's
|
| - // been selected.
|
| - MapList receiver_maps;
|
| - if (!maybe_cached_stub->IsUndefined()) {
|
| - GetReceiverMapsForStub(Code::cast(maybe_cached_stub), &receiver_maps);
|
| - }
|
| - bool added_map = false;
|
| - for (int i = 0; i < target_receiver_maps.length(); ++i) {
|
| - if (AddOneReceiverMapIfMissing(&receiver_maps,
|
| - target_receiver_maps.at(i))) {
|
| - added_map = true;
|
| - }
|
| - }
|
| - ASSERT(receiver_maps.length() > 0);
|
| -
|
| - // If the maximum number of receiver maps has been exceeded, use the Generic
|
| + // If the maximum number of receiver maps has been exceeded, use the generic
|
| // version of the IC.
|
| - if (receiver_maps.length() > KeyedIC::kMaxKeyedPolymorphism) {
|
| + if (target_receiver_maps.length() > kMaxKeyedPolymorphism) {
|
| return generic_stub;
|
| }
|
|
|
| - // If no maps have been seen at the call site that aren't in the cached
|
| - // stub, then use it.
|
| - if (!added_map) {
|
| - ASSERT(!maybe_cached_stub->IsUndefined());
|
| + PolymorphicCodeCache* cache = isolate()->heap()->polymorphic_code_cache();
|
| + Code::Flags flags = Code::ComputeFlags(this->kind(),
|
| + NOT_IN_LOOP,
|
| + MEGAMORPHIC,
|
| + strict_mode);
|
| + Object* maybe_cached_stub = cache->Lookup(&target_receiver_maps, flags);
|
| + // If there is a cached stub, use it.
|
| + if (!maybe_cached_stub->IsUndefined()) {
|
| ASSERT(maybe_cached_stub->IsCode());
|
| return Code::cast(maybe_cached_stub);
|
| }
|
| -
|
| - // Lookup all of the receiver maps in the cache, they should all already
|
| - // have MONOMORPHIC stubs.
|
| - CodeList handler_ics(KeyedIC::kMaxKeyedPolymorphism);
|
| - for (int current = 0; current < receiver_maps.length(); ++current) {
|
| - Map* receiver_map(receiver_maps.at(current));
|
| + // 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,
|
| - generic_stub);
|
| + receiver_map, strict_mode);
|
| Code* cached_stub;
|
| - if (!maybe_cached_stub->To(&cached_stub)) {
|
| - return maybe_cached_stub;
|
| - }
|
| + if (!maybe_cached_stub->To(&cached_stub)) return maybe_cached_stub;
|
| handler_ics.Add(cached_stub);
|
| }
|
| -
|
| - Code* stub;
|
| // Build the MEGAMORPHIC stub.
|
| - maybe_stub = ConstructMegamorphicStub(&receiver_maps,
|
| - &handler_ics,
|
| - 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 = receiver->UpdateMapCodeCache(
|
| - megamorphic_name,
|
| - stub);
|
| + MaybeObject* maybe_update = cache->Update(&target_receiver_maps, flags, stub);
|
| if (maybe_update->IsFailure()) return maybe_update;
|
| return stub;
|
| }
|
| @@ -1709,33 +1689,18 @@
|
|
|
| MaybeObject* KeyedIC::ComputeMonomorphicStubWithoutMapCheck(
|
| Map* receiver_map,
|
| - StrictModeFlag strict_mode,
|
| - Code* generic_stub) {
|
| + StrictModeFlag strict_mode) {
|
| if ((receiver_map->instance_type() & kNotStringTag) == 0) {
|
| ASSERT(string_stub() != NULL);
|
| return string_stub();
|
| - } else if (receiver_map->has_external_array_elements()) {
|
| - // Determine the array type from the default MONOMORPHIC already generated
|
| - // stub. There is no other way to determine the type of the external array
|
| - // directly from the receiver type.
|
| - Code::Kind kind = this->kind();
|
| - Code::Flags flags = Code::ComputeMonomorphicFlags(kind,
|
| - NORMAL,
|
| - strict_mode);
|
| - String* monomorphic_name = GetStubNameForCache(MONOMORPHIC);
|
| - Object* maybe_default_stub = receiver_map->FindInCodeCache(monomorphic_name,
|
| - flags);
|
| - if (maybe_default_stub->IsUndefined()) {
|
| - return generic_stub;
|
| - }
|
| - Code* default_stub = Code::cast(maybe_default_stub);
|
| - return GetExternalArrayStubWithoutMapCheck(
|
| - default_stub->external_array_type());
|
| - } else if (receiver_map->has_fast_elements()) {
|
| - bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE;
|
| - return GetFastElementStubWithoutMapCheck(is_js_array);
|
| } else {
|
| - return generic_stub;
|
| + ASSERT(receiver_map->has_dictionary_elements() ||
|
| + receiver_map->has_fast_elements() ||
|
| + receiver_map->has_fast_double_elements() ||
|
| + receiver_map->has_external_array_elements());
|
| + bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE;
|
| + return GetElementStubWithoutMapCheck(is_js_array,
|
| + receiver_map->elements_kind());
|
| }
|
| }
|
|
|
| @@ -1745,16 +1710,14 @@
|
| StrictModeFlag strict_mode,
|
| Code* generic_stub) {
|
| Code* result = NULL;
|
| - if (receiver->HasExternalArrayElements()) {
|
| + if (receiver->HasFastElements() ||
|
| + receiver->HasExternalArrayElements() ||
|
| + receiver->HasFastDoubleElements() ||
|
| + receiver->HasDictionaryElements()) {
|
| MaybeObject* maybe_stub =
|
| - isolate()->stub_cache()->ComputeKeyedLoadOrStoreExternalArray(
|
| + isolate()->stub_cache()->ComputeKeyedLoadOrStoreElement(
|
| receiver, is_store, strict_mode);
|
| if (!maybe_stub->To(&result)) return maybe_stub;
|
| - } else if (receiver->map()->has_fast_elements()) {
|
| - MaybeObject* maybe_stub =
|
| - isolate()->stub_cache()->ComputeKeyedLoadOrStoreFastElement(
|
| - receiver, is_store, strict_mode);
|
| - if (!maybe_stub->To(&result)) return maybe_stub;
|
| } else {
|
| result = generic_stub;
|
| }
|
| @@ -1762,28 +1725,13 @@
|
| }
|
|
|
|
|
| -String* KeyedStoreIC::GetStubNameForCache(IC::State ic_state) {
|
| - if (ic_state == MONOMORPHIC) {
|
| - return isolate()->heap()->KeyedStoreSpecializedMonomorphic_symbol();
|
| - } else {
|
| - ASSERT(ic_state == MEGAMORPHIC);
|
| - return isolate()->heap()->KeyedStoreSpecializedPolymorphic_symbol();
|
| - }
|
| +MaybeObject* KeyedStoreIC::GetElementStubWithoutMapCheck(
|
| + bool is_js_array,
|
| + JSObject::ElementsKind elements_kind) {
|
| + return KeyedStoreElementStub(is_js_array, elements_kind).TryGetCode();
|
| }
|
|
|
|
|
| -MaybeObject* KeyedStoreIC::GetFastElementStubWithoutMapCheck(
|
| - bool is_js_array) {
|
| - return KeyedStoreFastElementStub(is_js_array).TryGetCode();
|
| -}
|
| -
|
| -
|
| -MaybeObject* KeyedStoreIC::GetExternalArrayStubWithoutMapCheck(
|
| - ExternalArrayType array_type) {
|
| - return KeyedStoreExternalArrayStub(array_type).TryGetCode();
|
| -}
|
| -
|
| -
|
| MaybeObject* KeyedStoreIC::ConstructMegamorphicStub(
|
| MapList* receiver_maps,
|
| CodeList* targets,
|
| @@ -1851,15 +1799,22 @@
|
| Code* stub = (strict_mode == kStrictMode)
|
| ? generic_stub_strict()
|
| : generic_stub();
|
| - if (!force_generic) {
|
| - if (object->IsJSObject() && key->IsSmi()) {
|
| - JSObject* receiver = JSObject::cast(*object);
|
| - MaybeObject* maybe_stub = ComputeStub(receiver,
|
| - true,
|
| - strict_mode,
|
| - stub);
|
| - stub = maybe_stub->IsFailure() ?
|
| - NULL : Code::cast(maybe_stub->ToObjectUnchecked());
|
| + if (object->IsJSObject()) {
|
| + JSObject* receiver = JSObject::cast(*object);
|
| + Heap* heap = Handle<JSObject>::cast(object)->GetHeap();
|
| + Map* elements_map = Handle<JSObject>::cast(object)->elements()->map();
|
| + if (elements_map == heap->non_strict_arguments_elements_map()) {
|
| + stub = non_strict_arguments_stub();
|
| + } else if (!force_generic) {
|
| + if (key->IsSmi() && (target() != non_strict_arguments_stub())) {
|
| + HandleScope scope(isolate());
|
| + MaybeObject* maybe_stub = ComputeStub(receiver,
|
| + true,
|
| + strict_mode,
|
| + stub);
|
| + stub = maybe_stub->IsFailure() ?
|
| + NULL : Code::cast(maybe_stub->ToObjectUnchecked());
|
| + }
|
| }
|
| }
|
| if (stub != NULL) set_target(stub);
|
| @@ -2325,25 +2280,21 @@
|
| }
|
|
|
|
|
| -// defined in code-stubs-<arch>.cc
|
| -// Only needed to remove dependency of ic.cc on code-stubs-<arch>.h.
|
| -Handle<Code> GetUnaryOpStub(int key, UnaryOpIC::TypeInfo type_info);
|
| -
|
| -
|
| RUNTIME_FUNCTION(MaybeObject*, UnaryOp_Patch) {
|
| ASSERT(args.length() == 4);
|
|
|
| HandleScope scope(isolate);
|
| Handle<Object> operand = args.at<Object>(0);
|
| - int key = Smi::cast(args[1])->value();
|
| - Token::Value op = static_cast<Token::Value>(Smi::cast(args[2])->value());
|
| + Token::Value op = static_cast<Token::Value>(args.smi_at(1));
|
| + UnaryOverwriteMode mode = static_cast<UnaryOverwriteMode>(args.smi_at(2));
|
| UnaryOpIC::TypeInfo previous_type =
|
| - static_cast<UnaryOpIC::TypeInfo>(Smi::cast(args[3])->value());
|
| + static_cast<UnaryOpIC::TypeInfo>(args.smi_at(3));
|
|
|
| UnaryOpIC::TypeInfo type = UnaryOpIC::GetTypeInfo(operand);
|
| type = UnaryOpIC::ComputeNewType(type, previous_type);
|
|
|
| - Handle<Code> code = GetUnaryOpStub(key, type);
|
| + UnaryOpStub stub(op, mode, type);
|
| + Handle<Code> code = stub.GetCode();
|
| if (!code.is_null()) {
|
| if (FLAG_trace_ic) {
|
| PrintF("[UnaryOpIC (%s->%s)#%s]\n",
|
| @@ -2380,23 +2331,16 @@
|
| return *result;
|
| }
|
|
|
| -// defined in code-stubs-<arch>.cc
|
| -// Only needed to remove dependency of ic.cc on code-stubs-<arch>.h.
|
| -Handle<Code> GetBinaryOpStub(int key,
|
| - BinaryOpIC::TypeInfo type_info,
|
| - BinaryOpIC::TypeInfo result_type);
|
| -
|
| -
|
| RUNTIME_FUNCTION(MaybeObject*, BinaryOp_Patch) {
|
| ASSERT(args.length() == 5);
|
|
|
| HandleScope scope(isolate);
|
| Handle<Object> left = args.at<Object>(0);
|
| Handle<Object> right = args.at<Object>(1);
|
| - int key = Smi::cast(args[2])->value();
|
| - Token::Value op = static_cast<Token::Value>(Smi::cast(args[3])->value());
|
| + 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>(Smi::cast(args[4])->value());
|
| + static_cast<BinaryOpIC::TypeInfo>(args.smi_at(4));
|
|
|
| BinaryOpIC::TypeInfo type = BinaryOpIC::GetTypeInfo(left, right);
|
| type = BinaryOpIC::JoinTypes(type, previous_type);
|
| @@ -2425,7 +2369,8 @@
|
| result_type = BinaryOpIC::HEAP_NUMBER;
|
| }
|
|
|
| - Handle<Code> code = GetBinaryOpStub(key, type, result_type);
|
| + BinaryOpStub stub(key, type, result_type);
|
| + Handle<Code> code = stub.GetCode();
|
| if (!code.is_null()) {
|
| if (FLAG_trace_ic) {
|
| PrintF("[BinaryOpIC (%s->(%s->%s))#%s]\n",
|
| @@ -2555,7 +2500,7 @@
|
| RUNTIME_FUNCTION(Code*, CompareIC_Miss) {
|
| NoHandleAllocation na;
|
| ASSERT(args.length() == 3);
|
| - CompareIC ic(isolate, static_cast<Token::Value>(Smi::cast(args[2])->value()));
|
| + CompareIC ic(isolate, static_cast<Token::Value>(args.smi_at(2)));
|
| ic.UpdateCaches(args.at<Object>(0), args.at<Object>(1));
|
| return ic.target();
|
| }
|
|
|