X64: Add StoreField inline cache stub.
Review URL: http://codereview.chromium.org/155915 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@2518 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
a109c08c78
commit
be562ee794
@ -212,7 +212,8 @@ class MacroAssembler: public Assembler {
|
|||||||
|
|
||||||
// Generate code for checking access rights - used for security checks
|
// Generate code for checking access rights - used for security checks
|
||||||
// on access to global objects across environments. The holder register
|
// on access to global objects across environments. The holder register
|
||||||
// is left untouched, but the scratch register is clobbered.
|
// is left untouched, but the scratch register and kScratchRegister,
|
||||||
|
// which must be different, are clobbered.
|
||||||
void CheckAccessGlobalProxy(Register holder_reg,
|
void CheckAccessGlobalProxy(Register holder_reg,
|
||||||
Register scratch,
|
Register scratch,
|
||||||
Label* miss);
|
Label* miss);
|
||||||
|
@ -427,12 +427,38 @@ Object* StoreStubCompiler::CompileStoreCallback(JSObject* a,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Object* StoreStubCompiler::CompileStoreField(JSObject* a,
|
Object* StoreStubCompiler::CompileStoreField(JSObject* object,
|
||||||
int b,
|
int index,
|
||||||
Map* c,
|
Map* transition,
|
||||||
String* d) {
|
String* name) {
|
||||||
UNIMPLEMENTED();
|
// ----------- S t a t e -------------
|
||||||
return NULL;
|
// -- rax : value
|
||||||
|
// -- rcx : name
|
||||||
|
// -- rsp[0] : return address
|
||||||
|
// -- rsp[8] : receiver
|
||||||
|
// -----------------------------------
|
||||||
|
Label miss;
|
||||||
|
|
||||||
|
// Get the object from the stack.
|
||||||
|
__ movq(rbx, Operand(rsp, 1 * kPointerSize));
|
||||||
|
|
||||||
|
// Generate store field code. Trashes the name register.
|
||||||
|
GenerateStoreField(masm(),
|
||||||
|
Builtins::StoreIC_ExtendStorage,
|
||||||
|
object,
|
||||||
|
index,
|
||||||
|
transition,
|
||||||
|
rbx, rcx, rdx,
|
||||||
|
&miss);
|
||||||
|
|
||||||
|
// Handle store cache miss.
|
||||||
|
__ bind(&miss);
|
||||||
|
__ Move(rcx, Handle<String>(name)); // restore name
|
||||||
|
Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss));
|
||||||
|
__ Jump(ic, RelocInfo::CODE_TARGET);
|
||||||
|
|
||||||
|
// Return the generated code.
|
||||||
|
return GetCode(transition == NULL ? FIELD : MAP_TRANSITION, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -699,6 +725,82 @@ void StubCache::GenerateProbe(MacroAssembler* masm,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void StubCompiler::GenerateStoreField(MacroAssembler* masm,
|
||||||
|
Builtins::Name storage_extend,
|
||||||
|
JSObject* object,
|
||||||
|
int index,
|
||||||
|
Map* transition,
|
||||||
|
Register receiver_reg,
|
||||||
|
Register name_reg,
|
||||||
|
Register scratch,
|
||||||
|
Label* miss_label) {
|
||||||
|
// Check that the object isn't a smi.
|
||||||
|
__ testl(receiver_reg, Immediate(kSmiTagMask));
|
||||||
|
__ j(zero, miss_label);
|
||||||
|
|
||||||
|
// Check that the map of the object hasn't changed.
|
||||||
|
__ Cmp(FieldOperand(receiver_reg, HeapObject::kMapOffset),
|
||||||
|
Handle<Map>(object->map()));
|
||||||
|
__ j(not_equal, miss_label);
|
||||||
|
|
||||||
|
// Perform global security token check if needed.
|
||||||
|
if (object->IsJSGlobalProxy()) {
|
||||||
|
__ CheckAccessGlobalProxy(receiver_reg, scratch, miss_label);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stub never generated for non-global objects that require access
|
||||||
|
// checks.
|
||||||
|
ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded());
|
||||||
|
|
||||||
|
// Perform map transition for the receiver if necessary.
|
||||||
|
if ((transition != NULL) && (object->map()->unused_property_fields() == 0)) {
|
||||||
|
// The properties must be extended before we can store the value.
|
||||||
|
// We jump to a runtime call that extends the properties array.
|
||||||
|
__ Move(rcx, Handle<Map>(transition));
|
||||||
|
Handle<Code> ic(Builtins::builtin(storage_extend));
|
||||||
|
__ Jump(ic, RelocInfo::CODE_TARGET);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (transition != NULL) {
|
||||||
|
// Update the map of the object; no write barrier updating is
|
||||||
|
// needed because the map is never in new space.
|
||||||
|
__ Move(FieldOperand(receiver_reg, HeapObject::kMapOffset),
|
||||||
|
Handle<Map>(transition));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Adjust for the number of properties stored in the object. Even in the
|
||||||
|
// face of a transition we can use the old map here because the size of the
|
||||||
|
// object and the number of in-object properties is not going to change.
|
||||||
|
index -= object->map()->inobject_properties();
|
||||||
|
|
||||||
|
if (index < 0) {
|
||||||
|
// Set the property straight into the object.
|
||||||
|
int offset = object->map()->instance_size() + (index * kPointerSize);
|
||||||
|
__ movq(FieldOperand(receiver_reg, offset), rax);
|
||||||
|
|
||||||
|
// Update the write barrier for the array address.
|
||||||
|
// Pass the value being stored in the now unused name_reg.
|
||||||
|
__ movq(name_reg, rax);
|
||||||
|
__ RecordWrite(receiver_reg, offset, name_reg, scratch);
|
||||||
|
} else {
|
||||||
|
// Write to the properties array.
|
||||||
|
int offset = index * kPointerSize + FixedArray::kHeaderSize;
|
||||||
|
// Get the properties array (optimistically).
|
||||||
|
__ movq(scratch, FieldOperand(receiver_reg, JSObject::kPropertiesOffset));
|
||||||
|
__ movq(FieldOperand(scratch, offset), rax);
|
||||||
|
|
||||||
|
// Update the write barrier for the array address.
|
||||||
|
// Pass the value being stored in the now unused name_reg.
|
||||||
|
__ movq(name_reg, rax);
|
||||||
|
__ RecordWrite(scratch, offset, name_reg, receiver_reg);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the value (register rax).
|
||||||
|
__ ret(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#undef __
|
#undef __
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user