StubCompiler::GenerateLoadFunctionPrototype(masm, receiver, r3, r4, &miss);
__ bind(&miss);
- StubCompiler::TailCallBuiltin(masm, StubCompiler::MissBuiltin(kind()));
+ StubCompiler::TailCallBuiltin(
+ masm, BaseLoadStoreStubCompiler::MissBuiltin(kind()));
}
support_wrapper_);
__ bind(&miss);
- StubCompiler::TailCallBuiltin(masm, StubCompiler::MissBuiltin(kind()));
+ StubCompiler::TailCallBuiltin(
+ masm, BaseLoadStoreStubCompiler::MissBuiltin(kind()));
}
__ bind(&miss);
- StubCompiler::TailCallBuiltin(masm, StubCompiler::MissBuiltin(kind()));
+ StubCompiler::TailCallBuiltin(
+ masm, BaseLoadStoreStubCompiler::MissBuiltin(kind()));
}
// -----------------------------------
// Get the receiver from the stack and probe the stub cache.
- Code::Flags flags =
- Code::ComputeFlags(Code::STORE_IC, MONOMORPHIC, strict_mode);
+ Code::Flags flags = Code::ComputeFlags(
+ Code::STUB, MONOMORPHIC, strict_mode,
+ Code::NORMAL, Code::STORE_IC);
Isolate::Current()->stub_cache()->GenerateProbe(
masm, flags, r1, r2, r3, r4, r5, r6);
}
+void BaseStoreStubCompiler::GenerateNegativeHolderLookup(
+ MacroAssembler* masm,
+ Handle<JSObject> holder,
+ Register holder_reg,
+ Handle<Name> name,
+ Label* miss) {
+ if (holder->IsJSGlobalObject()) {
+ GenerateCheckPropertyCell(
+ masm, Handle<GlobalObject>::cast(holder), name, scratch1(), miss);
+ } else if (!holder->HasFastProperties() && !holder->IsJSGlobalProxy()) {
+ GenerateDictionaryNegativeLookup(
+ masm, miss, holder_reg, name, scratch1(), scratch2());
+ }
+}
+
+
// Generate StoreTransition code, value is passed in r0 register.
// When leaving generated code after success, the receiver_reg and name_reg
// may be clobbered. Upon branch to miss_label, the receiver and name
// registers have their original values.
-void StubCompiler::GenerateStoreTransition(MacroAssembler* masm,
- Handle<JSObject> object,
- LookupResult* lookup,
- Handle<Map> transition,
- Handle<Name> name,
- Register receiver_reg,
- Register name_reg,
- Register value_reg,
- Register scratch1,
- Register scratch2,
- Register scratch3,
- Label* miss_label,
- Label* miss_restore_name,
- Label* slow) {
+void BaseStoreStubCompiler::GenerateStoreTransition(MacroAssembler* masm,
+ Handle<JSObject> object,
+ LookupResult* lookup,
+ Handle<Map> transition,
+ Handle<Name> name,
+ Register receiver_reg,
+ Register storage_reg,
+ Register value_reg,
+ Register scratch1,
+ Register scratch2,
+ Register scratch3,
+ Label* miss_label,
+ Label* slow) {
// r0 : value
Label exit;
- // Check that the map of the object hasn't changed.
- __ CheckMap(receiver_reg, scratch1, Handle<Map>(object->map()), miss_label,
- DO_SMI_CHECK);
-
- // Perform global security token check if needed.
- if (object->IsJSGlobalProxy()) {
- __ CheckAccessGlobalProxy(receiver_reg, scratch1, miss_label);
- }
-
int descriptor = transition->LastAdded();
DescriptorArray* descriptors = transition->instance_descriptors();
PropertyDetails details = descriptors->GetDetails(descriptor);
Representation representation = details.representation();
ASSERT(!representation.IsNone());
- // Ensure no transitions to deprecated maps are followed.
- __ CheckMapDeprecated(transition, scratch1, miss_label);
-
- // Check that we are allowed to write this.
- if (object->GetPrototype()->IsJSObject()) {
- JSObject* holder;
- // holder == object indicates that no property was found.
- if (lookup->holder() != *object) {
- holder = lookup->holder();
- } else {
- // Find the top object.
- holder = *object;
- do {
- holder = JSObject::cast(holder->GetPrototype());
- } while (holder->GetPrototype()->IsJSObject());
- }
- Register holder_reg = CheckPrototypes(
- object, receiver_reg, Handle<JSObject>(holder), name_reg,
- scratch1, scratch2, name, miss_restore_name, SKIP_RECEIVER);
- // If no property was found, and the holder (the last object in the
- // prototype chain) is in slow mode, we need to do a negative lookup on the
- // holder.
- if (lookup->holder() == *object) {
- if (holder->IsJSGlobalObject()) {
- GenerateCheckPropertyCell(
- masm,
- Handle<GlobalObject>(GlobalObject::cast(holder)),
- name,
- scratch1,
- miss_restore_name);
- } else if (!holder->HasFastProperties() && !holder->IsJSGlobalProxy()) {
- GenerateDictionaryNegativeLookup(
- masm, miss_restore_name, holder_reg, name, scratch1, scratch2);
- }
- }
- }
-
- Register storage_reg = name_reg;
-
if (details.type() == CONSTANT_FUNCTION) {
Handle<HeapObject> constant(
HeapObject::cast(descriptors->GetValue(descriptor)));
__ LoadHeapObject(scratch1, constant);
__ cmp(value_reg, scratch1);
- __ b(ne, miss_restore_name);
+ __ b(ne, miss_label);
} else if (FLAG_track_fields && representation.IsSmi()) {
- __ JumpIfNotSmi(value_reg, miss_restore_name);
+ __ JumpIfNotSmi(value_reg, miss_label);
} else if (FLAG_track_heap_object_fields && representation.IsHeapObject()) {
- __ JumpIfSmi(value_reg, miss_restore_name);
+ __ JumpIfSmi(value_reg, miss_label);
} else if (FLAG_track_double_fields && representation.IsDouble()) {
Label do_store, heap_number;
__ LoadRoot(scratch3, Heap::kHeapNumberMapRootIndex);
__ bind(&heap_number);
__ CheckMap(value_reg, scratch1, Heap::kHeapNumberMapRootIndex,
- miss_restore_name, DONT_DO_SMI_CHECK);
+ miss_label, DONT_DO_SMI_CHECK);
__ vldr(d0, FieldMemOperand(value_reg, HeapNumber::kValueOffset));
__ bind(&do_store);
__ mov(scratch1, Operand(transition));
__ str(scratch1, FieldMemOperand(receiver_reg, HeapObject::kMapOffset));
- // Update the write barrier for the map field and pass the now unused
- // name_reg as scratch register.
+ // Update the write barrier for the map field.
__ RecordWriteField(receiver_reg,
HeapObject::kMapOffset,
scratch1,
__ JumpIfSmi(value_reg, &exit);
// Update the write barrier for the array address.
- // Pass the now unused name_reg as a scratch register.
if (!FLAG_track_double_fields || !representation.IsDouble()) {
- __ mov(name_reg, value_reg);
- } else {
- ASSERT(storage_reg.is(name_reg));
+ __ mov(storage_reg, value_reg);
}
__ RecordWriteField(receiver_reg,
offset,
- name_reg,
+ storage_reg,
scratch1,
kLRHasNotBeenSaved,
kDontSaveFPRegs,
__ JumpIfSmi(value_reg, &exit);
// Update the write barrier for the array address.
- // Ok to clobber receiver_reg and name_reg, since we return.
if (!FLAG_track_double_fields || !representation.IsDouble()) {
- __ mov(name_reg, value_reg);
- } else {
- ASSERT(storage_reg.is(name_reg));
+ __ mov(storage_reg, value_reg);
}
__ RecordWriteField(scratch1,
offset,
- name_reg,
+ storage_reg,
receiver_reg,
kLRHasNotBeenSaved,
kDontSaveFPRegs,
// When leaving generated code after success, the receiver_reg and name_reg
// may be clobbered. Upon branch to miss_label, the receiver and name
// registers have their original values.
-void StubCompiler::GenerateStoreField(MacroAssembler* masm,
- Handle<JSObject> object,
- LookupResult* lookup,
- Register receiver_reg,
- Register name_reg,
- Register value_reg,
- Register scratch1,
- Register scratch2,
- Label* miss_label) {
+void BaseStoreStubCompiler::GenerateStoreField(MacroAssembler* masm,
+ Handle<JSObject> object,
+ LookupResult* lookup,
+ Register receiver_reg,
+ Register name_reg,
+ Register value_reg,
+ Register scratch1,
+ Register scratch2,
+ Label* miss_label) {
// r0 : value
Label exit;
- // Check that the map of the object hasn't changed.
- __ CheckMap(receiver_reg, scratch1, Handle<Map>(object->map()), miss_label,
- DO_SMI_CHECK);
-
- // Perform global security token check if needed.
- if (object->IsJSGlobalProxy()) {
- __ CheckAccessGlobalProxy(receiver_reg, scratch1, miss_label);
- }
-
// Stub never generated for non-global objects that require access
// checks.
ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
}
-void BaseLoadStubCompiler::HandlerFrontendFooter(Label* success,
+void BaseLoadStubCompiler::HandlerFrontendFooter(Handle<Name> name,
+ Label* success,
Label* miss) {
if (!miss->is_unused()) {
__ b(success);
}
+void BaseStoreStubCompiler::HandlerFrontendFooter(Handle<Name> name,
+ Label* success,
+ Label* miss) {
+ if (!miss->is_unused()) {
+ __ b(success);
+ GenerateRestoreName(masm(), miss, name);
+ TailCallBuiltin(masm(), MissBuiltin(kind()));
+ }
+}
+
+
Register BaseLoadStubCompiler::CallbackHandlerFrontend(
Handle<JSObject> object,
Register object_reg,
__ b(ne, &miss);
}
- HandlerFrontendFooter(success, &miss);
+ HandlerFrontendFooter(name, success, &miss);
return reg;
}
GenerateCheckPropertyCell(masm(), global, name, scratch2(), &miss);
}
- HandlerFrontendFooter(success, &miss);
+ HandlerFrontendFooter(name, success, &miss);
}
Handle<Code> StoreStubCompiler::CompileStoreCallback(
- Handle<Name> name,
Handle<JSObject> object,
Handle<JSObject> holder,
+ Handle<Name> name,
Handle<ExecutableAccessorInfo> callback) {
- Label miss;
- // Check that the maps haven't changed.
- __ JumpIfSmi(receiver(), &miss);
- CheckPrototypes(object, receiver(), holder,
- scratch1(), scratch2(), scratch3(), name, &miss);
+ Label success;
+ HandlerFrontend(object, receiver(), holder, name, &success);
+ __ bind(&success);
// Stub never generated for non-global objects that require access checks.
ASSERT(holder->IsJSGlobalProxy() || !holder->IsAccessCheckNeeded());
__ push(receiver()); // receiver
__ mov(ip, Operand(callback)); // callback info
- __ Push(ip, this->name(), value());
+ __ push(ip);
+ __ mov(ip, Operand(name));
+ __ Push(ip, value());
// Do tail-call to the runtime system.
ExternalReference store_callback_property =
ExternalReference(IC_Utility(IC::kStoreCallbackProperty), isolate());
__ TailCallExternalReference(store_callback_property, 4, 1);
- // Handle store cache miss.
- __ bind(&miss);
- TailCallBuiltin(masm(), MissBuiltin(kind()));
-
// Return the generated code.
- return GetICCode(kind(), Code::CALLBACKS, name);
+ return GetCode(kind(), Code::CALLBACKS, name);
}
__ b(eq, &miss);
}
- HandlerFrontendFooter(&success, &miss);
+ HandlerFrontendFooter(name, &success, &miss);
__ bind(&success);
Counters* counters = isolate()->counters();
}
-Handle<Code> BaseLoadStubCompiler::CompilePolymorphicIC(
+Handle<Code> BaseLoadStoreStubCompiler::CompilePolymorphicIC(
MapHandleList* receiver_maps,
CodeHandleList* handlers,
Handle<Name> name,
// Record receiver type for monomorphic keyed stores.
receiver_types_.Add(oracle->StoreMonomorphicReceiverType(id), zone);
store_mode_ = oracle->GetStoreMode(id);
- } else if (oracle->StoreIsPolymorphic(id)) {
+ } else if (oracle->StoreIsKeyedPolymorphic(id)) {
receiver_types_.Reserve(kMaxKeyedPolymorphism, zone);
oracle->CollectKeyedReceiverTypes(id, &receiver_types_);
store_mode_ = oracle->GetStoreMode(id);
// Record receiver type for monomorphic keyed stores.
receiver_types_.Add(
oracle->StoreMonomorphicReceiverType(id), zone);
- } else if (oracle->StoreIsPolymorphic(id)) {
+ } else if (oracle->StoreIsKeyedPolymorphic(id)) {
receiver_types_.Reserve(kMaxKeyedPolymorphism, zone);
oracle->CollectKeyedReceiverTypes(id, &receiver_types_);
+ } else {
+ oracle->CollectPolymorphicStoreReceiverTypes(id, &receiver_types_);
}
store_mode_ = oracle->GetStoreMode(id);
type_ = oracle->IncrementType(this);
StubCompiler::GenerateLoadFunctionPrototype(masm, edx, eax, ebx, &miss);
__ bind(&miss);
- StubCompiler::TailCallBuiltin(masm, StubCompiler::MissBuiltin(kind()));
+ StubCompiler::TailCallBuiltin(
+ masm, BaseLoadStoreStubCompiler::MissBuiltin(kind()));
}
StubCompiler::GenerateLoadStringLength(masm, edx, eax, ebx, &miss,
support_wrapper_);
__ bind(&miss);
- StubCompiler::TailCallBuiltin(masm, StubCompiler::MissBuiltin(kind()));
+ StubCompiler::TailCallBuiltin(
+ masm, BaseLoadStoreStubCompiler::MissBuiltin(kind()));
}
__ bind(&miss);
- StubCompiler::TailCallBuiltin(masm, StubCompiler::MissBuiltin(kind()));
+ StubCompiler::TailCallBuiltin(
+ masm, BaseLoadStoreStubCompiler::MissBuiltin(kind()));
}
// -- esp[0] : return address
// -----------------------------------
- Code::Flags flags =
- Code::ComputeFlags(Code::STORE_IC, MONOMORPHIC, strict_mode);
+ Code::Flags flags = Code::ComputeFlags(
+ Code::STUB, MONOMORPHIC, strict_mode,
+ Code::NORMAL, Code::STORE_IC);
Isolate::Current()->stub_cache()->GenerateProbe(masm, flags, edx, ecx, ebx,
no_reg);
}
-// Both name_reg and receiver_reg are preserved on jumps to miss_label,
-// but may be destroyed if store is successful.
-void StubCompiler::GenerateStoreTransition(MacroAssembler* masm,
- Handle<JSObject> object,
- LookupResult* lookup,
- Handle<Map> transition,
- Handle<Name> name,
- Register receiver_reg,
- Register name_reg,
- Register value_reg,
- Register scratch1,
- Register scratch2,
- Register unused,
- Label* miss_label,
- Label* miss_restore_name,
- Label* slow) {
- // Check that the map of the object hasn't changed.
- __ CheckMap(receiver_reg, Handle<Map>(object->map()),
- miss_label, DO_SMI_CHECK);
-
- // Perform global security token check if needed.
- if (object->IsJSGlobalProxy()) {
- __ CheckAccessGlobalProxy(receiver_reg, scratch1, scratch2, miss_label);
- }
-
+void BaseStoreStubCompiler::GenerateNegativeHolderLookup(
+ MacroAssembler* masm,
+ Handle<JSObject> holder,
+ Register holder_reg,
+ Handle<Name> name,
+ Label* miss) {
+ if (holder->IsJSGlobalObject()) {
+ GenerateCheckPropertyCell(
+ masm, Handle<GlobalObject>::cast(holder), name, scratch1(), miss);
+ } else if (!holder->HasFastProperties() && !holder->IsJSGlobalProxy()) {
+ GenerateDictionaryNegativeLookup(
+ masm, miss, holder_reg, name, scratch1(), scratch2());
+ }
+}
+
+
+// Receiver_reg is preserved on jumps to miss_label, but may be destroyed if
+// store is successful.
+void BaseStoreStubCompiler::GenerateStoreTransition(MacroAssembler* masm,
+ Handle<JSObject> object,
+ LookupResult* lookup,
+ Handle<Map> transition,
+ Handle<Name> name,
+ Register receiver_reg,
+ Register storage_reg,
+ Register value_reg,
+ Register scratch1,
+ Register scratch2,
+ Register unused,
+ Label* miss_label,
+ Label* slow) {
int descriptor = transition->LastAdded();
DescriptorArray* descriptors = transition->instance_descriptors();
PropertyDetails details = descriptors->GetDetails(descriptor);
Representation representation = details.representation();
ASSERT(!representation.IsNone());
- // Ensure no transitions to deprecated maps are followed.
- __ CheckMapDeprecated(transition, scratch1, miss_label);
-
- // Check that we are allowed to write this.
- if (object->GetPrototype()->IsJSObject()) {
- JSObject* holder;
- // holder == object indicates that no property was found.
- if (lookup->holder() != *object) {
- holder = lookup->holder();
- } else {
- // Find the top object.
- holder = *object;
- do {
- holder = JSObject::cast(holder->GetPrototype());
- } while (holder->GetPrototype()->IsJSObject());
- }
- // We need an extra register, push
- Register holder_reg = CheckPrototypes(
- object, receiver_reg, Handle<JSObject>(holder), name_reg,
- scratch1, scratch2, name, miss_restore_name, SKIP_RECEIVER);
- // If no property was found, and the holder (the last object in the
- // prototype chain) is in slow mode, we need to do a negative lookup on the
- // holder.
- if (lookup->holder() == *object) {
- if (holder->IsJSGlobalObject()) {
- GenerateCheckPropertyCell(
- masm,
- Handle<GlobalObject>(GlobalObject::cast(holder)),
- name,
- scratch1,
- miss_restore_name);
- } else if (!holder->HasFastProperties() && !holder->IsJSGlobalProxy()) {
- GenerateDictionaryNegativeLookup(
- masm, miss_restore_name, holder_reg, name, scratch1, scratch2);
- }
- }
- }
-
- Register storage_reg = name_reg;
-
if (details.type() == CONSTANT_FUNCTION) {
Handle<HeapObject> constant(
HeapObject::cast(descriptors->GetValue(descriptor)));
__ LoadHeapObject(scratch1, constant);
__ cmp(value_reg, scratch1);
- __ j(not_equal, miss_restore_name);
+ __ j(not_equal, miss_label);
} else if (FLAG_track_fields && representation.IsSmi()) {
- __ JumpIfNotSmi(value_reg, miss_restore_name);
+ __ JumpIfNotSmi(value_reg, miss_label);
} else if (FLAG_track_heap_object_fields && representation.IsHeapObject()) {
- __ JumpIfSmi(value_reg, miss_restore_name);
+ __ JumpIfSmi(value_reg, miss_label);
} else if (FLAG_track_double_fields && representation.IsDouble()) {
Label do_store, heap_number;
__ AllocateHeapNumber(storage_reg, scratch1, scratch2, slow);
__ bind(&heap_number);
__ CheckMap(value_reg, masm->isolate()->factory()->heap_number_map(),
- miss_restore_name, DONT_DO_SMI_CHECK);
+ miss_label, DONT_DO_SMI_CHECK);
if (CpuFeatures::IsSupported(SSE2)) {
CpuFeatureScope use_sse2(masm, SSE2);
__ movdbl(xmm0, FieldOperand(value_reg, HeapNumber::kValueOffset));
if (!FLAG_track_fields || !representation.IsSmi()) {
// Update the write barrier for the array address.
- // Pass the value being stored in the now unused name_reg.
if (!FLAG_track_double_fields || !representation.IsDouble()) {
- __ mov(name_reg, value_reg);
- } else {
- ASSERT(storage_reg.is(name_reg));
+ __ mov(storage_reg, value_reg);
}
__ RecordWriteField(receiver_reg,
offset,
- name_reg,
+ storage_reg,
scratch1,
kDontSaveFPRegs,
EMIT_REMEMBERED_SET,
if (!FLAG_track_fields || !representation.IsSmi()) {
// Update the write barrier for the array address.
- // Pass the value being stored in the now unused name_reg.
if (!FLAG_track_double_fields || !representation.IsDouble()) {
- __ mov(name_reg, value_reg);
- } else {
- ASSERT(storage_reg.is(name_reg));
+ __ mov(storage_reg, value_reg);
}
__ RecordWriteField(scratch1,
offset,
- name_reg,
+ storage_reg,
receiver_reg,
kDontSaveFPRegs,
EMIT_REMEMBERED_SET,
// Both name_reg and receiver_reg are preserved on jumps to miss_label,
// but may be destroyed if store is successful.
-void StubCompiler::GenerateStoreField(MacroAssembler* masm,
- Handle<JSObject> object,
- LookupResult* lookup,
- Register receiver_reg,
- Register name_reg,
- Register value_reg,
- Register scratch1,
- Register scratch2,
- Label* miss_label) {
- // Check that the map of the object hasn't changed.
- __ CheckMap(receiver_reg, Handle<Map>(object->map()),
- miss_label, DO_SMI_CHECK);
-
- // Perform global security token check if needed.
- if (object->IsJSGlobalProxy()) {
- __ CheckAccessGlobalProxy(receiver_reg, scratch1, scratch2, miss_label);
- }
-
+void BaseStoreStubCompiler::GenerateStoreField(MacroAssembler* masm,
+ Handle<JSObject> object,
+ LookupResult* lookup,
+ Register receiver_reg,
+ Register name_reg,
+ Register value_reg,
+ Register scratch1,
+ Register scratch2,
+ Label* miss_label) {
// Stub never generated for non-global objects that require access
// checks.
ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
}
-void BaseLoadStubCompiler::HandlerFrontendFooter(Label* success,
+void BaseLoadStubCompiler::HandlerFrontendFooter(Handle<Name> name,
+ Label* success,
Label* miss) {
if (!miss->is_unused()) {
__ jmp(success);
}
+void BaseStoreStubCompiler::HandlerFrontendFooter(Handle<Name> name,
+ Label* success,
+ Label* miss) {
+ if (!miss->is_unused()) {
+ __ jmp(success);
+ GenerateRestoreName(masm(), miss, name);
+ TailCallBuiltin(masm(), MissBuiltin(kind()));
+ }
+}
+
+
Register BaseLoadStubCompiler::CallbackHandlerFrontend(
Handle<JSObject> object,
Register object_reg,
__ j(not_equal, &miss);
}
- HandlerFrontendFooter(success, &miss);
+ HandlerFrontendFooter(name, success, &miss);
return reg;
}
GenerateCheckPropertyCell(masm(), global, name, scratch2(), &miss);
}
- HandlerFrontendFooter(success, &miss);
+ HandlerFrontendFooter(name, success, &miss);
}
Handle<Code> StoreStubCompiler::CompileStoreCallback(
- Handle<Name> name,
Handle<JSObject> object,
Handle<JSObject> holder,
+ Handle<Name> name,
Handle<ExecutableAccessorInfo> callback) {
- Label miss, miss_restore_name;
- // Check that the maps haven't changed, preserving the value register.
- __ JumpIfSmi(receiver(), &miss);
- CheckPrototypes(object, receiver(), holder,
- scratch1(), this->name(), scratch2(),
- name, &miss_restore_name);
-
- // Stub never generated for non-global objects that require access checks.
- ASSERT(holder->IsJSGlobalProxy() || !holder->IsAccessCheckNeeded());
+ Label success;
+ HandlerFrontend(object, receiver(), holder, name, &success);
+ __ bind(&success);
__ pop(scratch1()); // remove the return address
__ push(receiver());
ExternalReference(IC_Utility(IC::kStoreCallbackProperty), isolate());
__ TailCallExternalReference(store_callback_property, 4, 1);
- // Handle store cache miss.
- GenerateRestoreName(masm(), &miss_restore_name, name);
- __ bind(&miss);
- TailCallBuiltin(masm(), MissBuiltin(kind()));
-
// Return the generated code.
- return GetICCode(kind(), Code::CALLBACKS, name);
+ return GetCode(kind(), Code::CALLBACKS, name);
}
Handle<Code> StoreStubCompiler::CompileStoreInterceptor(
Handle<JSObject> object,
Handle<Name> name) {
- Label miss;
-
- // Check that the map of the object hasn't changed.
- __ CheckMap(receiver(), Handle<Map>(object->map()), &miss, DO_SMI_CHECK);
-
- // Perform global security token check if needed.
- if (object->IsJSGlobalProxy()) {
- __ CheckAccessGlobalProxy(receiver(), scratch1(), scratch2(), &miss);
- }
-
- // Stub never generated for non-global objects that require access
- // checks.
- ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
-
__ pop(scratch1()); // remove the return address
__ push(receiver());
__ push(this->name());
ExternalReference(IC_Utility(IC::kStoreInterceptorProperty), isolate());
__ TailCallExternalReference(store_ic_property, 4, 1);
- // Handle store cache miss.
- __ bind(&miss);
- TailCallBuiltin(masm(), MissBuiltin(kind()));
-
// Return the generated code.
- return GetICCode(kind(), Code::INTERCEPTOR, name);
+ return GetCode(kind(), Code::INTERCEPTOR, name);
}
__ Check(not_equal, "DontDelete cells can't contain the hole");
}
- HandlerFrontendFooter(&success, &miss);
+ HandlerFrontendFooter(name, &success, &miss);
__ bind(&success);
Counters* counters = isolate()->counters();
}
-Handle<Code> BaseLoadStubCompiler::CompilePolymorphicIC(
+Handle<Code> BaseLoadStoreStubCompiler::CompilePolymorphicIC(
MapHandleList* receiver_maps,
CodeHandleList* handlers,
Handle<Name> name,
int index = map->IndexInCodeCache(name, target);
if (index >= 0) {
map->RemoveFromCodeCache(String::cast(name), target, index);
- // For loads, handlers are stored in addition to the ICs on the map. Remove
- // those, too.
- if (target->is_load_stub() || target->is_keyed_load_stub()) {
+ // For loads and stores, handlers are stored in addition to the ICs on the
+ // map. Remove those, too.
+ if ((target->is_load_stub() || target->is_keyed_load_stub() ||
+ target->is_store_stub() || target->is_keyed_store_stub()) &&
+ target->type() != Code::NORMAL) {
Code* handler = target->FindFirstCode();
index = map->IndexInCodeCache(name, handler);
if (index >= 0) {
bool IC::UpdatePolymorphicIC(State state,
- StrictModeFlag strict_mode,
Handle<JSObject> receiver,
Handle<String> name,
- Handle<Code> code) {
+ Handle<Code> code,
+ StrictModeFlag strict_mode) {
if (code->type() == Code::NORMAL) return false;
if (target()->ic_state() == MONOMORPHIC &&
target()->type() == Code::NORMAL) {
handlers.Add(code);
}
- Handle<Code> ic = isolate()->stub_cache()->ComputePolymorphicIC(
- &receiver_maps, &handlers, number_of_valid_maps, name);
+ Handle<Code> ic = ComputePolymorphicIC(
+ &receiver_maps, &handlers, number_of_valid_maps, name, strict_mode);
set_target(*ic);
return true;
}
+Handle<Code> LoadIC::ComputePolymorphicIC(MapHandleList* receiver_maps,
+ CodeHandleList* handlers,
+ int number_of_valid_maps,
+ Handle<Name> name,
+ StrictModeFlag strict_mode) {
+ return isolate()->stub_cache()->ComputePolymorphicLoadIC(
+ receiver_maps, handlers, number_of_valid_maps, name);
+}
+
+
+Handle<Code> StoreIC::ComputePolymorphicIC(MapHandleList* receiver_maps,
+ CodeHandleList* handlers,
+ int number_of_valid_maps,
+ Handle<Name> name,
+ StrictModeFlag strict_mode) {
+ return isolate()->stub_cache()->ComputePolymorphicStoreIC(
+ receiver_maps, handlers, number_of_valid_maps, name, strict_mode);
+}
+
+
void LoadIC::UpdateMonomorphicIC(Handle<JSObject> receiver,
Handle<Code> handler,
- Handle<String> name) {
+ Handle<String> name,
+ StrictModeFlag strict_mode) {
if (handler->type() == Code::NORMAL) return set_target(*handler);
- Handle<Code> ic = isolate()->stub_cache()->ComputeMonomorphicIC(
+ Handle<Code> ic = isolate()->stub_cache()->ComputeMonomorphicLoadIC(
receiver, handler, name);
set_target(*ic);
}
void KeyedLoadIC::UpdateMonomorphicIC(Handle<JSObject> receiver,
Handle<Code> handler,
- Handle<String> name) {
+ Handle<String> name,
+ StrictModeFlag strict_mode) {
if (handler->type() == Code::NORMAL) return set_target(*handler);
- Handle<Code> ic = isolate()->stub_cache()->ComputeKeyedMonomorphicIC(
+ Handle<Code> ic = isolate()->stub_cache()->ComputeMonomorphicKeyedLoadIC(
receiver, handler, name);
set_target(*ic);
}
+void StoreIC::UpdateMonomorphicIC(Handle<JSObject> receiver,
+ Handle<Code> handler,
+ Handle<String> name,
+ StrictModeFlag strict_mode) {
+ if (handler->type() == Code::NORMAL) return set_target(*handler);
+ Handle<Code> ic = isolate()->stub_cache()->ComputeMonomorphicStoreIC(
+ receiver, handler, name, strict_mode);
+ set_target(*ic);
+}
+
+
+void KeyedStoreIC::UpdateMonomorphicIC(Handle<JSObject> receiver,
+ Handle<Code> handler,
+ Handle<String> name,
+ StrictModeFlag strict_mode) {
+ if (handler->type() == Code::NORMAL) return set_target(*handler);
+ Handle<Code> ic = isolate()->stub_cache()->ComputeMonomorphicKeyedStoreIC(
+ receiver, handler, name, strict_mode);
+ set_target(*ic);
+}
+
+
void IC::CopyICToMegamorphicCache(Handle<String> name) {
MapHandleList receiver_maps;
CodeHandleList handlers;
case UNINITIALIZED:
case PREMONOMORPHIC:
case MONOMORPHIC_PROTOTYPE_FAILURE:
- UpdateMonomorphicIC(receiver, code, name);
+ UpdateMonomorphicIC(receiver, code, name, strict_mode);
break;
case MONOMORPHIC:
// Only move to megamorphic if the target changes.
if (target() != *code) {
- if (target()->is_load_stub()) {
+ if (target()->is_load_stub() || target()->is_store_stub()) {
bool is_same_handler = false;
{
DisallowHeapAllocation no_allocation;
}
if (is_same_handler
&& IsTransitionedMapOfMonomorphicTarget(receiver->map())) {
- UpdateMonomorphicIC(receiver, code, name);
+ UpdateMonomorphicIC(receiver, code, name, strict_mode);
break;
}
- if (UpdatePolymorphicIC(state, strict_mode, receiver, name, code)) {
+ if (UpdatePolymorphicIC(state, receiver, name, code, strict_mode)) {
break;
}
UpdateMegamorphicCache(receiver->map(), *name, *code);
break;
case POLYMORPHIC:
- if (target()->is_load_stub()) {
- if (UpdatePolymorphicIC(state, strict_mode, receiver, name, code)) {
+ if (target()->is_load_stub() || target()->is_store_stub()) {
+ if (UpdatePolymorphicIC(state, receiver, name, code, strict_mode)) {
break;
}
CopyICToMegamorphicCache(name);
UpdateMegamorphicCache(receiver->map(), *name, *code);
- set_target(*megamorphic_stub());
+ set_target((strict_mode == kStrictMode)
+ ? *megamorphic_stub_strict()
+ : *megamorphic_stub());
} else {
// When trying to patch a polymorphic keyed load/store element stub
// with anything other than another polymorphic stub, go generic.
virtual void UpdateMonomorphicIC(Handle<JSObject> receiver,
Handle<Code> handler,
- Handle<String> name) {
+ Handle<String> name,
+ StrictModeFlag strict_mode) {
set_target(*handler);
}
bool UpdatePolymorphicIC(State state,
- StrictModeFlag strict_mode,
Handle<JSObject> receiver,
Handle<String> name,
- Handle<Code> code);
+ Handle<Code> code,
+ StrictModeFlag strict_mode);
+
+ virtual Handle<Code> ComputePolymorphicIC(MapHandleList* receiver_maps,
+ CodeHandleList* handlers,
+ int number_of_valid_maps,
+ Handle<Name> name,
+ StrictModeFlag strict_mode) {
+ UNREACHABLE();
+ return Handle<Code>::null();
+ };
+
void CopyICToMegamorphicCache(Handle<String> name);
bool IsTransitionedMapOfMonomorphicTarget(Map* receiver_map);
void PatchCache(State state,
State state,
Handle<Object> object,
Handle<String> name);
+
virtual void UpdateMonomorphicIC(Handle<JSObject> receiver,
Handle<Code> handler,
- Handle<String> name);
+ Handle<String> name,
+ StrictModeFlag strict_mode);
+
+ virtual Handle<Code> ComputePolymorphicIC(MapHandleList* receiver_maps,
+ CodeHandleList* handlers,
+ int number_of_valid_maps,
+ Handle<Name> name,
+ StrictModeFlag strict_mode);
+
virtual Handle<Code> ComputeLoadHandler(LookupResult* lookup,
Handle<JSObject> receiver,
Handle<String> name);
// Update the inline cache.
virtual void UpdateMonomorphicIC(Handle<JSObject> receiver,
Handle<Code> handler,
- Handle<String> name);
+ Handle<String> name,
+ StrictModeFlag strict_mode);
virtual Handle<Code> ComputeLoadHandler(LookupResult* lookup,
Handle<JSObject> receiver,
Handle<String> name);
return isolate()->builtins()->StoreIC_GlobalProxy_Strict();
}
+ virtual void UpdateMonomorphicIC(Handle<JSObject> receiver,
+ Handle<Code> handler,
+ Handle<String> name,
+ StrictModeFlag strict_mode);
+
+ virtual Handle<Code> ComputePolymorphicIC(MapHandleList* receiver_maps,
+ CodeHandleList* handlers,
+ int number_of_valid_maps,
+ Handle<Name> name,
+ StrictModeFlag strict_mode);
// Update the inline cache and the global stub cache based on the
// lookup result.
KeyedAccessStoreMode store_mode,
StrictModeFlag strict_mode);
+ virtual void UpdateMonomorphicIC(Handle<JSObject> receiver,
+ Handle<Code> handler,
+ Handle<String> name,
+ StrictModeFlag strict_mode);
+
private:
void set_target(Code* code) {
// Strict mode must be preserved across IC patching.
}
-Handle<Code> StubCache::FindHandler(Handle<Name> name,
- Handle<JSObject> receiver,
- Handle<JSObject> stub_holder,
- Code::Kind kind,
- Code::StubType type) {
+Handle<Code> StubCache::FindLoadHandler(Handle<Name> name,
+ Handle<JSObject> receiver,
+ Handle<JSObject> stub_holder,
+ Code::Kind kind,
+ Code::StubType type) {
Code::ExtraICState extra_ic_state = Code::ComputeExtraICState(
receiver.is_identical_to(stub_holder) ? Code::OWN_STUB
: Code::PROTOTYPE_STUB);
}
-Handle<Code> StubCache::ComputeMonomorphicIC(Handle<JSObject> receiver,
- Handle<Code> handler,
- Handle<Name> name) {
+Handle<Code> StubCache::FindStoreHandler(Handle<Name> name,
+ Handle<JSObject> receiver,
+ Code::Kind kind,
+ Code::StubType type,
+ StrictModeFlag strict_mode) {
+ Code::ExtraICState extra_ic_state = Code::ComputeExtraICState(
+ STANDARD_STORE, strict_mode);
+ ASSERT(type != Code::NORMAL);
+ Code::Flags flags = Code::ComputeMonomorphicFlags(
+ Code::STUB, extra_ic_state, type, kind);
+ Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags),
+ isolate_);
+ if (probe->IsCode()) return Handle<Code>::cast(probe);
+ return Handle<Code>::null();
+}
+
+
+Handle<Code> StubCache::ComputeMonomorphicLoadIC(Handle<JSObject> receiver,
+ Handle<Code> handler,
+ Handle<Name> name) {
Handle<Code> ic = FindIC(name, receiver, Code::LOAD_IC, handler->type());
if (!ic.is_null()) return ic;
}
-Handle<Code> StubCache::ComputeKeyedMonomorphicIC(Handle<JSObject> receiver,
- Handle<Code> handler,
- Handle<Name> name) {
+Handle<Code> StubCache::ComputeMonomorphicKeyedLoadIC(Handle<JSObject> receiver,
+ Handle<Code> handler,
+ Handle<Name> name) {
Handle<Code> ic = FindIC(
name, receiver, Code::KEYED_LOAD_IC, handler->type());
if (!ic.is_null()) return ic;
}
+Handle<Code> StubCache::ComputeMonomorphicStoreIC(Handle<JSObject> receiver,
+ Handle<Code> handler,
+ Handle<Name> name,
+ StrictModeFlag strict_mode) {
+ Handle<Code> ic = FindIC(
+ name, receiver, Code::STORE_IC, handler->type(), strict_mode);
+ if (!ic.is_null()) return ic;
+
+ StoreStubCompiler ic_compiler(isolate(), strict_mode);
+ ic = ic_compiler.CompileMonomorphicIC(
+ Handle<Map>(receiver->map()), handler, name);
+
+ JSObject::UpdateMapCodeCache(receiver, name, ic);
+ return ic;
+}
+
+
+Handle<Code> StubCache::ComputeMonomorphicKeyedStoreIC(
+ Handle<JSObject> receiver,
+ Handle<Code> handler,
+ Handle<Name> name,
+ StrictModeFlag strict_mode) {
+ Handle<Code> ic = FindIC(
+ name, receiver, Code::KEYED_STORE_IC, handler->type(), strict_mode);
+ if (!ic.is_null()) return ic;
+
+ KeyedStoreStubCompiler ic_compiler(isolate(), strict_mode, STANDARD_STORE);
+ ic = ic_compiler.CompileMonomorphicIC(
+ Handle<Map>(receiver->map()), handler, name);
+
+ JSObject::UpdateMapCodeCache(receiver, name, ic);
+ return ic;
+}
+
+
Handle<Code> StubCache::ComputeLoadNonexistent(Handle<Name> name,
Handle<JSObject> receiver) {
// If no global objects are present in the prototype chain, the load
// Compile the stub that is either shared for all names or
// name specific if there are global objects involved.
- Handle<Code> handler = FindHandler(
+ Handle<Code> handler = FindLoadHandler(
cache_name, receiver, receiver, Code::LOAD_IC, Code::NONEXISTENT);
if (!handler.is_null()) return handler;
}
Handle<JSObject> stub_holder = StubHolder(receiver, holder);
- Handle<Code> stub = FindHandler(
+ Handle<Code> stub = FindLoadHandler(
name, receiver, stub_holder, Code::LOAD_IC, Code::FIELD);
if (!stub.is_null()) return stub;
Handle<ExecutableAccessorInfo> callback) {
ASSERT(v8::ToCData<Address>(callback->getter()) != 0);
Handle<JSObject> stub_holder = StubHolder(receiver, holder);
- Handle<Code> stub = FindHandler(
+ Handle<Code> stub = FindLoadHandler(
name, receiver, stub_holder, Code::LOAD_IC, Code::CALLBACKS);
if (!stub.is_null()) return stub;
Handle<JSObject> holder,
Handle<JSFunction> getter) {
Handle<JSObject> stub_holder = StubHolder(receiver, holder);
- Handle<Code> stub = FindHandler(
+ Handle<Code> stub = FindLoadHandler(
name, receiver, stub_holder, Code::LOAD_IC, Code::CALLBACKS);
if (!stub.is_null()) return stub;
Handle<JSObject> holder,
Handle<JSFunction> value) {
Handle<JSObject> stub_holder = StubHolder(receiver, holder);
- Handle<Code> handler = FindHandler(
+ Handle<Code> handler = FindLoadHandler(
name, receiver, stub_holder, Code::LOAD_IC, Code::CONSTANT_FUNCTION);
if (!handler.is_null()) return handler;
Handle<JSObject> receiver,
Handle<JSObject> holder) {
Handle<JSObject> stub_holder = StubHolder(receiver, holder);
- Handle<Code> stub = FindHandler(
+ Handle<Code> stub = FindLoadHandler(
name, receiver, stub_holder, Code::LOAD_IC, Code::INTERCEPTOR);
if (!stub.is_null()) return stub;
}
Handle<JSObject> stub_holder = StubHolder(receiver, holder);
- Handle<Code> stub = FindHandler(
+ Handle<Code> stub = FindLoadHandler(
name, receiver, stub_holder, Code::KEYED_LOAD_IC, Code::FIELD);
if (!stub.is_null()) return stub;
Handle<JSObject> holder,
Handle<JSFunction> value) {
Handle<JSObject> stub_holder = StubHolder(receiver, holder);
- Handle<Code> handler = FindHandler(
+ Handle<Code> handler = FindLoadHandler(
name, receiver, stub_holder, Code::KEYED_LOAD_IC,
Code::CONSTANT_FUNCTION);
if (!handler.is_null()) return handler;
Handle<JSObject> receiver,
Handle<JSObject> holder) {
Handle<JSObject> stub_holder = StubHolder(receiver, holder);
- Handle<Code> stub = FindHandler(
+ Handle<Code> stub = FindLoadHandler(
name, receiver, stub_holder, Code::KEYED_LOAD_IC, Code::INTERCEPTOR);
if (!stub.is_null()) return stub;
Handle<JSObject> holder,
Handle<ExecutableAccessorInfo> callback) {
Handle<JSObject> stub_holder = StubHolder(receiver, holder);
- Handle<Code> stub = FindHandler(
+ Handle<Code> stub = FindLoadHandler(
name, receiver, stub_holder, Code::KEYED_LOAD_IC, Code::CALLBACKS);
if (!stub.is_null()) return stub;
Handle<JSObject> receiver,
LookupResult* lookup,
StrictModeFlag strict_mode) {
- Handle<Code> stub = FindIC(
+ Handle<Code> stub = FindStoreHandler(
name, receiver, Code::STORE_IC, Code::FIELD, strict_mode);
if (!stub.is_null()) return stub;
StoreStubCompiler compiler(isolate_, strict_mode);
- Handle<Code> code = compiler.CompileStoreField(receiver, lookup, name);
- JSObject::UpdateMapCodeCache(receiver, name, code);
- return code;
+ Handle<Code> handler = compiler.CompileStoreField(receiver, lookup, name);
+ JSObject::UpdateMapCodeCache(receiver, name, handler);
+ return handler;
}
LookupResult* lookup,
Handle<Map> transition,
StrictModeFlag strict_mode) {
- Handle<Code> stub = FindIC(
+ Handle<Code> stub = FindStoreHandler(
name, receiver, Code::STORE_IC, Code::MAP_TRANSITION, strict_mode);
if (!stub.is_null()) return stub;
StoreStubCompiler compiler(isolate_, strict_mode);
- Handle<Code> code =
+ Handle<Code> handler =
compiler.CompileStoreTransition(receiver, lookup, transition, name);
- JSObject::UpdateMapCodeCache(receiver, name, code);
- return code;
+ JSObject::UpdateMapCodeCache(receiver, name, handler);
+ return handler;
}
Handle<ExecutableAccessorInfo> callback,
StrictModeFlag strict_mode) {
ASSERT(v8::ToCData<Address>(callback->setter()) != 0);
- Handle<Code> stub = FindIC(
+ Handle<Code> stub = FindStoreHandler(
name, receiver, Code::STORE_IC, Code::CALLBACKS, strict_mode);
if (!stub.is_null()) return stub;
StoreStubCompiler compiler(isolate_, strict_mode);
- Handle<Code> code =
- compiler.CompileStoreCallback(name, receiver, holder, callback);
- JSObject::UpdateMapCodeCache(receiver, name, code);
- return code;
+ Handle<Code> handler = compiler.CompileStoreCallback(
+ receiver, holder, name, callback);
+ JSObject::UpdateMapCodeCache(receiver, name, handler);
+ return handler;
}
Handle<JSObject> holder,
Handle<JSFunction> setter,
StrictModeFlag strict_mode) {
- Handle<Code> stub = FindIC(
+ Handle<Code> stub = FindStoreHandler(
name, receiver, Code::STORE_IC, Code::CALLBACKS, strict_mode);
if (!stub.is_null()) return stub;
StoreStubCompiler compiler(isolate_, strict_mode);
- Handle<Code> code =
- compiler.CompileStoreViaSetter(name, receiver, holder, setter);
- JSObject::UpdateMapCodeCache(receiver, name, code);
- return code;
+ Handle<Code> handler = compiler.CompileStoreViaSetter(
+ receiver, holder, name, setter);
+ JSObject::UpdateMapCodeCache(receiver, name, handler);
+ return handler;
}
Handle<Code> StubCache::ComputeStoreInterceptor(Handle<Name> name,
Handle<JSObject> receiver,
StrictModeFlag strict_mode) {
- Handle<Code> stub = FindIC(
+ Handle<Code> stub = FindStoreHandler(
name, receiver, Code::STORE_IC, Code::INTERCEPTOR, strict_mode);
if (!stub.is_null()) return stub;
StoreStubCompiler compiler(isolate_, strict_mode);
- Handle<Code> code = compiler.CompileStoreInterceptor(receiver, name);
- JSObject::UpdateMapCodeCache(receiver, name, code);
- return code;
+ Handle<Code> handler = compiler.CompileStoreInterceptor(receiver, name);
+ JSObject::UpdateMapCodeCache(receiver, name, handler);
+ return handler;
}
Handle<JSObject> receiver,
LookupResult* lookup,
StrictModeFlag strict_mode) {
- Handle<Code> stub = FindIC(
+ Handle<Code> stub = FindStoreHandler(
name, receiver, Code::KEYED_STORE_IC, Code::FIELD, strict_mode);
if (!stub.is_null()) return stub;
KeyedStoreStubCompiler compiler(isolate(), strict_mode, STANDARD_STORE);
- Handle<Code> code = compiler.CompileStoreField(receiver, lookup, name);
- JSObject::UpdateMapCodeCache(receiver, name, code);
- return code;
+ Handle<Code> handler = compiler.CompileStoreField(receiver, lookup, name);
+ JSObject::UpdateMapCodeCache(receiver, name, handler);
+ return handler;
}
LookupResult* lookup,
Handle<Map> transition,
StrictModeFlag strict_mode) {
- Handle<Code> stub = FindIC(
+ Handle<Code> stub = FindStoreHandler(
name, receiver, Code::KEYED_STORE_IC, Code::MAP_TRANSITION, strict_mode);
if (!stub.is_null()) return stub;
KeyedStoreStubCompiler compiler(isolate(), strict_mode, STANDARD_STORE);
- Handle<Code> code =
+ Handle<Code> handler =
compiler.CompileStoreTransition(receiver, lookup, transition, name);
- JSObject::UpdateMapCodeCache(receiver, name, code);
- return code;
+ JSObject::UpdateMapCodeCache(receiver, name, handler);
+ return handler;
}
}
-Handle<Code> StubCache::ComputePolymorphicIC(MapHandleList* receiver_maps,
- CodeHandleList* handlers,
- int number_of_valid_maps,
- Handle<Name> name) {
+Handle<Code> StubCache::ComputePolymorphicLoadIC(MapHandleList* receiver_maps,
+ CodeHandleList* handlers,
+ int number_of_valid_maps,
+ Handle<Name> name) {
LoadStubCompiler ic_compiler(isolate_);
Code::StubType type = number_of_valid_maps == 1 ? handlers->at(0)->type()
: Code::NORMAL;
}
+Handle<Code> StubCache::ComputePolymorphicStoreIC(MapHandleList* receiver_maps,
+ CodeHandleList* handlers,
+ int number_of_valid_maps,
+ Handle<Name> name,
+ StrictModeFlag strict_mode) {
+ StoreStubCompiler ic_compiler(isolate_, strict_mode);
+ Code::StubType type = number_of_valid_maps == 1 ? handlers->at(0)->type()
+ : Code::NORMAL;
+ Handle<Code> ic = ic_compiler.CompilePolymorphicIC(
+ receiver_maps, handlers, name, type, PROPERTY);
+ return ic;
+}
+
+
Handle<Code> StubCache::ComputeStoreElementPolymorphic(
MapHandleList* receiver_maps,
KeyedAccessStoreMode store_mode,
#define __ ACCESS_MASM(masm())
-Register BaseLoadStubCompiler::HandlerFrontendHeader(Handle<JSObject> object,
- Register object_reg,
- Handle<JSObject> holder,
- Handle<Name> name,
- Label* miss) {
- // Check the prototype chain.
+Register BaseLoadStubCompiler::HandlerFrontendHeader(
+ Handle<JSObject> object,
+ Register object_reg,
+ Handle<JSObject> holder,
+ Handle<Name> name,
+ Label* miss) {
return CheckPrototypes(object, object_reg, holder,
scratch1(), scratch2(), scratch3(),
name, miss, SKIP_RECEIVER);
}
-Register BaseLoadStubCompiler::HandlerFrontend(Handle<JSObject> object,
- Register object_reg,
- Handle<JSObject> holder,
- Handle<Name> name,
- Label* success) {
+// HandlerFrontend for store uses the name register. It has to be restored
+// before a miss.
+Register BaseStoreStubCompiler::HandlerFrontendHeader(
+ Handle<JSObject> object,
+ Register object_reg,
+ Handle<JSObject> holder,
+ Handle<Name> name,
+ Label* miss) {
+ return CheckPrototypes(object, object_reg, holder,
+ this->name(), scratch1(), scratch2(),
+ name, miss, SKIP_RECEIVER);
+}
+
+
+Register BaseLoadStoreStubCompiler::HandlerFrontend(Handle<JSObject> object,
+ Register object_reg,
+ Handle<JSObject> holder,
+ Handle<Name> name,
+ Label* success) {
Label miss;
Register reg = HandlerFrontendHeader(object, object_reg, holder, name, &miss);
- HandlerFrontendFooter(success, &miss);
+ HandlerFrontendFooter(name, success, &miss);
return reg;
}
}
-Handle<Code> BaseLoadStubCompiler::CompileMonomorphicIC(
+Handle<Code> BaseLoadStoreStubCompiler::CompileMonomorphicIC(
Handle<Map> receiver_map,
Handle<Code> handler,
Handle<Name> name) {
LookupResult* lookup,
Handle<Map> transition,
Handle<Name> name) {
- Label miss, miss_restore_name, slow;
+ Label miss, slow;
+
+ // Ensure no transitions to deprecated maps are followed.
+ __ CheckMapDeprecated(transition, scratch1(), &miss);
+
+ // Check that we are allowed to write this.
+ if (object->GetPrototype()->IsJSObject()) {
+ Handle<JSObject> holder;
+ // holder == object indicates that no property was found.
+ if (lookup->holder() != *object) {
+ holder = Handle<JSObject>(lookup->holder());
+ } else {
+ // Find the top object.
+ holder = object;
+ do {
+ holder = Handle<JSObject>(JSObject::cast(holder->GetPrototype()));
+ } while (holder->GetPrototype()->IsJSObject());
+ }
- GenerateNameCheck(name, this->name(), &miss);
+ Register holder_reg =
+ HandlerFrontendHeader(object, receiver(), holder, name, &miss);
+
+ // If no property was found, and the holder (the last object in the
+ // prototype chain) is in slow mode, we need to do a negative lookup on the
+ // holder.
+ if (lookup->holder() == *object) {
+ GenerateNegativeHolderLookup(masm(), holder, holder_reg, name, &miss);
+ }
+ }
GenerateStoreTransition(masm(),
object,
receiver(), this->name(), value(),
scratch1(), scratch2(), scratch3(),
&miss,
- &miss_restore_name,
&slow);
// Handle store cache miss.
- GenerateRestoreName(masm(), &miss_restore_name, name);
- __ bind(&miss);
+ GenerateRestoreName(masm(), &miss, name);
TailCallBuiltin(masm(), MissBuiltin(kind()));
GenerateRestoreName(masm(), &slow, name);
TailCallBuiltin(masm(), SlowBuiltin(kind()));
// Return the generated code.
- return GetICCode(kind(), Code::MAP_TRANSITION, name);
+ return GetCode(kind(), Code::MAP_TRANSITION, name);
}
Handle<Name> name) {
Label miss;
- GenerateNameCheck(name, this->name(), &miss);
+ HandlerFrontendHeader(object, receiver(), object, name, &miss);
// Generate store field code.
GenerateStoreField(masm(),
TailCallBuiltin(masm(), MissBuiltin(kind()));
// Return the generated code.
- return GetICCode(kind(), Code::FIELD, name);
+ return GetCode(kind(), Code::FIELD, name);
}
Handle<Code> StoreStubCompiler::CompileStoreViaSetter(
- Handle<Name> name,
Handle<JSObject> object,
Handle<JSObject> holder,
+ Handle<Name> name,
Handle<JSFunction> setter) {
- Label miss, miss_restore_name;
-
- // Check that the maps haven't changed, preserving the name register.
- __ JumpIfSmi(receiver(), &miss);
- CheckPrototypes(object, receiver(), holder,
- this->name(), scratch1(), scratch2(),
- name, &miss_restore_name);
+ Label success;
+ HandlerFrontend(object, receiver(), holder, name, &success);
+ __ bind(&success);
GenerateStoreViaSetter(masm(), setter);
- GenerateRestoreName(masm(), &miss_restore_name, name);
-
- __ bind(&miss);
- TailCallBuiltin(masm(), MissBuiltin(kind()));
-
- // Return the generated code.
- return GetICCode(kind(), Code::CALLBACKS, name);
+ return GetCode(kind(), Code::CALLBACKS, name);
}
}
-Handle<Code> BaseLoadStubCompiler::GetICCode(Code::Kind kind,
- Code::StubType type,
- Handle<Name> name,
- InlineCacheState state) {
+Handle<Code> BaseLoadStoreStubCompiler::GetICCode(Code::Kind kind,
+ Code::StubType type,
+ Handle<Name> name,
+ InlineCacheState state) {
Code::Flags flags = Code::ComputeFlags(
- kind, state, Code::kNoExtraICState, type);
+ kind, state, extra_state(), type);
Handle<Code> code = GetCodeWithFlags(flags, name);
PROFILE(isolate(), CodeCreateEvent(log_kind(code), *code, *name));
JitEvent(name, code);
}
-Handle<Code> BaseStoreStubCompiler::GetICCode(Code::Kind kind,
- Code::StubType type,
- Handle<Name> name,
- InlineCacheState state) {
- Code::Flags flags = Code::ComputeFlags(
- kind, state, extra_state(), type);
- Handle<Code> code = GetCodeWithFlags(flags, name);
- PROFILE(isolate(), CodeCreateEvent(log_kind(code), *code, *name));
- JitEvent(name, code);
- return code;
-}
-
-
Handle<Code> BaseStoreStubCompiler::GetCode(Code::Kind kind,
Code::StubType type,
Handle<Name> name) {
Code::StubType type,
Code::ExtraICState extra_state = Code::kNoExtraICState);
- Handle<Code> FindHandler(
- Handle<Name> name,
- Handle<JSObject> receiver,
- Handle<JSObject> stub_holder,
- Code::Kind kind,
- Code::StubType type);
+ Handle<Code> FindLoadHandler(Handle<Name> name,
+ Handle<JSObject> receiver,
+ Handle<JSObject> stub_holder,
+ Code::Kind kind,
+ Code::StubType type);
- Handle<Code> ComputeMonomorphicIC(Handle<JSObject> receiver,
- Handle<Code> handler,
- Handle<Name> name);
- Handle<Code> ComputeKeyedMonomorphicIC(Handle<JSObject> receiver,
+ Handle<Code> FindStoreHandler(Handle<Name> name,
+ Handle<JSObject> receiver,
+ Code::Kind kind,
+ Code::StubType type,
+ StrictModeFlag strict_mode);
+
+ Handle<Code> ComputeMonomorphicLoadIC(Handle<JSObject> receiver,
+ Handle<Code> handler,
+ Handle<Name> name);
+
+ Handle<Code> ComputeMonomorphicKeyedLoadIC(Handle<JSObject> receiver,
+ Handle<Code> handler,
+ Handle<Name> name);
+
+ Handle<Code> ComputeMonomorphicStoreIC(Handle<JSObject> receiver,
Handle<Code> handler,
- Handle<Name> name);
+ Handle<Name> name,
+ StrictModeFlag strict_mode);
+
+ Handle<Code> ComputeMonomorphicKeyedStoreIC(Handle<JSObject> receiver,
+ Handle<Code> handler,
+ Handle<Name> name,
+ StrictModeFlag strict_mode);
// Computes the right stub matching. Inserts the result in the
// cache before returning. This might compile a stub if needed.
KeyedAccessStoreMode store_mode,
StrictModeFlag strict_mode);
- Handle<Code> ComputePolymorphicIC(MapHandleList* receiver_maps,
- CodeHandleList* handlers,
- int number_of_valid_maps,
- Handle<Name> name);
+ Handle<Code> ComputePolymorphicLoadIC(MapHandleList* receiver_maps,
+ CodeHandleList* handlers,
+ int number_of_valid_maps,
+ Handle<Name> name);
+
+ Handle<Code> ComputePolymorphicStoreIC(MapHandleList* receiver_maps,
+ CodeHandleList* handlers,
+ int number_of_valid_maps,
+ Handle<Name> name,
+ StrictModeFlag strict_mode);
// Finds the Code object stored in the Heap::non_monomorphic_cache().
Code* FindCallInitialize(int argc, RelocInfo::Mode mode, Code::Kind kind);
Register scratch2,
Label* miss_label);
- void GenerateStoreTransition(MacroAssembler* masm,
- Handle<JSObject> object,
- LookupResult* lookup,
- Handle<Map> transition,
- Handle<Name> name,
- Register receiver_reg,
- Register name_reg,
- Register value_reg,
- Register scratch1,
- Register scratch2,
- Register scratch3,
- Label* miss_label,
- Label* miss_restore_name,
- Label* slow);
-
- void GenerateStoreField(MacroAssembler* masm,
- Handle<JSObject> object,
- LookupResult* lookup,
- Register receiver_reg,
- Register name_reg,
- Register value_reg,
- Register scratch1,
- Register scratch2,
- Label* miss_label);
-
- static Builtins::Name MissBuiltin(Code::Kind kind) {
- switch (kind) {
- case Code::LOAD_IC: return Builtins::kLoadIC_Miss;
- case Code::STORE_IC: return Builtins::kStoreIC_Miss;
- case Code::KEYED_LOAD_IC: return Builtins::kKeyedLoadIC_Miss;
- case Code::KEYED_STORE_IC: return Builtins::kKeyedStoreIC_Miss;
- default: UNREACHABLE();
- }
- return Builtins::kLoadIC_Miss;
- }
- static Builtins::Name SlowBuiltin(Code::Kind kind) {
- switch (kind) {
- case Code::STORE_IC: return Builtins::kStoreIC_Slow;
- case Code::KEYED_STORE_IC: return Builtins::kKeyedStoreIC_Slow;
- default: UNREACHABLE();
- }
- return Builtins::kStoreIC_Slow;
- }
static void TailCallBuiltin(MacroAssembler* masm, Builtins::Name name);
// Generates code that verifies that the property holder has not changed
enum FrontendCheckType { PERFORM_INITIAL_CHECKS, SKIP_INITIAL_CHECKS };
-class BaseLoadStubCompiler: public StubCompiler {
+class BaseLoadStoreStubCompiler: public StubCompiler {
public:
- BaseLoadStubCompiler(Isolate* isolate, Register* registers)
+ BaseLoadStoreStubCompiler(Isolate* isolate, Register* registers)
: StubCompiler(isolate), registers_(registers) { }
+ virtual ~BaseLoadStoreStubCompiler() { }
+
+ Handle<Code> CompileMonomorphicIC(Handle<Map> receiver_map,
+ Handle<Code> handler,
+ Handle<Name> name);
+
+ Handle<Code> CompilePolymorphicIC(MapHandleList* receiver_maps,
+ CodeHandleList* handlers,
+ Handle<Name> name,
+ Code::StubType type,
+ IcCheckType check);
+
+ virtual void GenerateNameCheck(Handle<Name> name,
+ Register name_reg,
+ Label* miss) { }
+
+ static Builtins::Name MissBuiltin(Code::Kind kind) {
+ switch (kind) {
+ case Code::LOAD_IC: return Builtins::kLoadIC_Miss;
+ case Code::STORE_IC: return Builtins::kStoreIC_Miss;
+ case Code::KEYED_LOAD_IC: return Builtins::kKeyedLoadIC_Miss;
+ case Code::KEYED_STORE_IC: return Builtins::kKeyedStoreIC_Miss;
+ default: UNREACHABLE();
+ }
+ return Builtins::kLoadIC_Miss;
+ }
+
+ protected:
+ virtual Register HandlerFrontendHeader(Handle<JSObject> object,
+ Register object_reg,
+ Handle<JSObject> holder,
+ Handle<Name> name,
+ Label* miss) = 0;
+
+ virtual void HandlerFrontendFooter(Handle<Name> name,
+ Label* success,
+ Label* miss) = 0;
+
+ Register HandlerFrontend(Handle<JSObject> object,
+ Register object_reg,
+ Handle<JSObject> holder,
+ Handle<Name> name,
+ Label* success);
+
+ Handle<Code> GetICCode(Code::Kind kind,
+ Code::StubType type,
+ Handle<Name> name,
+ InlineCacheState state = MONOMORPHIC);
+
+ virtual Code::ExtraICState extra_state() { return Code::kNoExtraICState; }
+ virtual Logger::LogEventsAndTags log_kind(Handle<Code> code) = 0;
+ virtual void JitEvent(Handle<Name> name, Handle<Code> code) = 0;
+ virtual Code::Kind kind() = 0;
+ virtual Register receiver() = 0;
+ virtual Register name() = 0;
+ virtual Register scratch1() = 0;
+ virtual Register scratch2() = 0;
+ virtual Register scratch3() = 0;
+
+ Register* registers_;
+};
+
+
+class BaseLoadStubCompiler: public BaseLoadStoreStubCompiler {
+ public:
+ BaseLoadStubCompiler(Isolate* isolate, Register* registers)
+ : BaseLoadStoreStubCompiler(isolate, registers) { }
virtual ~BaseLoadStubCompiler() { }
Handle<Code> CompileLoadField(Handle<JSObject> object,
Handle<JSObject> holder,
Handle<Name> name);
- Handle<Code> CompileMonomorphicIC(Handle<Map> receiver_map,
- Handle<Code> handler,
- Handle<Name> name);
- Handle<Code> CompilePolymorphicIC(MapHandleList* receiver_maps,
- CodeHandleList* handlers,
- Handle<Name> name,
- Code::StubType type,
- IcCheckType check);
-
protected:
- Register HandlerFrontendHeader(Handle<JSObject> object,
- Register object_reg,
- Handle<JSObject> holder,
- Handle<Name> name,
- Label* success);
- void HandlerFrontendFooter(Label* success, Label* miss);
+ virtual Register HandlerFrontendHeader(Handle<JSObject> object,
+ Register object_reg,
+ Handle<JSObject> holder,
+ Handle<Name> name,
+ Label* miss);
+
+ virtual void HandlerFrontendFooter(Handle<Name> name,
+ Label* success,
+ Label* miss);
- Register HandlerFrontend(Handle<JSObject> object,
- Register object_reg,
- Handle<JSObject> holder,
- Handle<Name> name,
- Label* success);
Register CallbackHandlerFrontend(Handle<JSObject> object,
Register object_reg,
Handle<JSObject> holder,
Handle<Name> name,
LookupResult* lookup);
- Handle<Code> GetICCode(Code::Kind kind,
- Code::StubType type,
- Handle<Name> name,
- InlineCacheState state = MONOMORPHIC);
-
Handle<Code> GetCode(Code::Kind kind,
Code::StubType type,
Handle<Name> name);
- Register receiver() { return registers_[0]; }
- Register name() { return registers_[1]; }
- Register scratch1() { return registers_[2]; }
- Register scratch2() { return registers_[3]; }
- Register scratch3() { return registers_[4]; }
+ virtual Register receiver() { return registers_[0]; }
+ virtual Register name() { return registers_[1]; }
+ virtual Register scratch1() { return registers_[2]; }
+ virtual Register scratch2() { return registers_[3]; }
+ virtual Register scratch3() { return registers_[4]; }
Register scratch4() { return registers_[5]; }
-
- private:
- virtual Code::Kind kind() = 0;
- virtual Logger::LogEventsAndTags log_kind(Handle<Code> code) = 0;
- virtual void JitEvent(Handle<Name> name, Handle<Code> code) = 0;
- virtual void GenerateNameCheck(Handle<Name> name,
- Register name_reg,
- Label* miss) { }
- Register* registers_;
};
Handle<Name> name,
bool is_dont_delete);
- static Register receiver() { return registers()[0]; }
-
private:
static Register* registers();
virtual Code::Kind kind() { return Code::LOAD_IC; }
static void GenerateLoadDictionaryElement(MacroAssembler* masm);
- static Register receiver() { return registers()[0]; }
-
private:
static Register* registers();
virtual Code::Kind kind() { return Code::KEYED_LOAD_IC; }
};
-class BaseStoreStubCompiler: public StubCompiler {
+class BaseStoreStubCompiler: public BaseLoadStoreStubCompiler {
public:
BaseStoreStubCompiler(Isolate* isolate,
StrictModeFlag strict_mode,
Register* registers)
- : StubCompiler(isolate),
- strict_mode_(strict_mode),
- registers_(registers) { }
+ : BaseLoadStoreStubCompiler(isolate, registers),
+ strict_mode_(strict_mode) { }
virtual ~BaseStoreStubCompiler() { }
LookupResult* lookup,
Handle<Name> name);
- protected:
- Handle<Code> GetICCode(Code::Kind kind,
- Code::StubType type,
- Handle<Name> name,
- InlineCacheState state = MONOMORPHIC);
+ void GenerateNegativeHolderLookup(MacroAssembler* masm,
+ Handle<JSObject> holder,
+ Register holder_reg,
+ Handle<Name> name,
+ Label* miss);
+
+ void GenerateStoreTransition(MacroAssembler* masm,
+ Handle<JSObject> object,
+ LookupResult* lookup,
+ Handle<Map> transition,
+ Handle<Name> name,
+ Register receiver_reg,
+ Register name_reg,
+ Register value_reg,
+ Register scratch1,
+ Register scratch2,
+ Register scratch3,
+ Label* miss_label,
+ Label* slow);
+
+ void GenerateStoreField(MacroAssembler* masm,
+ Handle<JSObject> object,
+ LookupResult* lookup,
+ Register receiver_reg,
+ Register name_reg,
+ Register value_reg,
+ Register scratch1,
+ Register scratch2,
+ Label* miss_label);
+
+ static Builtins::Name MissBuiltin(Code::Kind kind) {
+ switch (kind) {
+ case Code::LOAD_IC: return Builtins::kLoadIC_Miss;
+ case Code::STORE_IC: return Builtins::kStoreIC_Miss;
+ case Code::KEYED_LOAD_IC: return Builtins::kKeyedLoadIC_Miss;
+ case Code::KEYED_STORE_IC: return Builtins::kKeyedStoreIC_Miss;
+ default: UNREACHABLE();
+ }
+ return Builtins::kLoadIC_Miss;
+ }
+ static Builtins::Name SlowBuiltin(Code::Kind kind) {
+ switch (kind) {
+ case Code::STORE_IC: return Builtins::kStoreIC_Slow;
+ case Code::KEYED_STORE_IC: return Builtins::kKeyedStoreIC_Slow;
+ default: UNREACHABLE();
+ }
+ return Builtins::kStoreIC_Slow;
+ }
+ protected:
+ virtual Register HandlerFrontendHeader(Handle<JSObject> object,
+ Register object_reg,
+ Handle<JSObject> holder,
+ Handle<Name> name,
+ Label* miss);
+
+ virtual void HandlerFrontendFooter(Handle<Name> name,
+ Label* success,
+ Label* miss);
Handle<Code> GetCode(Code::Kind kind,
Code::StubType type,
Handle<Name> name);
Label* label,
Handle<Name> name);
- Register receiver() { return registers_[0]; }
- Register name() { return registers_[1]; }
+ virtual Register receiver() { return registers_[0]; }
+ virtual Register name() { return registers_[1]; }
Register value() { return registers_[2]; }
- Register scratch1() { return registers_[3]; }
- Register scratch2() { return registers_[4]; }
- Register scratch3() { return registers_[5]; }
+ virtual Register scratch1() { return registers_[3]; }
+ virtual Register scratch2() { return registers_[4]; }
+ virtual Register scratch3() { return registers_[5]; }
StrictModeFlag strict_mode() { return strict_mode_; }
virtual Code::ExtraICState extra_state() { return strict_mode_; }
private:
- virtual Code::Kind kind() = 0;
- virtual Logger::LogEventsAndTags log_kind(Handle<Code> code) = 0;
- virtual void JitEvent(Handle<Name> name, Handle<Code> code) = 0;
- virtual void GenerateNameCheck(Handle<Name> name,
- Register name_reg,
- Label* miss) { }
StrictModeFlag strict_mode_;
- Register* registers_;
};
: BaseStoreStubCompiler(isolate, strict_mode, registers()) { }
- Handle<Code> CompileStoreCallback(Handle<Name> name,
- Handle<JSObject> object,
+ Handle<Code> CompileStoreCallback(Handle<JSObject> object,
Handle<JSObject> holder,
+ Handle<Name> name,
Handle<ExecutableAccessorInfo> callback);
static void GenerateStoreViaSetter(MacroAssembler* masm,
Handle<JSFunction> setter);
- Handle<Code> CompileStoreViaSetter(Handle<Name> name,
- Handle<JSObject> object,
+ Handle<Code> CompileStoreViaSetter(Handle<JSObject> object,
Handle<JSObject> holder,
+ Handle<Name> name,
Handle<JSFunction> setter);
Handle<Code> CompileStoreInterceptor(Handle<JSObject> object,
}
-bool TypeFeedbackOracle::StoreIsPolymorphic(TypeFeedbackId ast_id) {
+bool TypeFeedbackOracle::StoreIsKeyedPolymorphic(TypeFeedbackId ast_id) {
Handle<Object> map_or_code = GetInfo(ast_id);
if (map_or_code->IsCode()) {
Handle<Code> code = Handle<Code>::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 &&
+ return code->is_keyed_store_stub() && standard_store &&
code->ic_state() == POLYMORPHIC;
}
return false;
void TypeFeedbackOracle::StoreReceiverTypes(Assignment* expr,
Handle<String> name,
SmallMapList* types) {
- Code::Flags flags = Code::ComputeMonomorphicFlags(Code::STORE_IC);
+ Code::Flags flags = Code::ComputeFlags(
+ Code::STUB, MONOMORPHIC, Code::kNoExtraICState,
+ Code::NORMAL, Code::STORE_IC);
CollectReceiverTypes(expr->AssignmentFeedbackId(), name, flags, types);
}
}
+void TypeFeedbackOracle::CollectPolymorphicStoreReceiverTypes(
+ TypeFeedbackId ast_id,
+ SmallMapList* types) {
+ Handle<Object> object = GetInfo(ast_id);
+ if (!object->IsCode()) return;
+ Handle<Code> code = Handle<Code>::cast(object);
+ if (code->kind() == Code::STORE_IC && code->ic_state() == POLYMORPHIC) {
+ CollectPolymorphicMaps(code, types);
+ }
+}
+
+
byte TypeFeedbackOracle::ToBooleanTypes(TypeFeedbackId id) {
Handle<Object> object = GetInfo(id);
return object->IsCode() ? Handle<Code>::cast(object)->to_boolean_state() : 0;
bool LoadIsPolymorphic(Property* expr);
bool StoreIsUninitialized(TypeFeedbackId ast_id);
bool StoreIsMonomorphicNormal(TypeFeedbackId ast_id);
- bool StoreIsPolymorphic(TypeFeedbackId ast_id);
+ bool StoreIsKeyedPolymorphic(TypeFeedbackId ast_id);
bool CallIsMonomorphic(Call* expr);
bool CallNewIsMonomorphic(CallNew* expr);
bool ObjectLiteralStoreIsMonomorphic(ObjectLiteralProperty* prop);
SmallMapList* types);
void CollectKeyedReceiverTypes(TypeFeedbackId ast_id,
SmallMapList* types);
+ void CollectPolymorphicStoreReceiverTypes(TypeFeedbackId ast_id,
+ SmallMapList* types);
static bool CanRetainOtherContext(Map* map, Context* native_context);
static bool CanRetainOtherContext(JSFunction* function,
StubCompiler::GenerateLoadFunctionPrototype(masm, receiver, r8, r9, &miss);
__ bind(&miss);
- StubCompiler::TailCallBuiltin(masm, StubCompiler::MissBuiltin(kind()));
+ StubCompiler::TailCallBuiltin(
+ masm, BaseLoadStoreStubCompiler::MissBuiltin(kind()));
}
StubCompiler::GenerateLoadStringLength(masm, receiver, r8, r9, &miss,
support_wrapper_);
__ bind(&miss);
- StubCompiler::TailCallBuiltin(masm, StubCompiler::MissBuiltin(kind()));
+ StubCompiler::TailCallBuiltin(
+ masm, BaseLoadStoreStubCompiler::MissBuiltin(kind()));
}
__ bind(&miss);
- StubCompiler::TailCallBuiltin(masm, StubCompiler::MissBuiltin(kind()));
+ StubCompiler::TailCallBuiltin(
+ masm, BaseLoadStoreStubCompiler::MissBuiltin(kind()));
}
// -----------------------------------
// Get the receiver from the stack and probe the stub cache.
- Code::Flags flags =
- Code::ComputeFlags(Code::STORE_IC, MONOMORPHIC, strict_mode);
+ Code::Flags flags = Code::ComputeFlags(
+ Code::STUB, MONOMORPHIC, strict_mode,
+ Code::NORMAL, Code::STORE_IC);
Isolate::Current()->stub_cache()->GenerateProbe(masm, flags, rdx, rcx, rbx,
no_reg);
}
-// Both name_reg and receiver_reg are preserved on jumps to miss_label,
-// but may be destroyed if store is successful.
-void StubCompiler::GenerateStoreTransition(MacroAssembler* masm,
- Handle<JSObject> object,
- LookupResult* lookup,
- Handle<Map> transition,
- Handle<Name> name,
- Register receiver_reg,
- Register name_reg,
- Register value_reg,
- Register scratch1,
- Register scratch2,
- Register unused,
- Label* miss_label,
- Label* miss_restore_name,
- Label* slow) {
- // Check that the map of the object hasn't changed.
- __ CheckMap(receiver_reg, Handle<Map>(object->map()),
- miss_label, DO_SMI_CHECK);
-
- // Perform global security token check if needed.
- if (object->IsJSGlobalProxy()) {
- __ CheckAccessGlobalProxy(receiver_reg, scratch1, miss_label);
- }
-
+void BaseStoreStubCompiler::GenerateNegativeHolderLookup(
+ MacroAssembler* masm,
+ Handle<JSObject> holder,
+ Register holder_reg,
+ Handle<Name> name,
+ Label* miss) {
+ if (holder->IsJSGlobalObject()) {
+ GenerateCheckPropertyCell(
+ masm, Handle<GlobalObject>::cast(holder), name, scratch1(), miss);
+ } else if (!holder->HasFastProperties() && !holder->IsJSGlobalProxy()) {
+ GenerateDictionaryNegativeLookup(
+ masm, miss, holder_reg, name, scratch1(), scratch2());
+ }
+}
+
+
+// Receiver_reg is preserved on jumps to miss_label, but may be destroyed if
+// store is successful.
+void BaseStoreStubCompiler::GenerateStoreTransition(MacroAssembler* masm,
+ Handle<JSObject> object,
+ LookupResult* lookup,
+ Handle<Map> transition,
+ Handle<Name> name,
+ Register receiver_reg,
+ Register storage_reg,
+ Register value_reg,
+ Register scratch1,
+ Register scratch2,
+ Register unused,
+ Label* miss_label,
+ Label* slow) {
int descriptor = transition->LastAdded();
DescriptorArray* descriptors = transition->instance_descriptors();
PropertyDetails details = descriptors->GetDetails(descriptor);
Representation representation = details.representation();
ASSERT(!representation.IsNone());
- // Ensure no transitions to deprecated maps are followed.
- __ CheckMapDeprecated(transition, scratch1, miss_label);
-
- // Check that we are allowed to write this.
- if (object->GetPrototype()->IsJSObject()) {
- JSObject* holder;
- // holder == object indicates that no property was found.
- if (lookup->holder() != *object) {
- holder = lookup->holder();
- } else {
- // Find the top object.
- holder = *object;
- do {
- holder = JSObject::cast(holder->GetPrototype());
- } while (holder->GetPrototype()->IsJSObject());
- }
- Register holder_reg = CheckPrototypes(
- object, receiver_reg, Handle<JSObject>(holder), name_reg,
- scratch1, scratch2, name, miss_restore_name, SKIP_RECEIVER);
- // If no property was found, and the holder (the last object in the
- // prototype chain) is in slow mode, we need to do a negative lookup on the
- // holder.
- if (lookup->holder() == *object) {
- if (holder->IsJSGlobalObject()) {
- GenerateCheckPropertyCell(
- masm,
- Handle<GlobalObject>(GlobalObject::cast(holder)),
- name,
- scratch1,
- miss_restore_name);
- } else if (!holder->HasFastProperties() && !holder->IsJSGlobalProxy()) {
- GenerateDictionaryNegativeLookup(
- masm, miss_restore_name, holder_reg, name, scratch1, scratch2);
- }
- }
- }
-
- Register storage_reg = name_reg;
-
if (details.type() == CONSTANT_FUNCTION) {
Handle<HeapObject> constant(
HeapObject::cast(descriptors->GetValue(descriptor)));
__ LoadHeapObject(scratch1, constant);
__ cmpq(value_reg, scratch1);
- __ j(not_equal, miss_restore_name);
+ __ j(not_equal, miss_label);
} else if (FLAG_track_fields && representation.IsSmi()) {
- __ JumpIfNotSmi(value_reg, miss_restore_name);
+ __ JumpIfNotSmi(value_reg, miss_label);
} else if (FLAG_track_heap_object_fields && representation.IsHeapObject()) {
- __ JumpIfSmi(value_reg, miss_restore_name);
+ __ JumpIfSmi(value_reg, miss_label);
} else if (FLAG_track_double_fields && representation.IsDouble()) {
Label do_store, heap_number;
__ AllocateHeapNumber(storage_reg, scratch1, slow);
__ bind(&heap_number);
__ CheckMap(value_reg, masm->isolate()->factory()->heap_number_map(),
- miss_restore_name, DONT_DO_SMI_CHECK);
+ miss_label, DONT_DO_SMI_CHECK);
__ movsd(xmm0, FieldOperand(value_reg, HeapNumber::kValueOffset));
__ bind(&do_store);
if (!FLAG_track_fields || !representation.IsSmi()) {
// Update the write barrier for the array address.
- // Pass the value being stored in the now unused name_reg.
if (!FLAG_track_double_fields || !representation.IsDouble()) {
- __ movq(name_reg, value_reg);
- } else {
- ASSERT(storage_reg.is(name_reg));
+ __ movq(storage_reg, value_reg);
}
__ RecordWriteField(
- receiver_reg, offset, name_reg, scratch1, kDontSaveFPRegs,
+ receiver_reg, offset, storage_reg, scratch1, kDontSaveFPRegs,
EMIT_REMEMBERED_SET, smi_check);
}
} else {
if (!FLAG_track_fields || !representation.IsSmi()) {
// Update the write barrier for the array address.
- // Pass the value being stored in the now unused name_reg.
if (!FLAG_track_double_fields || !representation.IsDouble()) {
- __ movq(name_reg, value_reg);
- } else {
- ASSERT(storage_reg.is(name_reg));
+ __ movq(storage_reg, value_reg);
}
__ RecordWriteField(
- scratch1, offset, name_reg, receiver_reg, kDontSaveFPRegs,
+ scratch1, offset, storage_reg, receiver_reg, kDontSaveFPRegs,
EMIT_REMEMBERED_SET, smi_check);
}
}
// Both name_reg and receiver_reg are preserved on jumps to miss_label,
// but may be destroyed if store is successful.
-void StubCompiler::GenerateStoreField(MacroAssembler* masm,
- Handle<JSObject> object,
- LookupResult* lookup,
- Register receiver_reg,
- Register name_reg,
- Register value_reg,
- Register scratch1,
- Register scratch2,
- Label* miss_label) {
- // Check that the map of the object hasn't changed.
- __ CheckMap(receiver_reg, Handle<Map>(object->map()),
- miss_label, DO_SMI_CHECK);
-
- // Perform global security token check if needed.
- if (object->IsJSGlobalProxy()) {
- __ CheckAccessGlobalProxy(receiver_reg, scratch1, miss_label);
- }
-
+void BaseStoreStubCompiler::GenerateStoreField(MacroAssembler* masm,
+ Handle<JSObject> object,
+ LookupResult* lookup,
+ Register receiver_reg,
+ Register name_reg,
+ Register value_reg,
+ Register scratch1,
+ Register scratch2,
+ Label* miss_label) {
// Stub never generated for non-global objects that require access
// checks.
ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
}
-void BaseLoadStubCompiler::HandlerFrontendFooter(Label* success,
+void BaseLoadStubCompiler::HandlerFrontendFooter(Handle<Name> name,
+ Label* success,
Label* miss) {
if (!miss->is_unused()) {
__ jmp(success);
}
+void BaseStoreStubCompiler::HandlerFrontendFooter(Handle<Name> name,
+ Label* success,
+ Label* miss) {
+ if (!miss->is_unused()) {
+ __ jmp(success);
+ GenerateRestoreName(masm(), miss, name);
+ TailCallBuiltin(masm(), MissBuiltin(kind()));
+ }
+}
+
+
Register BaseLoadStubCompiler::CallbackHandlerFrontend(
Handle<JSObject> object,
Register object_reg,
__ j(not_equal, &miss);
}
- HandlerFrontendFooter(success, &miss);
+ HandlerFrontendFooter(name, success, &miss);
return reg;
}
GenerateCheckPropertyCell(masm(), global, name, scratch2(), &miss);
}
- HandlerFrontendFooter(success, &miss);
+ HandlerFrontendFooter(name, success, &miss);
}
Handle<Code> StoreStubCompiler::CompileStoreCallback(
- Handle<Name> name,
Handle<JSObject> object,
Handle<JSObject> holder,
+ Handle<Name> name,
Handle<ExecutableAccessorInfo> callback) {
- Label miss;
- // Check that the maps haven't changed.
- __ JumpIfSmi(receiver(), &miss);
- CheckPrototypes(object, receiver(), holder,
- scratch1(), scratch2(), scratch3(), name, &miss);
-
- // Stub never generated for non-global objects that require access checks.
- ASSERT(holder->IsJSGlobalProxy() || !holder->IsAccessCheckNeeded());
+ Label success;
+ HandlerFrontend(object, receiver(), holder, name, &success);
+ __ bind(&success);
__ pop(scratch1()); // remove the return address
__ push(receiver());
__ Push(callback); // callback info
- __ push(this->name());
+ __ Push(name);
__ push(value());
__ push(scratch1()); // restore return address
ExternalReference(IC_Utility(IC::kStoreCallbackProperty), isolate());
__ TailCallExternalReference(store_callback_property, 4, 1);
- // Handle store cache miss.
- __ bind(&miss);
- TailCallBuiltin(masm(), MissBuiltin(kind()));
-
// Return the generated code.
- return GetICCode(kind(), Code::CALLBACKS, name);
+ return GetCode(kind(), Code::CALLBACKS, name);
}
Handle<Code> StoreStubCompiler::CompileStoreInterceptor(
Handle<JSObject> object,
Handle<Name> name) {
- Label miss;
-
- // Check that the map of the object hasn't changed.
- __ CheckMap(receiver(), Handle<Map>(object->map()), &miss, DO_SMI_CHECK);
-
- // Perform global security token check if needed.
- if (object->IsJSGlobalProxy()) {
- __ CheckAccessGlobalProxy(receiver(), scratch1(), &miss);
- }
-
- // Stub never generated for non-global objects that require access
- // checks.
- ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
-
__ pop(scratch1()); // remove the return address
__ push(receiver());
__ push(this->name());
ExternalReference(IC_Utility(IC::kStoreInterceptorProperty), isolate());
__ TailCallExternalReference(store_ic_property, 4, 1);
- // Handle store cache miss.
- __ bind(&miss);
- TailCallBuiltin(masm(), MissBuiltin(kind()));
-
// Return the generated code.
- return GetICCode(kind(), Code::INTERCEPTOR, name);
+ return GetCode(kind(), Code::INTERCEPTOR, name);
}
__ Check(not_equal, "DontDelete cells can't contain the hole");
}
- HandlerFrontendFooter(&success, &miss);
+ HandlerFrontendFooter(name, &success, &miss);
__ bind(&success);
Counters* counters = isolate()->counters();
}
-Handle<Code> BaseLoadStubCompiler::CompilePolymorphicIC(
+Handle<Code> BaseLoadStoreStubCompiler::CompilePolymorphicIC(
MapHandleList* receiver_maps,
CodeHandleList* handlers,
Handle<Name> name,