 Chromium Code Reviews
 Chromium Code Reviews Issue 12209021:
  Refactor LoadIC into Handler Frontend and Backends.  (Closed) 
  Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
    
  
    Issue 12209021:
  Refactor LoadIC into Handler Frontend and Backends.  (Closed) 
  Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge| 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)); |