Change LoadIC interface on ia32 to take arguments in registers.
Review URL: http://codereview.chromium.org/573009 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@3841 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
85c24cee57
commit
c7fe99d3ff
@ -1050,7 +1050,13 @@ void FullCodeGenerator::VisitAssignment(Assignment* expr) {
|
|||||||
// Nothing to do here.
|
// Nothing to do here.
|
||||||
break;
|
break;
|
||||||
case NAMED_PROPERTY:
|
case NAMED_PROPERTY:
|
||||||
VisitForValue(prop->obj(), kStack);
|
if (expr->is_compound()) {
|
||||||
|
// We need the receiver both on the stack and in the accumulator.
|
||||||
|
VisitForValue(prop->obj(), kAccumulator);
|
||||||
|
__ push(result_register());
|
||||||
|
} else {
|
||||||
|
VisitForValue(prop->obj(), kStack);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case KEYED_PROPERTY:
|
case KEYED_PROPERTY:
|
||||||
VisitForValue(prop->obj(), kStack);
|
VisitForValue(prop->obj(), kStack);
|
||||||
|
@ -2327,6 +2327,7 @@ void CodeGenerator::CallApplyLazy(Expression* applicand,
|
|||||||
// Load applicand.apply onto the stack. This will usually
|
// Load applicand.apply onto the stack. This will usually
|
||||||
// give us a megamorphic load site. Not super, but it works.
|
// give us a megamorphic load site. Not super, but it works.
|
||||||
Load(applicand);
|
Load(applicand);
|
||||||
|
frame()->Dup();
|
||||||
Handle<String> name = Factory::LookupAsciiSymbol("apply");
|
Handle<String> name = Factory::LookupAsciiSymbol("apply");
|
||||||
frame()->Push(name);
|
frame()->Push(name);
|
||||||
Result answer = frame()->CallLoadIC(RelocInfo::CODE_TARGET);
|
Result answer = frame()->CallLoadIC(RelocInfo::CODE_TARGET);
|
||||||
@ -4197,8 +4198,6 @@ Result CodeGenerator::LoadFromGlobalSlotCheckExtensions(
|
|||||||
// property case was inlined. Ensure that there is not a test eax
|
// property case was inlined. Ensure that there is not a test eax
|
||||||
// instruction here.
|
// instruction here.
|
||||||
__ nop();
|
__ nop();
|
||||||
// Discard the global object. The result is in answer.
|
|
||||||
frame_->Drop();
|
|
||||||
return answer;
|
return answer;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -6276,7 +6275,7 @@ bool CodeGenerator::HasValidEntryRegisters() {
|
|||||||
|
|
||||||
|
|
||||||
// Emit a LoadIC call to get the value from receiver and leave it in
|
// Emit a LoadIC call to get the value from receiver and leave it in
|
||||||
// dst. The receiver register is restored after the call.
|
// dst.
|
||||||
class DeferredReferenceGetNamedValue: public DeferredCode {
|
class DeferredReferenceGetNamedValue: public DeferredCode {
|
||||||
public:
|
public:
|
||||||
DeferredReferenceGetNamedValue(Register dst,
|
DeferredReferenceGetNamedValue(Register dst,
|
||||||
@ -6299,7 +6298,9 @@ class DeferredReferenceGetNamedValue: public DeferredCode {
|
|||||||
|
|
||||||
|
|
||||||
void DeferredReferenceGetNamedValue::Generate() {
|
void DeferredReferenceGetNamedValue::Generate() {
|
||||||
__ push(receiver_);
|
if (!receiver_.is(eax)) {
|
||||||
|
__ mov(eax, receiver_);
|
||||||
|
}
|
||||||
__ Set(ecx, Immediate(name_));
|
__ Set(ecx, Immediate(name_));
|
||||||
Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
|
Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
|
||||||
__ call(ic, RelocInfo::CODE_TARGET);
|
__ call(ic, RelocInfo::CODE_TARGET);
|
||||||
@ -6316,7 +6317,6 @@ void DeferredReferenceGetNamedValue::Generate() {
|
|||||||
__ IncrementCounter(&Counters::named_load_inline_miss, 1);
|
__ IncrementCounter(&Counters::named_load_inline_miss, 1);
|
||||||
|
|
||||||
if (!dst_.is(eax)) __ mov(dst_, eax);
|
if (!dst_.is(eax)) __ mov(dst_, eax);
|
||||||
__ pop(receiver_);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -6570,6 +6570,9 @@ void Reference::GetValue() {
|
|||||||
Slot* slot = expression_->AsVariableProxy()->AsVariable()->slot();
|
Slot* slot = expression_->AsVariableProxy()->AsVariable()->slot();
|
||||||
ASSERT(slot != NULL);
|
ASSERT(slot != NULL);
|
||||||
cgen_->LoadFromSlotCheckForArguments(slot, NOT_INSIDE_TYPEOF);
|
cgen_->LoadFromSlotCheckForArguments(slot, NOT_INSIDE_TYPEOF);
|
||||||
|
if (!persist_after_get_) {
|
||||||
|
cgen_->UnloadReference(this);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -6578,6 +6581,9 @@ void Reference::GetValue() {
|
|||||||
bool is_global = var != NULL;
|
bool is_global = var != NULL;
|
||||||
ASSERT(!is_global || var->is_global());
|
ASSERT(!is_global || var->is_global());
|
||||||
|
|
||||||
|
if (persist_after_get_) {
|
||||||
|
cgen_->frame()->Dup();
|
||||||
|
}
|
||||||
// Do not inline the inobject property case for loads from the global
|
// Do not inline the inobject property case for loads from the global
|
||||||
// object. Also do not inline for unoptimized code. This saves time
|
// object. Also do not inline for unoptimized code. This saves time
|
||||||
// in the code generator. Unoptimized code is toplevel code or code
|
// in the code generator. Unoptimized code is toplevel code or code
|
||||||
@ -6636,9 +6642,11 @@ void Reference::GetValue() {
|
|||||||
|
|
||||||
__ IncrementCounter(&Counters::named_load_inline, 1);
|
__ IncrementCounter(&Counters::named_load_inline, 1);
|
||||||
deferred->BindExit();
|
deferred->BindExit();
|
||||||
cgen_->frame()->Push(&receiver);
|
|
||||||
cgen_->frame()->Push(&value);
|
cgen_->frame()->Push(&value);
|
||||||
}
|
}
|
||||||
|
if (!persist_after_get_) {
|
||||||
|
set_unloaded();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -6648,16 +6656,15 @@ void Reference::GetValue() {
|
|||||||
ASSERT(!is_global || var->is_global());
|
ASSERT(!is_global || var->is_global());
|
||||||
Result value = cgen_->EmitKeyedLoad(is_global);
|
Result value = cgen_->EmitKeyedLoad(is_global);
|
||||||
cgen_->frame()->Push(&value);
|
cgen_->frame()->Push(&value);
|
||||||
|
if (!persist_after_get_) {
|
||||||
|
cgen_->UnloadReference(this);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!persist_after_get_) {
|
|
||||||
cgen_->UnloadReference(this);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -125,9 +125,10 @@ static void Generate_DebugBreakCallHelper(MacroAssembler* masm,
|
|||||||
void Debug::GenerateLoadICDebugBreak(MacroAssembler* masm) {
|
void Debug::GenerateLoadICDebugBreak(MacroAssembler* masm) {
|
||||||
// Register state for IC load call (from ic-ia32.cc).
|
// Register state for IC load call (from ic-ia32.cc).
|
||||||
// ----------- S t a t e -------------
|
// ----------- S t a t e -------------
|
||||||
|
// -- eax : receiver
|
||||||
// -- ecx : name
|
// -- ecx : name
|
||||||
// -----------------------------------
|
// -----------------------------------
|
||||||
Generate_DebugBreakCallHelper(masm, ecx.bit(), false);
|
Generate_DebugBreakCallHelper(masm, eax.bit() | ecx.bit(), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -808,7 +808,7 @@ void FullCodeGenerator::EmitVariableLoad(Variable* var,
|
|||||||
Comment cmnt(masm_, "Global variable");
|
Comment cmnt(masm_, "Global variable");
|
||||||
// Use inline caching. Variable name is passed in ecx and the global
|
// Use inline caching. Variable name is passed in ecx and the global
|
||||||
// object on the stack.
|
// object on the stack.
|
||||||
__ push(CodeGenerator::GlobalObject());
|
__ mov(eax, CodeGenerator::GlobalObject());
|
||||||
__ mov(ecx, var->name());
|
__ mov(ecx, var->name());
|
||||||
Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
|
Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
|
||||||
__ call(ic, RelocInfo::CODE_TARGET_CONTEXT);
|
__ call(ic, RelocInfo::CODE_TARGET_CONTEXT);
|
||||||
@ -817,7 +817,7 @@ void FullCodeGenerator::EmitVariableLoad(Variable* var,
|
|||||||
// Remember that the assembler may choose to do peephole optimization
|
// Remember that the assembler may choose to do peephole optimization
|
||||||
// (eg, push/pop elimination).
|
// (eg, push/pop elimination).
|
||||||
__ nop();
|
__ nop();
|
||||||
DropAndApply(1, context, eax);
|
Apply(context, eax);
|
||||||
|
|
||||||
} else if (slot != NULL && slot->type() == Slot::LOOKUP) {
|
} else if (slot != NULL && slot->type() == Slot::LOOKUP) {
|
||||||
Comment cmnt(masm_, "Lookup slot");
|
Comment cmnt(masm_, "Lookup slot");
|
||||||
@ -1183,14 +1183,12 @@ void FullCodeGenerator::VisitProperty(Property* expr) {
|
|||||||
Comment cmnt(masm_, "[ Property");
|
Comment cmnt(masm_, "[ Property");
|
||||||
Expression* key = expr->key();
|
Expression* key = expr->key();
|
||||||
|
|
||||||
// Evaluate the receiver.
|
|
||||||
VisitForValue(expr->obj(), kStack);
|
|
||||||
|
|
||||||
if (key->IsPropertyName()) {
|
if (key->IsPropertyName()) {
|
||||||
|
VisitForValue(expr->obj(), kAccumulator);
|
||||||
EmitNamedPropertyLoad(expr);
|
EmitNamedPropertyLoad(expr);
|
||||||
// Drop receiver left on the stack by IC.
|
Apply(context_, eax);
|
||||||
DropAndApply(1, context_, eax);
|
|
||||||
} else {
|
} else {
|
||||||
|
VisitForValue(expr->obj(), kStack);
|
||||||
VisitForValue(expr->key(), kStack);
|
VisitForValue(expr->key(), kStack);
|
||||||
EmitKeyedPropertyLoad(expr);
|
EmitKeyedPropertyLoad(expr);
|
||||||
// Drop key and receiver left on the stack by IC.
|
// Drop key and receiver left on the stack by IC.
|
||||||
@ -1455,13 +1453,13 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
|
|||||||
!proxy->var()->is_this() &&
|
!proxy->var()->is_this() &&
|
||||||
proxy->var()->is_global()) {
|
proxy->var()->is_global()) {
|
||||||
Comment cmnt(masm_, "Global variable");
|
Comment cmnt(masm_, "Global variable");
|
||||||
__ push(CodeGenerator::GlobalObject());
|
__ mov(eax, CodeGenerator::GlobalObject());
|
||||||
__ mov(ecx, Immediate(proxy->name()));
|
__ mov(ecx, Immediate(proxy->name()));
|
||||||
Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
|
Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
|
||||||
// Use a regular load, not a contextual load, to avoid a reference
|
// Use a regular load, not a contextual load, to avoid a reference
|
||||||
// error.
|
// error.
|
||||||
__ call(ic, RelocInfo::CODE_TARGET);
|
__ call(ic, RelocInfo::CODE_TARGET);
|
||||||
__ mov(Operand(esp, 0), eax);
|
__ push(eax);
|
||||||
} else if (proxy != NULL &&
|
} else if (proxy != NULL &&
|
||||||
proxy->var()->slot() != NULL &&
|
proxy->var()->slot() != NULL &&
|
||||||
proxy->var()->slot()->type() == Slot::LOOKUP) {
|
proxy->var()->slot()->type() == Slot::LOOKUP) {
|
||||||
@ -1565,10 +1563,13 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
|
|||||||
if (expr->is_postfix() && context_ != Expression::kEffect) {
|
if (expr->is_postfix() && context_ != Expression::kEffect) {
|
||||||
__ push(Immediate(Smi::FromInt(0)));
|
__ push(Immediate(Smi::FromInt(0)));
|
||||||
}
|
}
|
||||||
VisitForValue(prop->obj(), kStack);
|
|
||||||
if (assign_type == NAMED_PROPERTY) {
|
if (assign_type == NAMED_PROPERTY) {
|
||||||
|
// Put the object both on the stack and in the accumulator.
|
||||||
|
VisitForValue(prop->obj(), kAccumulator);
|
||||||
|
__ push(eax);
|
||||||
EmitNamedPropertyLoad(prop);
|
EmitNamedPropertyLoad(prop);
|
||||||
} else {
|
} else {
|
||||||
|
VisitForValue(prop->obj(), kStack);
|
||||||
VisitForValue(prop->key(), kStack);
|
VisitForValue(prop->key(), kStack);
|
||||||
EmitKeyedPropertyLoad(prop);
|
EmitKeyedPropertyLoad(prop);
|
||||||
}
|
}
|
||||||
|
@ -50,28 +50,29 @@ namespace internal {
|
|||||||
// or if name is not a symbol, and will jump to the miss_label in that case.
|
// or if name is not a symbol, and will jump to the miss_label in that case.
|
||||||
static void GenerateDictionaryLoad(MacroAssembler* masm,
|
static void GenerateDictionaryLoad(MacroAssembler* masm,
|
||||||
Label* miss_label,
|
Label* miss_label,
|
||||||
|
Register receiver,
|
||||||
|
Register name,
|
||||||
Register r0,
|
Register r0,
|
||||||
Register r1,
|
Register r1,
|
||||||
Register r2,
|
Register r2,
|
||||||
Register name,
|
|
||||||
DictionaryCheck check_dictionary) {
|
DictionaryCheck check_dictionary) {
|
||||||
// Register use:
|
// Register use:
|
||||||
//
|
//
|
||||||
|
// name - holds the name of the property and is unchanged.
|
||||||
|
// receiver - holds the receiver and is unchanged.
|
||||||
|
// Scratch registers:
|
||||||
// r0 - used to hold the property dictionary.
|
// r0 - used to hold the property dictionary.
|
||||||
//
|
//
|
||||||
// r1 - initially the receiver
|
// r1 - used for the index into the property dictionary
|
||||||
// - used for the index into the property dictionary
|
|
||||||
// - holds the result on exit.
|
// - holds the result on exit.
|
||||||
//
|
//
|
||||||
// r2 - used to hold the capacity of the property dictionary.
|
// r2 - used to hold the capacity of the property dictionary.
|
||||||
//
|
|
||||||
// name - holds the name of the property and is unchanged.
|
|
||||||
|
|
||||||
Label done;
|
Label done;
|
||||||
|
|
||||||
// Check for the absence of an interceptor.
|
// Check for the absence of an interceptor.
|
||||||
// Load the map into r0.
|
// Load the map into r0.
|
||||||
__ mov(r0, FieldOperand(r1, JSObject::kMapOffset));
|
__ mov(r0, FieldOperand(receiver, JSObject::kMapOffset));
|
||||||
// Test the has_named_interceptor bit in the map.
|
// Test the has_named_interceptor bit in the map.
|
||||||
__ test(FieldOperand(r0, Map::kInstanceAttributesOffset),
|
__ test(FieldOperand(r0, Map::kInstanceAttributesOffset),
|
||||||
Immediate(1 << (Map::kHasNamedInterceptor + (3 * 8))));
|
Immediate(1 << (Map::kHasNamedInterceptor + (3 * 8))));
|
||||||
@ -91,7 +92,7 @@ static void GenerateDictionaryLoad(MacroAssembler* masm,
|
|||||||
__ j(equal, miss_label, not_taken);
|
__ j(equal, miss_label, not_taken);
|
||||||
|
|
||||||
// Load properties array.
|
// Load properties array.
|
||||||
__ mov(r0, FieldOperand(r1, JSObject::kPropertiesOffset));
|
__ mov(r0, FieldOperand(receiver, JSObject::kPropertiesOffset));
|
||||||
|
|
||||||
// Check that the properties array is a dictionary.
|
// Check that the properties array is a dictionary.
|
||||||
if (check_dictionary == CHECK_DICTIONARY) {
|
if (check_dictionary == CHECK_DICTIONARY) {
|
||||||
@ -176,14 +177,12 @@ const int LoadIC::kOffsetToLoadInstruction = 13;
|
|||||||
|
|
||||||
void LoadIC::GenerateArrayLength(MacroAssembler* masm) {
|
void LoadIC::GenerateArrayLength(MacroAssembler* masm) {
|
||||||
// ----------- S t a t e -------------
|
// ----------- S t a t e -------------
|
||||||
|
// -- eax : receiver
|
||||||
// -- ecx : name
|
// -- ecx : name
|
||||||
// -- esp[0] : return address
|
// -- esp[0] : return address
|
||||||
// -- esp[4] : receiver
|
|
||||||
// -----------------------------------
|
// -----------------------------------
|
||||||
Label miss;
|
Label miss;
|
||||||
|
|
||||||
__ mov(eax, Operand(esp, kPointerSize));
|
|
||||||
|
|
||||||
StubCompiler::GenerateLoadArrayLength(masm, eax, edx, &miss);
|
StubCompiler::GenerateLoadArrayLength(masm, eax, edx, &miss);
|
||||||
__ bind(&miss);
|
__ bind(&miss);
|
||||||
StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
|
StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
|
||||||
@ -192,14 +191,12 @@ void LoadIC::GenerateArrayLength(MacroAssembler* masm) {
|
|||||||
|
|
||||||
void LoadIC::GenerateStringLength(MacroAssembler* masm) {
|
void LoadIC::GenerateStringLength(MacroAssembler* masm) {
|
||||||
// ----------- S t a t e -------------
|
// ----------- S t a t e -------------
|
||||||
|
// -- eax : receiver
|
||||||
// -- ecx : name
|
// -- ecx : name
|
||||||
// -- esp[0] : return address
|
// -- esp[0] : return address
|
||||||
// -- esp[4] : receiver
|
|
||||||
// -----------------------------------
|
// -----------------------------------
|
||||||
Label miss;
|
Label miss;
|
||||||
|
|
||||||
__ mov(eax, Operand(esp, kPointerSize));
|
|
||||||
|
|
||||||
StubCompiler::GenerateLoadStringLength(masm, eax, edx, ebx, &miss);
|
StubCompiler::GenerateLoadStringLength(masm, eax, edx, ebx, &miss);
|
||||||
__ bind(&miss);
|
__ bind(&miss);
|
||||||
StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
|
StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
|
||||||
@ -208,14 +205,12 @@ void LoadIC::GenerateStringLength(MacroAssembler* masm) {
|
|||||||
|
|
||||||
void LoadIC::GenerateFunctionPrototype(MacroAssembler* masm) {
|
void LoadIC::GenerateFunctionPrototype(MacroAssembler* masm) {
|
||||||
// ----------- S t a t e -------------
|
// ----------- S t a t e -------------
|
||||||
|
// -- eax : receiver
|
||||||
// -- ecx : name
|
// -- ecx : name
|
||||||
// -- esp[0] : return address
|
// -- esp[0] : return address
|
||||||
// -- esp[4] : receiver
|
|
||||||
// -----------------------------------
|
// -----------------------------------
|
||||||
Label miss;
|
Label miss;
|
||||||
|
|
||||||
__ mov(eax, Operand(esp, kPointerSize));
|
|
||||||
|
|
||||||
StubCompiler::GenerateLoadFunctionPrototype(masm, eax, edx, ebx, &miss);
|
StubCompiler::GenerateLoadFunctionPrototype(masm, eax, edx, ebx, &miss);
|
||||||
__ bind(&miss);
|
__ bind(&miss);
|
||||||
StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
|
StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC);
|
||||||
@ -364,13 +359,14 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
|
|||||||
__ bind(&probe_dictionary);
|
__ bind(&probe_dictionary);
|
||||||
GenerateDictionaryLoad(masm,
|
GenerateDictionaryLoad(masm,
|
||||||
&slow,
|
&slow,
|
||||||
ebx,
|
|
||||||
ecx,
|
ecx,
|
||||||
edx,
|
|
||||||
eax,
|
eax,
|
||||||
|
ebx,
|
||||||
|
edx,
|
||||||
|
edi,
|
||||||
DICTIONARY_CHECK_DONE);
|
DICTIONARY_CHECK_DONE);
|
||||||
GenerateCheckNonObjectOrLoaded(masm, &slow, ecx, edx);
|
GenerateCheckNonObjectOrLoaded(masm, &slow, edx, ebx);
|
||||||
__ mov(eax, Operand(ecx));
|
__ mov(eax, Operand(edx));
|
||||||
__ IncrementCounter(&Counters::keyed_load_generic_symbol, 1);
|
__ IncrementCounter(&Counters::keyed_load_generic_symbol, 1);
|
||||||
__ ret(0);
|
__ ret(0);
|
||||||
|
|
||||||
@ -1001,7 +997,7 @@ static void GenerateNormalHelper(MacroAssembler* masm,
|
|||||||
|
|
||||||
// Search dictionary - put result in register edi.
|
// Search dictionary - put result in register edi.
|
||||||
__ mov(edi, edx);
|
__ mov(edi, edx);
|
||||||
GenerateDictionaryLoad(masm, miss, eax, edi, ebx, ecx, CHECK_DICTIONARY);
|
GenerateDictionaryLoad(masm, miss, edx, ecx, eax, edi, ebx, CHECK_DICTIONARY);
|
||||||
|
|
||||||
// Check that the result is not a smi.
|
// Check that the result is not a smi.
|
||||||
__ test(edi, Immediate(kSmiTagMask));
|
__ test(edi, Immediate(kSmiTagMask));
|
||||||
@ -1150,13 +1146,11 @@ Object* LoadIC_Miss(Arguments args);
|
|||||||
|
|
||||||
void LoadIC::GenerateMegamorphic(MacroAssembler* masm) {
|
void LoadIC::GenerateMegamorphic(MacroAssembler* masm) {
|
||||||
// ----------- S t a t e -------------
|
// ----------- S t a t e -------------
|
||||||
|
// -- eax : receiver
|
||||||
// -- ecx : name
|
// -- ecx : name
|
||||||
// -- esp[0] : return address
|
// -- esp[0] : return address
|
||||||
// -- esp[4] : receiver
|
|
||||||
// -----------------------------------
|
// -----------------------------------
|
||||||
|
|
||||||
__ mov(eax, Operand(esp, kPointerSize));
|
|
||||||
|
|
||||||
// Probe the stub cache.
|
// Probe the stub cache.
|
||||||
Code::Flags flags = Code::ComputeFlags(Code::LOAD_IC,
|
Code::Flags flags = Code::ComputeFlags(Code::LOAD_IC,
|
||||||
NOT_IN_LOOP,
|
NOT_IN_LOOP,
|
||||||
@ -1170,14 +1164,12 @@ void LoadIC::GenerateMegamorphic(MacroAssembler* masm) {
|
|||||||
|
|
||||||
void LoadIC::GenerateNormal(MacroAssembler* masm) {
|
void LoadIC::GenerateNormal(MacroAssembler* masm) {
|
||||||
// ----------- S t a t e -------------
|
// ----------- S t a t e -------------
|
||||||
|
// -- eax : receiver
|
||||||
// -- ecx : name
|
// -- ecx : name
|
||||||
// -- esp[0] : return address
|
// -- esp[0] : return address
|
||||||
// -- esp[4] : receiver
|
|
||||||
// -----------------------------------
|
// -----------------------------------
|
||||||
Label miss, probe, global;
|
Label miss, probe, global;
|
||||||
|
|
||||||
__ mov(eax, Operand(esp, kPointerSize));
|
|
||||||
|
|
||||||
// Check that the receiver isn't a smi.
|
// Check that the receiver isn't a smi.
|
||||||
__ test(eax, Immediate(kSmiTagMask));
|
__ test(eax, Immediate(kSmiTagMask));
|
||||||
__ j(zero, &miss, not_taken);
|
__ j(zero, &miss, not_taken);
|
||||||
@ -1202,8 +1194,16 @@ void LoadIC::GenerateNormal(MacroAssembler* masm) {
|
|||||||
|
|
||||||
// Search the dictionary placing the result in eax.
|
// Search the dictionary placing the result in eax.
|
||||||
__ bind(&probe);
|
__ bind(&probe);
|
||||||
GenerateDictionaryLoad(masm, &miss, edx, eax, ebx, ecx, CHECK_DICTIONARY);
|
GenerateDictionaryLoad(masm,
|
||||||
GenerateCheckNonObjectOrLoaded(masm, &miss, eax, edx);
|
&miss,
|
||||||
|
eax,
|
||||||
|
ecx,
|
||||||
|
edx,
|
||||||
|
edi,
|
||||||
|
ebx,
|
||||||
|
CHECK_DICTIONARY);
|
||||||
|
GenerateCheckNonObjectOrLoaded(masm, &miss, edi, edx);
|
||||||
|
__ mov(eax, edi);
|
||||||
__ ret(0);
|
__ ret(0);
|
||||||
|
|
||||||
// Global object access: Check access rights.
|
// Global object access: Check access rights.
|
||||||
@ -1213,20 +1213,19 @@ void LoadIC::GenerateNormal(MacroAssembler* masm) {
|
|||||||
|
|
||||||
// Cache miss: Restore receiver from stack and jump to runtime.
|
// Cache miss: Restore receiver from stack and jump to runtime.
|
||||||
__ bind(&miss);
|
__ bind(&miss);
|
||||||
__ mov(eax, Operand(esp, 1 * kPointerSize));
|
|
||||||
GenerateMiss(masm);
|
GenerateMiss(masm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void LoadIC::GenerateMiss(MacroAssembler* masm) {
|
void LoadIC::GenerateMiss(MacroAssembler* masm) {
|
||||||
// ----------- S t a t e -------------
|
// ----------- S t a t e -------------
|
||||||
|
// -- eax : receiver
|
||||||
// -- ecx : name
|
// -- ecx : name
|
||||||
// -- esp[0] : return address
|
// -- esp[0] : return address
|
||||||
// -- esp[4] : receiver
|
|
||||||
// -----------------------------------
|
// -----------------------------------
|
||||||
|
|
||||||
__ pop(ebx);
|
__ pop(ebx);
|
||||||
__ push(Operand(esp, 0)); // receiver
|
__ push(eax); // receiver
|
||||||
__ push(ecx); // name
|
__ push(ecx); // name
|
||||||
__ push(ebx); // return address
|
__ push(ebx); // return address
|
||||||
|
|
||||||
|
@ -1767,13 +1767,12 @@ Object* LoadStubCompiler::CompileLoadField(JSObject* object,
|
|||||||
int index,
|
int index,
|
||||||
String* name) {
|
String* name) {
|
||||||
// ----------- S t a t e -------------
|
// ----------- S t a t e -------------
|
||||||
|
// -- eax : receiver
|
||||||
// -- ecx : name
|
// -- ecx : name
|
||||||
// -- esp[0] : return address
|
// -- esp[0] : return address
|
||||||
// -- esp[4] : receiver
|
|
||||||
// -----------------------------------
|
// -----------------------------------
|
||||||
Label miss;
|
Label miss;
|
||||||
|
|
||||||
__ mov(eax, Operand(esp, kPointerSize));
|
|
||||||
GenerateLoadField(object, holder, eax, ebx, edx, index, name, &miss);
|
GenerateLoadField(object, holder, eax, ebx, edx, index, name, &miss);
|
||||||
__ bind(&miss);
|
__ bind(&miss);
|
||||||
GenerateLoadMiss(masm(), Code::LOAD_IC);
|
GenerateLoadMiss(masm(), Code::LOAD_IC);
|
||||||
@ -1788,13 +1787,12 @@ Object* LoadStubCompiler::CompileLoadCallback(String* name,
|
|||||||
JSObject* holder,
|
JSObject* holder,
|
||||||
AccessorInfo* callback) {
|
AccessorInfo* callback) {
|
||||||
// ----------- S t a t e -------------
|
// ----------- S t a t e -------------
|
||||||
|
// -- eax : receiver
|
||||||
// -- ecx : name
|
// -- ecx : name
|
||||||
// -- esp[0] : return address
|
// -- esp[0] : return address
|
||||||
// -- esp[4] : receiver
|
|
||||||
// -----------------------------------
|
// -----------------------------------
|
||||||
Label miss;
|
Label miss;
|
||||||
|
|
||||||
__ mov(eax, Operand(esp, kPointerSize));
|
|
||||||
Failure* failure = Failure::InternalError();
|
Failure* failure = Failure::InternalError();
|
||||||
bool success = GenerateLoadCallback(object, holder, eax, ecx, ebx, edx,
|
bool success = GenerateLoadCallback(object, holder, eax, ecx, ebx, edx,
|
||||||
callback, name, &miss, &failure);
|
callback, name, &miss, &failure);
|
||||||
@ -1813,13 +1811,12 @@ Object* LoadStubCompiler::CompileLoadConstant(JSObject* object,
|
|||||||
Object* value,
|
Object* value,
|
||||||
String* name) {
|
String* name) {
|
||||||
// ----------- S t a t e -------------
|
// ----------- S t a t e -------------
|
||||||
|
// -- eax : receiver
|
||||||
// -- ecx : name
|
// -- ecx : name
|
||||||
// -- esp[0] : return address
|
// -- esp[0] : return address
|
||||||
// -- esp[4] : receiver
|
|
||||||
// -----------------------------------
|
// -----------------------------------
|
||||||
Label miss;
|
Label miss;
|
||||||
|
|
||||||
__ mov(eax, Operand(esp, kPointerSize));
|
|
||||||
GenerateLoadConstant(object, holder, eax, ebx, edx, value, name, &miss);
|
GenerateLoadConstant(object, holder, eax, ebx, edx, value, name, &miss);
|
||||||
__ bind(&miss);
|
__ bind(&miss);
|
||||||
GenerateLoadMiss(masm(), Code::LOAD_IC);
|
GenerateLoadMiss(masm(), Code::LOAD_IC);
|
||||||
@ -1833,16 +1830,15 @@ Object* LoadStubCompiler::CompileLoadInterceptor(JSObject* receiver,
|
|||||||
JSObject* holder,
|
JSObject* holder,
|
||||||
String* name) {
|
String* name) {
|
||||||
// ----------- S t a t e -------------
|
// ----------- S t a t e -------------
|
||||||
|
// -- eax : receiver
|
||||||
// -- ecx : name
|
// -- ecx : name
|
||||||
// -- esp[0] : return address
|
// -- esp[0] : return address
|
||||||
// -- esp[4] : receiver
|
|
||||||
// -----------------------------------
|
// -----------------------------------
|
||||||
Label miss;
|
Label miss;
|
||||||
|
|
||||||
LookupResult lookup;
|
LookupResult lookup;
|
||||||
LookupPostInterceptor(holder, name, &lookup);
|
LookupPostInterceptor(holder, name, &lookup);
|
||||||
|
|
||||||
__ mov(eax, Operand(esp, kPointerSize));
|
|
||||||
// TODO(368): Compile in the whole chain: all the interceptors in
|
// TODO(368): Compile in the whole chain: all the interceptors in
|
||||||
// prototypes and ultimate answer.
|
// prototypes and ultimate answer.
|
||||||
GenerateLoadInterceptor(receiver,
|
GenerateLoadInterceptor(receiver,
|
||||||
@ -1869,15 +1865,12 @@ Object* LoadStubCompiler::CompileLoadGlobal(JSObject* object,
|
|||||||
String* name,
|
String* name,
|
||||||
bool is_dont_delete) {
|
bool is_dont_delete) {
|
||||||
// ----------- S t a t e -------------
|
// ----------- S t a t e -------------
|
||||||
|
// -- eax : receiver
|
||||||
// -- ecx : name
|
// -- ecx : name
|
||||||
// -- esp[0] : return address
|
// -- esp[0] : return address
|
||||||
// -- esp[4] : receiver
|
|
||||||
// -----------------------------------
|
// -----------------------------------
|
||||||
Label miss;
|
Label miss;
|
||||||
|
|
||||||
// Get the receiver from the stack.
|
|
||||||
__ mov(eax, Operand(esp, kPointerSize));
|
|
||||||
|
|
||||||
// If the object is the holder then we know that it's a global
|
// If the object is the holder then we know that it's a global
|
||||||
// object which can only happen for contextual loads. In this case,
|
// object which can only happen for contextual loads. In this case,
|
||||||
// the receiver cannot be a smi.
|
// the receiver cannot be a smi.
|
||||||
@ -1890,19 +1883,20 @@ Object* LoadStubCompiler::CompileLoadGlobal(JSObject* object,
|
|||||||
CheckPrototypes(object, eax, holder, ebx, edx, name, &miss);
|
CheckPrototypes(object, eax, holder, ebx, edx, name, &miss);
|
||||||
|
|
||||||
// Get the value from the cell.
|
// Get the value from the cell.
|
||||||
__ mov(eax, Immediate(Handle<JSGlobalPropertyCell>(cell)));
|
__ mov(ebx, Immediate(Handle<JSGlobalPropertyCell>(cell)));
|
||||||
__ mov(eax, FieldOperand(eax, JSGlobalPropertyCell::kValueOffset));
|
__ mov(ebx, FieldOperand(ebx, JSGlobalPropertyCell::kValueOffset));
|
||||||
|
|
||||||
// Check for deleted property if property can actually be deleted.
|
// Check for deleted property if property can actually be deleted.
|
||||||
if (!is_dont_delete) {
|
if (!is_dont_delete) {
|
||||||
__ cmp(eax, Factory::the_hole_value());
|
__ cmp(ebx, Factory::the_hole_value());
|
||||||
__ j(equal, &miss, not_taken);
|
__ j(equal, &miss, not_taken);
|
||||||
} else if (FLAG_debug_code) {
|
} else if (FLAG_debug_code) {
|
||||||
__ cmp(eax, Factory::the_hole_value());
|
__ cmp(ebx, Factory::the_hole_value());
|
||||||
__ Check(not_equal, "DontDelete cells can't contain the hole");
|
__ Check(not_equal, "DontDelete cells can't contain the hole");
|
||||||
}
|
}
|
||||||
|
|
||||||
__ IncrementCounter(&Counters::named_load_global_inline, 1);
|
__ IncrementCounter(&Counters::named_load_global_inline, 1);
|
||||||
|
__ mov(eax, ebx);
|
||||||
__ ret(0);
|
__ ret(0);
|
||||||
|
|
||||||
__ bind(&miss);
|
__ bind(&miss);
|
||||||
|
@ -888,13 +888,28 @@ Result VirtualFrame::RawCallCodeObject(Handle<Code> code,
|
|||||||
|
|
||||||
Result VirtualFrame::CallLoadIC(RelocInfo::Mode mode) {
|
Result VirtualFrame::CallLoadIC(RelocInfo::Mode mode) {
|
||||||
// Name and receiver are on the top of the frame. The IC expects
|
// Name and receiver are on the top of the frame. The IC expects
|
||||||
// name in ecx and receiver on the stack. It does not drop the
|
// name in ecx and receiver in eax.
|
||||||
// receiver.
|
|
||||||
Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
|
Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
|
||||||
Result name = Pop();
|
Result name = Pop();
|
||||||
PrepareForCall(1, 0); // One stack arg, not callee-dropped.
|
Result receiver = Pop();
|
||||||
name.ToRegister(ecx);
|
PrepareForCall(0, 0); // No stack arguments.
|
||||||
|
// Move results to the right registers:
|
||||||
|
if (name.is_register() && name.reg().is(eax)) {
|
||||||
|
if (receiver.is_register() && receiver.reg().is(ecx)) {
|
||||||
|
// Wrong registers.
|
||||||
|
__ xchg(eax, ecx);
|
||||||
|
} else {
|
||||||
|
// Register ecx is free for name, which frees eax for receiver.
|
||||||
|
name.ToRegister(ecx);
|
||||||
|
receiver.ToRegister(eax);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Register eax is free for receiver, which frees ecx for name.
|
||||||
|
receiver.ToRegister(eax);
|
||||||
|
name.ToRegister(ecx);
|
||||||
|
}
|
||||||
name.Unuse();
|
name.Unuse();
|
||||||
|
receiver.Unuse();
|
||||||
return RawCallCodeObject(ic, mode);
|
return RawCallCodeObject(ic, mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -333,7 +333,7 @@ class VirtualFrame: public ZoneObject {
|
|||||||
Result InvokeBuiltin(Builtins::JavaScript id, InvokeFlag flag, int arg_count);
|
Result InvokeBuiltin(Builtins::JavaScript id, InvokeFlag flag, int arg_count);
|
||||||
|
|
||||||
// Call load IC. Name and receiver are found on top of the frame.
|
// Call load IC. Name and receiver are found on top of the frame.
|
||||||
// Receiver is not dropped.
|
// Both are dropped.
|
||||||
Result CallLoadIC(RelocInfo::Mode mode);
|
Result CallLoadIC(RelocInfo::Mode mode);
|
||||||
|
|
||||||
// Call keyed load IC. Key and receiver are found on top of the
|
// Call keyed load IC. Key and receiver are found on top of the
|
||||||
|
Loading…
Reference in New Issue
Block a user