| Index: src/ic.cc
|
| diff --git a/src/ic.cc b/src/ic.cc
|
| index 14fc6a9bf45db768d57253d72d1d2d53c1a53fab..f1e3c5539d64fbd9f74cc0de671edc62a2cb3db6 100644
|
| --- a/src/ic.cc
|
| +++ b/src/ic.cc
|
| @@ -127,6 +127,11 @@ IC::IC(FrameDepth depth, Isolate* isolate)
|
| // running DeltaBlue and a ~25% speedup of gbemu with the '--nouse-ic' flag.
|
| const Address entry =
|
| Isolate::c_entry_fp(isolate->thread_local_top());
|
| + Address constant_pool = NULL;
|
| + if (FLAG_enable_ool_constant_pool) {
|
| + constant_pool = Memory::Address_at(
|
| + entry + ExitFrameConstants::kConstantPoolOffset);
|
| + }
|
| Address* pc_address =
|
| reinterpret_cast<Address*>(entry + ExitFrameConstants::kCallerPCOffset);
|
| Address fp = Memory::Address_at(entry + ExitFrameConstants::kCallerFPOffset);
|
| @@ -134,6 +139,10 @@ IC::IC(FrameDepth depth, Isolate* isolate)
|
| // StubFailureTrampoline, we need to look one frame further down the stack to
|
| // find the frame pointer and the return address stack slot.
|
| if (depth == EXTRA_CALL_FRAME) {
|
| + if (FLAG_enable_ool_constant_pool) {
|
| + constant_pool = Memory::Address_at(
|
| + fp + StandardFrameConstants::kConstantPoolOffset);
|
| + }
|
| const int kCallerPCOffset = StandardFrameConstants::kCallerPCOffset;
|
| pc_address = reinterpret_cast<Address*>(fp + kCallerPCOffset);
|
| fp = Memory::Address_at(fp + StandardFrameConstants::kCallerFPOffset);
|
| @@ -145,6 +154,11 @@ IC::IC(FrameDepth depth, Isolate* isolate)
|
| ASSERT(fp == frame->fp() && pc_address == frame->pc_address());
|
| #endif
|
| fp_ = fp;
|
| + if (FLAG_enable_ool_constant_pool) {
|
| + raw_constant_pool_ = handle(
|
| + ConstantPoolArray::cast(reinterpret_cast<Object*>(constant_pool)),
|
| + isolate);
|
| + }
|
| pc_address_ = StackFrame::ResolveReturnAddressLocation(pc_address);
|
| target_ = handle(raw_target(), isolate);
|
| state_ = target_->ic_state();
|
| @@ -153,8 +167,7 @@ IC::IC(FrameDepth depth, Isolate* isolate)
|
|
|
|
|
| #ifdef ENABLE_DEBUGGER_SUPPORT
|
| -Address IC::OriginalCodeAddress() const {
|
| - HandleScope scope(isolate());
|
| +SharedFunctionInfo* IC::GetSharedFunctionInfo() const {
|
| // Compute the JavaScript frame for the frame pointer of this IC
|
| // structure. We need this to be able to find the function
|
| // corresponding to the frame.
|
| @@ -164,21 +177,25 @@ Address IC::OriginalCodeAddress() const {
|
| // Find the function on the stack and both the active code for the
|
| // function and the original code.
|
| JSFunction* function = frame->function();
|
| - Handle<SharedFunctionInfo> shared(function->shared(), isolate());
|
| + return function->shared();
|
| +}
|
| +
|
| +
|
| +Code* IC::GetCode() const {
|
| + HandleScope scope(isolate());
|
| + Handle<SharedFunctionInfo> shared(GetSharedFunctionInfo(), isolate());
|
| Code* code = shared->code();
|
| + return code;
|
| +}
|
| +
|
| +
|
| +Code* IC::GetOriginalCode() const {
|
| + HandleScope scope(isolate());
|
| + Handle<SharedFunctionInfo> shared(GetSharedFunctionInfo(), isolate());
|
| ASSERT(Debug::HasDebugInfo(shared));
|
| Code* original_code = Debug::GetDebugInfo(shared)->original_code();
|
| ASSERT(original_code->IsCode());
|
| - // 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 = 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.
|
| - intptr_t delta =
|
| - original_code->instruction_start() - code->instruction_start();
|
| - return addr + delta;
|
| + return original_code;
|
| }
|
| #endif
|
|
|
| @@ -409,21 +426,26 @@ void IC::PostPatching(Address address, Code* target, Code* old_target) {
|
| }
|
|
|
|
|
| -void IC::Clear(Isolate* isolate, Address address) {
|
| - Code* target = GetTargetAtAddress(address);
|
| +void IC::Clear(Isolate* isolate, Address address,
|
| + ConstantPoolArray* constant_pool) {
|
| + Code* target = GetTargetAtAddress(address, constant_pool);
|
|
|
| // Don't clear debug break inline cache as it will remove the break point.
|
| if (target->is_debug_stub()) return;
|
|
|
| switch (target->kind()) {
|
| - case Code::LOAD_IC: return LoadIC::Clear(isolate, address, target);
|
| + case Code::LOAD_IC:
|
| + return LoadIC::Clear(isolate, address, target, constant_pool);
|
| case Code::KEYED_LOAD_IC:
|
| - return KeyedLoadIC::Clear(isolate, address, target);
|
| - case Code::STORE_IC: return StoreIC::Clear(isolate, address, target);
|
| + return KeyedLoadIC::Clear(isolate, address, target, constant_pool);
|
| + case Code::STORE_IC:
|
| + return StoreIC::Clear(isolate, address, target, constant_pool);
|
| case Code::KEYED_STORE_IC:
|
| - return KeyedStoreIC::Clear(isolate, address, target);
|
| - case Code::COMPARE_IC: return CompareIC::Clear(isolate, address, target);
|
| - case Code::COMPARE_NIL_IC: return CompareNilIC::Clear(address, target);
|
| + return KeyedStoreIC::Clear(isolate, address, target, constant_pool);
|
| + case Code::COMPARE_IC:
|
| + return CompareIC::Clear(isolate, address, target, constant_pool);
|
| + case Code::COMPARE_NIL_IC:
|
| + return CompareNilIC::Clear(address, target, constant_pool);
|
| case Code::BINARY_OP_IC:
|
| case Code::TO_BOOLEAN_IC:
|
| // Clearing these is tricky and does not
|
| @@ -434,40 +456,56 @@ void IC::Clear(Isolate* isolate, Address address) {
|
| }
|
|
|
|
|
| -void KeyedLoadIC::Clear(Isolate* isolate, Address address, Code* target) {
|
| +void KeyedLoadIC::Clear(Isolate* isolate,
|
| + Address address,
|
| + Code* target,
|
| + ConstantPoolArray* constant_pool) {
|
| if (IsCleared(target)) return;
|
| // Make sure to also clear the map used in inline fast cases. If we
|
| // do not clear these maps, cached code can keep objects alive
|
| // through the embedded maps.
|
| - SetTargetAtAddress(address, *pre_monomorphic_stub(isolate));
|
| + SetTargetAtAddress(address, *pre_monomorphic_stub(isolate), constant_pool);
|
| }
|
|
|
|
|
| -void LoadIC::Clear(Isolate* isolate, Address address, Code* target) {
|
| +void LoadIC::Clear(Isolate* isolate,
|
| + Address address,
|
| + Code* target,
|
| + ConstantPoolArray* constant_pool) {
|
| if (IsCleared(target)) return;
|
| Code* code = target->GetIsolate()->stub_cache()->FindPreMonomorphicIC(
|
| Code::LOAD_IC, target->extra_ic_state());
|
| - SetTargetAtAddress(address, code);
|
| + SetTargetAtAddress(address, code, constant_pool);
|
| }
|
|
|
|
|
| -void StoreIC::Clear(Isolate* isolate, Address address, Code* target) {
|
| +void StoreIC::Clear(Isolate* isolate,
|
| + Address address,
|
| + Code* target,
|
| + ConstantPoolArray* constant_pool) {
|
| if (IsCleared(target)) return;
|
| Code* code = target->GetIsolate()->stub_cache()->FindPreMonomorphicIC(
|
| Code::STORE_IC, target->extra_ic_state());
|
| - SetTargetAtAddress(address, code);
|
| + SetTargetAtAddress(address, code, constant_pool);
|
| }
|
|
|
|
|
| -void KeyedStoreIC::Clear(Isolate* isolate, Address address, Code* target) {
|
| +void KeyedStoreIC::Clear(Isolate* isolate,
|
| + Address address,
|
| + Code* target,
|
| + ConstantPoolArray* constant_pool) {
|
| if (IsCleared(target)) return;
|
| SetTargetAtAddress(address,
|
| *pre_monomorphic_stub(
|
| - isolate, StoreIC::GetStrictMode(target->extra_ic_state())));
|
| + isolate, StoreIC::GetStrictMode(target->extra_ic_state())),
|
| + constant_pool);
|
| }
|
|
|
|
|
| -void CompareIC::Clear(Isolate* isolate, Address address, Code* target) {
|
| +void CompareIC::Clear(Isolate* isolate,
|
| + Address address,
|
| + Code* target,
|
| + ConstantPoolArray* constant_pool) {
|
| ASSERT(target->major_key() == CodeStub::CompareIC);
|
| CompareIC::State handler_state;
|
| Token::Value op;
|
| @@ -475,7 +513,7 @@ void CompareIC::Clear(Isolate* isolate, Address address, Code* target) {
|
| &handler_state, &op);
|
| // Only clear CompareICs that can retain objects.
|
| if (handler_state != KNOWN_OBJECT) return;
|
| - SetTargetAtAddress(address, GetRawUninitialized(isolate, op));
|
| + SetTargetAtAddress(address, GetRawUninitialized(isolate, op), constant_pool);
|
| PatchInlinedSmiCode(address, DISABLE_INLINED_SMI_CHECK);
|
| }
|
|
|
| @@ -498,31 +536,6 @@ MaybeObject* LoadIC::Load(Handle<Object> object,
|
| }
|
|
|
| if (FLAG_use_ic) {
|
| - // 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->IsStringWrapper() &&
|
| - name->Equals(isolate()->heap()->length_string())) {
|
| - Handle<Code> stub;
|
| - if (state() == UNINITIALIZED) {
|
| - stub = pre_monomorphic_stub();
|
| - } else if (state() == PREMONOMORPHIC || state() == MONOMORPHIC) {
|
| - StringLengthStub string_length_stub(kind());
|
| - stub = string_length_stub.GetCode(isolate());
|
| - } else if (state() != MEGAMORPHIC) {
|
| - ASSERT(state() != GENERIC);
|
| - stub = megamorphic_stub();
|
| - }
|
| - if (!stub.is_null()) {
|
| - set_target(*stub);
|
| - if (FLAG_trace_ic) PrintF("[LoadIC : +#length /stringwrapper]\n");
|
| - }
|
| - // Get the string if we have a string wrapper object.
|
| - String* string = String::cast(JSValue::cast(*object)->value());
|
| - return Smi::FromInt(string->length());
|
| - }
|
| -
|
| // Use specialized code for getting prototype of functions.
|
| if (object->IsJSFunction() &&
|
| name->Equals(isolate()->heap()->prototype_string()) &&
|
| @@ -872,6 +885,17 @@ Handle<Code> LoadIC::CompileHandler(LookupResult* lookup,
|
| return SimpleFieldLoad(length_index);
|
| }
|
|
|
| + if (object->IsStringWrapper() &&
|
| + name->Equals(isolate()->heap()->length_string())) {
|
| + if (kind() == Code::LOAD_IC) {
|
| + StringLengthStub string_length_stub;
|
| + return string_length_stub.GetCode(isolate());
|
| + } else {
|
| + KeyedStringLengthStub string_length_stub;
|
| + return string_length_stub.GetCode(isolate());
|
| + }
|
| + }
|
| +
|
| Handle<HeapType> type = CurrentTypeOf(object, isolate());
|
| Handle<JSObject> holder(lookup->holder());
|
| LoadStubCompiler compiler(isolate(), kNoExtraICState, cache_holder, kind());
|
| @@ -943,8 +967,8 @@ Handle<Code> LoadIC::CompileHandler(LookupResult* lookup,
|
| Handle<JSFunction> function = Handle<JSFunction>::cast(getter);
|
| if (!object->IsJSObject() &&
|
| !function->IsBuiltin() &&
|
| - function->shared()->is_classic_mode()) {
|
| - // Calling non-strict non-builtins with a value as the receiver
|
| + function->shared()->strict_mode() == SLOPPY) {
|
| + // Calling sloppy non-builtins with a value as the receiver
|
| // requires boxing.
|
| break;
|
| }
|
| @@ -1072,18 +1096,18 @@ MaybeObject* KeyedLoadIC::Load(Handle<Object> object, Handle<Object> key) {
|
| maybe_object = LoadIC::Load(object, Handle<String>::cast(key));
|
| if (maybe_object->IsFailure()) return maybe_object;
|
| } else if (FLAG_use_ic && !object->IsAccessCheckNeeded()) {
|
| - ASSERT(!object->IsJSGlobalProxy());
|
| + ASSERT(!object->IsAccessCheckNeeded());
|
| if (object->IsString() && key->IsNumber()) {
|
| if (state() == UNINITIALIZED) stub = string_stub();
|
| } else if (object->IsJSObject()) {
|
| Handle<JSObject> receiver = Handle<JSObject>::cast(object);
|
| if (receiver->elements()->map() ==
|
| - isolate()->heap()->non_strict_arguments_elements_map()) {
|
| - stub = non_strict_arguments_stub();
|
| + isolate()->heap()->sloppy_arguments_elements_map()) {
|
| + stub = sloppy_arguments_stub();
|
| } else if (receiver->HasIndexedInterceptor()) {
|
| stub = indexed_interceptor_stub();
|
| } else if (!key->ToSmi()->IsFailure() &&
|
| - (!target().is_identical_to(non_strict_arguments_stub()))) {
|
| + (!target().is_identical_to(sloppy_arguments_stub()))) {
|
| stub = LoadElementStub(receiver);
|
| }
|
| }
|
| @@ -1111,22 +1135,20 @@ static bool LookupForWrite(Handle<JSObject> receiver,
|
| Handle<JSObject> holder = receiver;
|
| receiver->Lookup(*name, lookup);
|
| if (lookup->IsFound()) {
|
| - if (lookup->IsReadOnly() || !lookup->IsCacheable()) return false;
|
| -
|
| - if (lookup->holder() == *receiver) {
|
| - if (lookup->IsInterceptor() && !HasInterceptorSetter(*receiver)) {
|
| - receiver->LocalLookupRealNamedProperty(*name, lookup);
|
| - return lookup->IsFound() &&
|
| - !lookup->IsReadOnly() &&
|
| - lookup->CanHoldValue(value) &&
|
| - lookup->IsCacheable();
|
| - }
|
| - return lookup->CanHoldValue(value);
|
| + if (lookup->IsInterceptor() && !HasInterceptorSetter(lookup->holder())) {
|
| + receiver->LocalLookupRealNamedProperty(*name, lookup);
|
| + if (!lookup->IsFound()) return false;
|
| }
|
|
|
| + if (lookup->IsReadOnly() || !lookup->IsCacheable()) return false;
|
| + if (lookup->holder() == *receiver) return lookup->CanHoldValue(value);
|
| if (lookup->IsPropertyCallbacks()) return true;
|
| - // JSGlobalProxy always goes via the runtime, so it's safe to cache.
|
| - if (receiver->IsJSGlobalProxy()) return true;
|
| + // JSGlobalProxy either stores on the global object in the prototype, or
|
| + // goes into the runtime if access checks are needed, so this is always
|
| + // safe.
|
| + if (receiver->IsJSGlobalProxy()) {
|
| + return lookup->holder() == receiver->GetPrototype();
|
| + }
|
| // Currently normal holders in the prototype chain are not supported. They
|
| // would require a runtime positive lookup and verification that the details
|
| // have not changed.
|
| @@ -1184,7 +1206,7 @@ MaybeObject* StoreIC::Store(Handle<Object> object,
|
| }
|
|
|
| // The length property of string values is read-only. Throw in strict mode.
|
| - if (strict_mode() == kStrictMode && object->IsString() &&
|
| + if (strict_mode() == STRICT && object->IsString() &&
|
| name->Equals(isolate()->heap()->length_string())) {
|
| return TypeError("strict_read_only_property", object, name);
|
| }
|
| @@ -1205,7 +1227,7 @@ MaybeObject* StoreIC::Store(Handle<Object> object,
|
| }
|
|
|
| // Observed objects are always modified through the runtime.
|
| - if (FLAG_harmony_observation && receiver->map()->is_observed()) {
|
| + if (receiver->map()->is_observed()) {
|
| Handle<Object> result = JSReceiver::SetProperty(
|
| receiver, name, value, NONE, strict_mode(), store_mode);
|
| RETURN_IF_EMPTY_HANDLE(isolate(), result);
|
| @@ -1235,7 +1257,7 @@ MaybeObject* StoreIC::Store(Handle<Object> object,
|
| LookupResult lookup(isolate());
|
| bool can_store = LookupForWrite(receiver, name, value, &lookup, this);
|
| if (!can_store &&
|
| - strict_mode() == kStrictMode &&
|
| + strict_mode() == STRICT &&
|
| !(lookup.IsProperty() && lookup.IsReadOnly()) &&
|
| object->IsGlobalObject()) {
|
| // Strict mode doesn't allow setting non-existent global property.
|
| @@ -1265,7 +1287,7 @@ MaybeObject* StoreIC::Store(Handle<Object> object,
|
|
|
|
|
| Handle<Code> StoreIC::initialize_stub(Isolate* isolate,
|
| - StrictModeFlag strict_mode) {
|
| + StrictMode strict_mode) {
|
| ExtraICState extra_state = ComputeExtraICState(strict_mode);
|
| Handle<Code> ic = isolate->stub_cache()->ComputeStore(
|
| UNINITIALIZED, extra_state);
|
| @@ -1284,7 +1306,7 @@ Handle<Code> StoreIC::generic_stub() const {
|
|
|
|
|
| Handle<Code> StoreIC::pre_monomorphic_stub(Isolate* isolate,
|
| - StrictModeFlag strict_mode) {
|
| + StrictMode strict_mode) {
|
| ExtraICState state = ComputeExtraICState(strict_mode);
|
| return isolate->stub_cache()->ComputeStore(PREMONOMORPHIC, state);
|
| }
|
| @@ -1311,14 +1333,14 @@ Handle<Code> StoreIC::CompileHandler(LookupResult* lookup,
|
| Handle<String> name,
|
| Handle<Object> value,
|
| InlineCacheHolderFlag cache_holder) {
|
| - if (object->IsJSGlobalProxy()) return slow_stub();
|
| + if (object->IsAccessCheckNeeded()) return slow_stub();
|
| ASSERT(cache_holder == OWN_MAP);
|
| // This is currently guaranteed by checks in StoreIC::Store.
|
| Handle<JSObject> receiver = Handle<JSObject>::cast(object);
|
|
|
| Handle<JSObject> holder(lookup->holder());
|
| // Handlers do not use strict mode.
|
| - StoreStubCompiler compiler(isolate(), kNonStrictMode, kind());
|
| + StoreStubCompiler compiler(isolate(), SLOPPY, kind());
|
| switch (lookup->type()) {
|
| case FIELD:
|
| return compiler.CompileStoreField(receiver, lookup, name);
|
| @@ -1335,17 +1357,19 @@ Handle<Code> StoreIC::CompileHandler(LookupResult* lookup,
|
| }
|
| case NORMAL:
|
| if (kind() == Code::KEYED_STORE_IC) break;
|
| - if (receiver->IsGlobalObject()) {
|
| + if (receiver->IsJSGlobalProxy() || receiver->IsGlobalObject()) {
|
| // The stub generated for the global object picks the value directly
|
| // from the property cell. So the property must be directly on the
|
| // global object.
|
| - Handle<GlobalObject> global = Handle<GlobalObject>::cast(receiver);
|
| + Handle<GlobalObject> global = receiver->IsJSGlobalProxy()
|
| + ? handle(GlobalObject::cast(receiver->GetPrototype()))
|
| + : Handle<GlobalObject>::cast(receiver);
|
| Handle<PropertyCell> cell(global->GetPropertyCell(lookup), isolate());
|
| Handle<HeapType> union_type = PropertyCell::UpdatedType(cell, value);
|
| - StoreGlobalStub stub(union_type->IsConstant());
|
| -
|
| + StoreGlobalStub stub(
|
| + union_type->IsConstant(), receiver->IsJSGlobalProxy());
|
| Handle<Code> code = stub.GetCodeCopyFromTemplate(
|
| - isolate(), receiver->map(), *cell);
|
| + isolate(), *global, *cell);
|
| // TODO(verwaest): Move caching of these NORMAL stubs outside as well.
|
| HeapObject::UpdateMapCodeCache(receiver, name, code);
|
| return code;
|
| @@ -1353,7 +1377,6 @@ Handle<Code> StoreIC::CompileHandler(LookupResult* lookup,
|
| ASSERT(holder.is_identical_to(receiver));
|
| return isolate()->builtins()->StoreIC_Normal();
|
| case CALLBACKS: {
|
| - if (kind() == Code::KEYED_STORE_IC) break;
|
| Handle<Object> callback(lookup->GetCallbackObject(), isolate());
|
| if (callback->IsExecutableAccessorInfo()) {
|
| Handle<ExecutableAccessorInfo> info =
|
| @@ -1386,7 +1409,7 @@ Handle<Code> StoreIC::CompileHandler(LookupResult* lookup,
|
| }
|
| case INTERCEPTOR:
|
| if (kind() == Code::KEYED_STORE_IC) break;
|
| - ASSERT(HasInterceptorSetter(*receiver));
|
| + ASSERT(HasInterceptorSetter(*holder));
|
| return compiler.CompileStoreInterceptor(receiver, name);
|
| case CONSTANT:
|
| break;
|
| @@ -1436,22 +1459,22 @@ Handle<Code> KeyedStoreIC::StoreElementStub(Handle<JSObject> receiver,
|
| KeyedStoreIC::GetKeyedAccessStoreMode(target()->extra_ic_state());
|
| Handle<Map> previous_receiver_map = target_receiver_maps.at(0);
|
| if (state() == MONOMORPHIC) {
|
| - // If the "old" and "new" maps are in the same elements map family, stay
|
| - // MONOMORPHIC and use the map for the most generic ElementsKind.
|
| Handle<Map> transitioned_receiver_map = receiver_map;
|
| if (IsTransitionStoreMode(store_mode)) {
|
| - transitioned_receiver_map =
|
| - ComputeTransitionedMap(receiver, store_mode);
|
| + transitioned_receiver_map = ComputeTransitionedMap(receiver, store_mode);
|
| }
|
| - if (IsTransitionOfMonomorphicTarget(
|
| + if (receiver_map.is_identical_to(previous_receiver_map) ||
|
| + IsTransitionOfMonomorphicTarget(
|
| MapToType<HeapType>(transitioned_receiver_map, isolate()))) {
|
| - // Element family is the same, use the "worst" case map.
|
| + // If the "old" and "new" maps are in the same elements map family, or
|
| + // if they at least come from the same origin for a transitioning store,
|
| + // stay MONOMORPHIC and use the map for the most generic ElementsKind.
|
| store_mode = GetNonTransitioningStoreMode(store_mode);
|
| return isolate()->stub_cache()->ComputeKeyedStoreElement(
|
| transitioned_receiver_map, strict_mode(), store_mode);
|
| } else if (*previous_receiver_map == receiver->map() &&
|
| old_store_mode == STANDARD_STORE &&
|
| - (IsGrowStoreMode(store_mode) ||
|
| + (store_mode == STORE_AND_GROW_NO_TRANSITION ||
|
| store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS ||
|
| store_mode == STORE_NO_TRANSITION_HANDLE_COW)) {
|
| // A "normal" IC that handles stores can switch to a version that can
|
| @@ -1576,7 +1599,10 @@ KeyedAccessStoreMode KeyedStoreIC::GetStoreMode(Handle<JSObject> receiver,
|
| key->ToSmi()->To(&smi_key);
|
| int index = smi_key->value();
|
| bool oob_access = IsOutOfBoundsAccess(receiver, index);
|
| - bool allow_growth = receiver->IsJSArray() && oob_access;
|
| + // Don't consider this a growing store if the store would send the receiver to
|
| + // dictionary mode.
|
| + bool allow_growth = receiver->IsJSArray() && oob_access &&
|
| + !receiver->WouldConvertToSlowElements(key);
|
| if (allow_growth) {
|
| // Handle growing array in stub if necessary.
|
| if (receiver->HasFastSmiElements()) {
|
| @@ -1671,7 +1697,7 @@ MaybeObject* KeyedStoreIC::Store(Handle<Object> object,
|
| if (maybe_object->IsFailure()) return maybe_object;
|
| } else {
|
| bool use_ic = FLAG_use_ic && !object->IsAccessCheckNeeded() &&
|
| - !(FLAG_harmony_observation && object->IsJSObject() &&
|
| + !(object->IsJSObject() &&
|
| JSObject::cast(*object)->map()->is_observed());
|
| if (use_ic && !object->IsSmi()) {
|
| // Don't use ICs for maps of the objects in Array's prototype chain. We
|
| @@ -1682,16 +1708,18 @@ MaybeObject* KeyedStoreIC::Store(Handle<Object> object,
|
| }
|
|
|
| if (use_ic) {
|
| - ASSERT(!object->IsJSGlobalProxy());
|
| + ASSERT(!object->IsAccessCheckNeeded());
|
|
|
| if (object->IsJSObject()) {
|
| Handle<JSObject> receiver = Handle<JSObject>::cast(object);
|
| bool key_is_smi_like = key->IsSmi() || !key->ToSmi()->IsFailure();
|
| if (receiver->elements()->map() ==
|
| - isolate()->heap()->non_strict_arguments_elements_map()) {
|
| - stub = non_strict_arguments_stub();
|
| + isolate()->heap()->sloppy_arguments_elements_map()) {
|
| + if (strict_mode() == SLOPPY) {
|
| + stub = sloppy_arguments_stub();
|
| + }
|
| } else if (key_is_smi_like &&
|
| - !(target().is_identical_to(non_strict_arguments_stub()))) {
|
| + !(target().is_identical_to(sloppy_arguments_stub()))) {
|
| // We should go generic if receiver isn't a dictionary, but our
|
| // prototype chain does have dictionary elements. This ensures that
|
| // other non-dictionary receivers in the polymorphic case benefit
|
| @@ -1844,14 +1872,12 @@ RUNTIME_FUNCTION(MaybeObject*, SharedStoreIC_ExtendStorage) {
|
|
|
| Object* to_store = value;
|
|
|
| - if (FLAG_track_double_fields) {
|
| - DescriptorArray* descriptors = transition->instance_descriptors();
|
| - PropertyDetails details = descriptors->GetDetails(transition->LastAdded());
|
| - if (details.representation().IsDouble()) {
|
| - MaybeObject* maybe_storage =
|
| - isolate->heap()->AllocateHeapNumber(value->Number());
|
| - if (!maybe_storage->To(&to_store)) return maybe_storage;
|
| - }
|
| + DescriptorArray* descriptors = transition->instance_descriptors();
|
| + PropertyDetails details = descriptors->GetDetails(transition->LastAdded());
|
| + if (details.representation().IsDouble()) {
|
| + MaybeObject* maybe_storage =
|
| + isolate->heap()->AllocateHeapNumber(value->Number());
|
| + if (!maybe_storage->To(&to_store)) return maybe_storage;
|
| }
|
|
|
| new_storage->set(old_storage->length(), to_store);
|
| @@ -1895,7 +1921,7 @@ RUNTIME_FUNCTION(MaybeObject*, StoreIC_Slow) {
|
| Handle<Object> object = args.at<Object>(0);
|
| Handle<Object> key = args.at<Object>(1);
|
| Handle<Object> value = args.at<Object>(2);
|
| - StrictModeFlag strict_mode = ic.strict_mode();
|
| + StrictMode strict_mode = ic.strict_mode();
|
| Handle<Object> result = Runtime::SetObjectProperty(isolate, object, key,
|
| value,
|
| NONE,
|
| @@ -1912,7 +1938,7 @@ RUNTIME_FUNCTION(MaybeObject*, KeyedStoreIC_Slow) {
|
| Handle<Object> object = args.at<Object>(0);
|
| Handle<Object> key = args.at<Object>(1);
|
| Handle<Object> value = args.at<Object>(2);
|
| - StrictModeFlag strict_mode = ic.strict_mode();
|
| + StrictMode strict_mode = ic.strict_mode();
|
| Handle<Object> result = Runtime::SetObjectProperty(isolate, object, key,
|
| value,
|
| NONE,
|
| @@ -1930,7 +1956,7 @@ RUNTIME_FUNCTION(MaybeObject*, ElementsTransitionAndStoreIC_Miss) {
|
| Handle<Map> map = args.at<Map>(1);
|
| Handle<Object> key = args.at<Object>(2);
|
| Handle<Object> object = args.at<Object>(3);
|
| - StrictModeFlag strict_mode = ic.strict_mode();
|
| + StrictMode strict_mode = ic.strict_mode();
|
| if (object->IsJSObject()) {
|
| JSObject::TransitionElementsKind(Handle<JSObject>::cast(object),
|
| map->elements_kind());
|
| @@ -2681,7 +2707,9 @@ RUNTIME_FUNCTION(Code*, CompareIC_Miss) {
|
| }
|
|
|
|
|
| -void CompareNilIC::Clear(Address address, Code* target) {
|
| +void CompareNilIC::Clear(Address address,
|
| + Code* target,
|
| + ConstantPoolArray* constant_pool) {
|
| if (IsCleared(target)) return;
|
| ExtraICState state = target->extra_ic_state();
|
|
|
| @@ -2691,7 +2719,7 @@ void CompareNilIC::Clear(Address address, Code* target) {
|
| Code* code = NULL;
|
| CHECK(stub.FindCodeInCache(&code, target->GetIsolate()));
|
|
|
| - SetTargetAtAddress(address, code);
|
| + SetTargetAtAddress(address, code, constant_pool);
|
| }
|
|
|
|
|
|
|