Index: src/ia32/stub-cache-ia32.cc |
diff --git a/src/ia32/stub-cache-ia32.cc b/src/ia32/stub-cache-ia32.cc |
index 96dc46bc72fdd96570d7ec55ce1b647016da9f9d..c753d4e353882a1939d067cc06a74d924acbaa5a 100644 |
--- a/src/ia32/stub-cache-ia32.cc |
+++ b/src/ia32/stub-cache-ia32.cc |
@@ -1044,46 +1044,20 @@ Register StubCompiler::CheckPrototypes(Handle<JSObject> object, |
} |
-void StubCompiler::GenerateLoadField(Handle<JSObject> object, |
- Handle<JSObject> holder, |
- Register receiver, |
- Register scratch1, |
- Register scratch2, |
- Register scratch3, |
- PropertyIndex index, |
- Handle<String> name, |
- Label* miss) { |
- // Check that the receiver isn't a smi. |
- __ JumpIfSmi(receiver, miss); |
- |
- // Check the prototype chain. |
- Register reg = CheckPrototypes( |
- object, receiver, holder, scratch1, scratch2, scratch3, name, miss); |
- |
- // Get the value from the properties. |
- GenerateFastPropertyLoad(masm(), eax, reg, holder, index); |
- __ ret(0); |
-} |
- |
- |
-void StubCompiler::GenerateDictionaryLoadCallback(Register receiver, |
- Register name_reg, |
- Register scratch1, |
- Register scratch2, |
- Register scratch3, |
- Handle<AccessorInfo> callback, |
- Handle<String> name, |
- Label* miss) { |
- ASSERT(!receiver.is(scratch2)); |
- ASSERT(!receiver.is(scratch3)); |
- Register dictionary = scratch1; |
- bool must_preserve_dictionary_reg = receiver.is(dictionary); |
+void BaseLoadStubCompiler::GenerateDictionaryLoadCallback( |
Toon Verwaest
2013/02/06 14:06:30
This got moved into CallbackHandlerFrontend direct
|
+ Register reg, |
+ Handle<AccessorInfo> callback, |
+ Label* miss) { |
+ ASSERT(!reg.is(scratch2())); |
+ ASSERT(!reg.is(scratch3())); |
+ Register dictionary = scratch1(); |
+ bool must_preserve_dictionary_reg = reg.is(dictionary); |
// Load the properties dictionary. |
if (must_preserve_dictionary_reg) { |
__ push(dictionary); |
} |
- __ mov(dictionary, FieldOperand(receiver, JSObject::kPropertiesOffset)); |
+ __ mov(dictionary, FieldOperand(reg, JSObject::kPropertiesOffset)); |
// Probe the dictionary. |
Label probe_done, pop_and_miss; |
@@ -1091,9 +1065,9 @@ void StubCompiler::GenerateDictionaryLoadCallback(Register receiver, |
&pop_and_miss, |
&probe_done, |
dictionary, |
- name_reg, |
- scratch2, |
- scratch3); |
+ this->name(), |
+ scratch2(), |
+ scratch3()); |
__ bind(&pop_and_miss); |
if (must_preserve_dictionary_reg) { |
__ pop(dictionary); |
@@ -1103,56 +1077,79 @@ void StubCompiler::GenerateDictionaryLoadCallback(Register receiver, |
// If probing finds an entry in the dictionary, scratch2 contains the |
// index into the dictionary. Check that the value is the callback. |
- Register index = scratch2; |
+ Register index = scratch2(); |
const int kElementsStartOffset = |
StringDictionary::kHeaderSize + |
StringDictionary::kElementsStartIndex * kPointerSize; |
const int kValueOffset = kElementsStartOffset + kPointerSize; |
- __ mov(scratch3, |
+ __ mov(scratch3(), |
Operand(dictionary, index, times_4, kValueOffset - kHeapObjectTag)); |
if (must_preserve_dictionary_reg) { |
__ pop(dictionary); |
} |
- __ cmp(scratch3, callback); |
+ __ cmp(scratch3(), callback); |
__ j(not_equal, miss); |
} |
-void StubCompiler::GenerateLoadCallback(Handle<JSObject> object, |
- Handle<JSObject> holder, |
- Register receiver, |
- Register name_reg, |
- Register scratch1, |
- Register scratch2, |
- Register scratch3, |
- Register scratch4, |
- Handle<AccessorInfo> callback, |
- Handle<String> name, |
- Label* miss) { |
- // Check that the receiver isn't a smi. |
- __ JumpIfSmi(receiver, miss); |
+Register BaseLoadStubCompiler::GenerateHandlerFrontend( |
+ Handle<JSObject> object, |
+ Register object_reg, |
+ Handle<JSObject> holder, |
+ Handle<String> name, |
+ Label* success, |
+ Handle<AccessorInfo> callback, |
+ bool perform_initial_checks) { |
+ Label miss; |
- // Check that the maps haven't changed. |
- Register reg = CheckPrototypes(object, receiver, holder, scratch1, |
- scratch2, scratch3, name, miss); |
+ if (perform_initial_checks) { |
+ GenerateNameCheck(name, this->name(), &miss); |
+ // Check that the receiver isn't a smi. |
+ __ JumpIfSmi(object_reg, &miss); |
+ } |
- if (!holder->HasFastProperties() && !holder->IsJSGlobalObject()) { |
- GenerateDictionaryLoadCallback( |
- reg, name_reg, scratch1, scratch2, scratch3, callback, name, miss); |
+ // Check the prototype chain. |
+ Register reg = CheckPrototypes(object, object_reg, holder, |
+ scratch1(), scratch2(), scratch3(), |
+ name, &miss); |
+ |
+ if (!callback.is_null() && |
+ !holder->HasFastProperties() && |
+ !holder->IsJSGlobalObject()) { |
+ GenerateDictionaryLoadCallback(reg, callback, &miss); |
} |
+ __ jmp(success); |
+ |
+ __ bind(&miss); |
+ GenerateLoadMiss(masm(), kind()); |
+ return reg; |
+} |
+ |
+ |
+void BaseLoadStubCompiler::GenerateLoadField(Register reg, |
+ Handle<JSObject> holder, |
+ PropertyIndex index) { |
+ // Get the value from the properties. |
+ GenerateFastPropertyLoad(masm(), eax, reg, holder, index); |
+ __ ret(0); |
+} |
+ |
+ |
+void BaseLoadStubCompiler::GenerateLoadCallback(Register reg, |
+ Handle<AccessorInfo> callback) { |
// Insert additional parameters into the stack frame above return address. |
- ASSERT(!scratch3.is(reg)); |
- __ pop(scratch3); // Get return address to place it below. |
+ ASSERT(!scratch3().is(reg)); |
+ __ pop(scratch3()); // Get return address to place it below. |
- __ push(receiver); // receiver |
- __ mov(scratch2, esp); |
- ASSERT(!scratch2.is(reg)); |
+ __ push(receiver()); // receiver |
+ __ mov(scratch2(), esp); |
+ ASSERT(!scratch2().is(reg)); |
__ push(reg); // holder |
// Push data from AccessorInfo. |
if (isolate()->heap()->InNewSpace(callback->data())) { |
- __ mov(scratch1, Immediate(callback)); |
- __ push(FieldOperand(scratch1, AccessorInfo::kDataOffset)); |
+ __ mov(scratch1(), Immediate(callback)); |
+ __ push(FieldOperand(scratch1(), AccessorInfo::kDataOffset)); |
} else { |
__ push(Immediate(Handle<Object>(callback->data()))); |
} |
@@ -1160,12 +1157,12 @@ void StubCompiler::GenerateLoadCallback(Handle<JSObject> object, |
// Save a pointer to where we pushed the arguments pointer. |
// This will be passed as the const AccessorInfo& to the C++ callback. |
- __ push(scratch2); |
+ __ push(scratch2()); |
- __ push(name_reg); // name |
+ __ push(name()); // name |
__ mov(ebx, esp); // esp points to reference to name (handler). |
- __ push(scratch3); // Restore return address. |
+ __ push(scratch3()); // Restore return address. |
// 4 elements array for v8::Arguments::values_, handler for name and pointer |
// to the values (it considered as smi in GC). |
@@ -1186,44 +1183,22 @@ void StubCompiler::GenerateLoadCallback(Handle<JSObject> object, |
} |
-void StubCompiler::GenerateLoadConstant(Handle<JSObject> object, |
- Handle<JSObject> holder, |
- Register receiver, |
- Register scratch1, |
- Register scratch2, |
- Register scratch3, |
- Handle<JSFunction> value, |
- Handle<String> name, |
- Label* miss) { |
- // Check that the receiver isn't a smi. |
- __ JumpIfSmi(receiver, miss); |
- |
- // Check that the maps haven't changed. |
- CheckPrototypes( |
- object, receiver, holder, scratch1, scratch2, scratch3, name, miss); |
- |
+void BaseLoadStubCompiler::GenerateLoadConstant(Handle<JSFunction> value) { |
// Return the constant value. |
__ LoadHeapObject(eax, value); |
__ ret(0); |
} |
-void StubCompiler::GenerateLoadInterceptor(Handle<JSObject> object, |
- Handle<JSObject> interceptor_holder, |
- LookupResult* lookup, |
- Register receiver, |
- Register name_reg, |
- Register scratch1, |
- Register scratch2, |
- Register scratch3, |
- Handle<String> name, |
- Label* miss) { |
+void BaseLoadStubCompiler::GenerateLoadInterceptor( |
+ Register holder_reg, |
+ Handle<JSObject> object, |
+ Handle<JSObject> interceptor_holder, |
+ LookupResult* lookup, |
+ Handle<String> name) { |
ASSERT(interceptor_holder->HasNamedInterceptor()); |
ASSERT(!interceptor_holder->GetNamedInterceptor()->getter()->IsUndefined()); |
- // Check that the receiver isn't a smi. |
- __ JumpIfSmi(receiver, miss); |
- |
// So far the most popular follow ups for interceptor loads are FIELD |
// and CALLBACKS, so inline only them, other cases may be added |
// later. |
@@ -1243,17 +1218,14 @@ void StubCompiler::GenerateLoadInterceptor(Handle<JSObject> object, |
// Compile the interceptor call, followed by inline code to load the |
// property from further up the prototype chain if the call fails. |
// Check that the maps haven't changed. |
- Register holder_reg = CheckPrototypes(object, receiver, interceptor_holder, |
- scratch1, scratch2, scratch3, |
- name, miss); |
- ASSERT(holder_reg.is(receiver) || holder_reg.is(scratch1)); |
+ ASSERT(holder_reg.is(receiver()) || holder_reg.is(scratch1())); |
// Preserve the receiver register explicitly whenever it is different from |
// the holder and it is needed should the interceptor return without any |
// result. The CALLBACKS case needs the receiver to be passed into C++ code, |
// the FIELD case might cause a miss during the prototype check. |
bool must_perfrom_prototype_check = *interceptor_holder != lookup->holder(); |
Jakob Kummerow
2013/02/06 12:48:27
While you're at it: s/perfrom/perform/
|
- bool must_preserve_receiver_reg = !receiver.is(holder_reg) && |
+ bool must_preserve_receiver_reg = !receiver().is(holder_reg) && |
(lookup->type() == CALLBACKS || must_perfrom_prototype_check); |
// Save necessary data before invoking an interceptor. |
@@ -1262,18 +1234,18 @@ void StubCompiler::GenerateLoadInterceptor(Handle<JSObject> object, |
FrameScope frame_scope(masm(), StackFrame::INTERNAL); |
if (must_preserve_receiver_reg) { |
- __ push(receiver); |
+ __ push(receiver()); |
} |
__ push(holder_reg); |
- __ push(name_reg); |
+ __ push(this->name()); |
// Invoke an interceptor. Note: map checks from receiver to |
// interceptor's holder has been compiled before (see a caller |
// of this method.) |
CompileCallLoadPropertyWithInterceptor(masm(), |
- receiver, |
+ receiver(), |
holder_reg, |
- name_reg, |
+ this->name(), |
interceptor_holder); |
// Check if interceptor provided a value for property. If it's |
@@ -1287,76 +1259,28 @@ void StubCompiler::GenerateLoadInterceptor(Handle<JSObject> object, |
// Clobber registers when generating debug-code to provoke errors. |
__ bind(&interceptor_failed); |
if (FLAG_debug_code) { |
- __ mov(receiver, Immediate(BitCast<int32_t>(kZapValue))); |
+ __ mov(receiver(), Immediate(BitCast<int32_t>(kZapValue))); |
__ mov(holder_reg, Immediate(BitCast<int32_t>(kZapValue))); |
- __ mov(name_reg, Immediate(BitCast<int32_t>(kZapValue))); |
+ __ mov(this->name(), Immediate(BitCast<int32_t>(kZapValue))); |
} |
- __ pop(name_reg); |
+ __ pop(this->name()); |
__ pop(holder_reg); |
if (must_preserve_receiver_reg) { |
- __ pop(receiver); |
+ __ pop(receiver()); |
} |
// Leave the internal frame. |
} |
- // Check that the maps from interceptor's holder to lookup's holder |
- // haven't changed. And load lookup's holder into holder_reg. |
- if (must_perfrom_prototype_check) { |
- holder_reg = CheckPrototypes(interceptor_holder, |
- holder_reg, |
- Handle<JSObject>(lookup->holder()), |
- scratch1, |
- scratch2, |
- scratch3, |
- name, |
- miss); |
- } |
- |
- if (lookup->IsField()) { |
- // We found FIELD property in prototype chain of interceptor's holder. |
- // Retrieve a field from field's holder. |
- GenerateFastPropertyLoad(masm(), eax, holder_reg, |
- Handle<JSObject>(lookup->holder()), |
- lookup->GetFieldIndex()); |
- __ ret(0); |
- } else { |
- // We found CALLBACKS property in prototype chain of interceptor's |
- // holder. |
- ASSERT(lookup->type() == CALLBACKS); |
- Handle<AccessorInfo> callback( |
- AccessorInfo::cast(lookup->GetCallbackObject())); |
- ASSERT(callback->getter() != NULL); |
- |
- // Tail call to runtime. |
- // Important invariant in CALLBACKS case: the code above must be |
- // structured to never clobber |receiver| register. |
- __ pop(scratch2); // return address |
- __ push(receiver); |
- __ push(holder_reg); |
- __ mov(holder_reg, Immediate(callback)); |
- __ push(FieldOperand(holder_reg, AccessorInfo::kDataOffset)); |
- __ push(Immediate(reinterpret_cast<int>(isolate()))); |
- __ push(holder_reg); |
- __ push(name_reg); |
- __ push(scratch2); // restore return address |
- |
- ExternalReference ref = |
- ExternalReference(IC_Utility(IC::kLoadCallbackProperty), |
- masm()->isolate()); |
- __ TailCallExternalReference(ref, 6, 1); |
- } |
+ GenerateLoadPostInterceptor(holder_reg, interceptor_holder, name, lookup); |
} else { // !compile_followup_inline |
// Call the runtime system to load the interceptor. |
// Check that the maps haven't changed. |
- Register holder_reg = |
- CheckPrototypes(object, receiver, interceptor_holder, |
- scratch1, scratch2, scratch3, name, miss); |
- __ pop(scratch2); // save old return address |
- PushInterceptorArguments(masm(), receiver, holder_reg, |
- name_reg, interceptor_holder); |
- __ push(scratch2); // restore old return address |
+ __ pop(scratch2()); // save old return address |
+ PushInterceptorArguments(masm(), receiver(), holder_reg, |
+ this->name(), interceptor_holder); |
+ __ push(scratch2()); // restore old return address |
ExternalReference ref = |
ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorForLoad), |
@@ -1366,6 +1290,46 @@ void StubCompiler::GenerateLoadInterceptor(Handle<JSObject> object, |
} |
+void BaseLoadStubCompiler::GenerateLoadPostInterceptor( |
+ Register interceptor_reg, |
+ Handle<JSObject> interceptor_holder, |
+ Handle<String> name, |
+ LookupResult* lookup) { |
+ Label success; |
+ Handle<JSObject> holder(lookup->holder()); |
+ if (lookup->IsField()) { |
+ // We found FIELD property in prototype chain of interceptor's holder. |
+ // Retrieve a field from field's holder. |
+ Register reg = GenerateHandlerFrontend(interceptor_holder, |
+ interceptor_reg, |
+ holder, |
+ name, |
+ &success, |
+ Handle<AccessorInfo>::null(), |
+ false); |
+ __ bind(&success); |
+ GenerateLoadField(reg, holder, lookup->GetFieldIndex()); |
+ } else { |
+ // We found CALLBACKS property in prototype chain of interceptor's |
+ // holder. |
+ ASSERT(lookup->type() == CALLBACKS); |
+ Handle<AccessorInfo> callback( |
+ AccessorInfo::cast(lookup->GetCallbackObject())); |
+ ASSERT(callback->getter() != NULL); |
+ |
+ Register reg = GenerateHandlerFrontend(interceptor_holder, |
+ interceptor_reg, |
+ holder, |
+ name, |
+ &success, |
+ callback, |
+ false); |
+ __ bind(&success); |
+ GenerateLoadCallback(reg, callback); |
+ } |
+} |
+ |
+ |
void CallStubCompiler::GenerateNameCheck(Handle<String> name, Label* miss) { |
if (kind_ == Code::KEYED_CALL_IC) { |
__ cmp(ecx, Immediate(name)); |