Index: src/ic/ic.cc |
diff --git a/src/ic/ic.cc b/src/ic/ic.cc |
index a2d60143028bbb0c0fb72147111b4582a3c059aa..1c6e72be23935282f17ad03d233c2ca5e61cefff 100644 |
--- a/src/ic/ic.cc |
+++ b/src/ic/ic.cc |
@@ -963,120 +963,130 @@ Handle<Code> LoadIC::CompileHandler(LookupIterator* lookup, |
Handle<HeapType> type = receiver_type(); |
Handle<JSObject> holder = lookup->GetHolder<JSObject>(); |
bool receiver_is_holder = receiver.is_identical_to(holder); |
- // -------------- Interceptors -------------- |
- if (lookup->state() == LookupIterator::INTERCEPTOR) { |
- DCHECK(!holder->GetNamedInterceptor()->getter()->IsUndefined()); |
- NamedLoadHandlerCompiler compiler(isolate(), receiver_type(), holder, |
- cache_holder); |
- // Perform a lookup behind the interceptor. Copy the LookupIterator since |
- // the original iterator will be used to fetch the value. |
- LookupIterator it = *lookup; |
- it.Next(); |
- LookupForRead(&it); |
- return compiler.CompileLoadInterceptor(&it); |
- } |
- |
- // -------------- Accessors -------------- |
- if (lookup->state() == LookupIterator::ACCESSOR) { |
- // Use simple field loads for some well-known callback properties. |
- if (receiver_is_holder) { |
- DCHECK(receiver->IsJSObject()); |
- Handle<JSObject> js_receiver = Handle<JSObject>::cast(receiver); |
- int object_offset; |
- if (Accessors::IsJSObjectFieldAccessor<HeapType>(type, lookup->name(), |
- &object_offset)) { |
- FieldIndex index = |
- FieldIndex::ForInObjectOffset(object_offset, js_receiver->map()); |
- return SimpleFieldLoad(index); |
- } |
- } |
- |
- Handle<Object> accessors = lookup->GetAccessors(); |
- if (accessors->IsExecutableAccessorInfo()) { |
- Handle<ExecutableAccessorInfo> info = |
- Handle<ExecutableAccessorInfo>::cast(accessors); |
- if (v8::ToCData<Address>(info->getter()) == 0) return slow_stub(); |
- if (!ExecutableAccessorInfo::IsCompatibleReceiverType(isolate(), info, |
- type)) { |
- return slow_stub(); |
- } |
- if (!holder->HasFastProperties()) return slow_stub(); |
+ switch (lookup->state()) { |
+ case LookupIterator::INTERCEPTOR: { |
+ DCHECK(!holder->GetNamedInterceptor()->getter()->IsUndefined()); |
NamedLoadHandlerCompiler compiler(isolate(), receiver_type(), holder, |
cache_holder); |
- return compiler.CompileLoadCallback(lookup->name(), info); |
+ // Perform a lookup behind the interceptor. Copy the LookupIterator since |
+ // the original iterator will be used to fetch the value. |
+ LookupIterator it = *lookup; |
+ it.Next(); |
+ LookupForRead(&it); |
+ return compiler.CompileLoadInterceptor(&it); |
} |
- if (accessors->IsAccessorPair()) { |
- Handle<Object> getter(Handle<AccessorPair>::cast(accessors)->getter(), |
- isolate()); |
- if (!getter->IsJSFunction()) return slow_stub(); |
- if (!holder->HasFastProperties()) return slow_stub(); |
- Handle<JSFunction> function = Handle<JSFunction>::cast(getter); |
- if (!receiver->IsJSObject() && !function->IsBuiltin() && |
- function->shared()->strict_mode() == SLOPPY) { |
- // Calling sloppy non-builtins with a value as the receiver |
- // requires boxing. |
- return slow_stub(); |
+ |
+ case LookupIterator::ACCESSOR: { |
+ // Use simple field loads for some well-known callback properties. |
+ if (receiver_is_holder) { |
+ DCHECK(receiver->IsJSObject()); |
+ Handle<JSObject> js_receiver = Handle<JSObject>::cast(receiver); |
+ int object_offset; |
+ if (Accessors::IsJSObjectFieldAccessor<HeapType>(type, lookup->name(), |
+ &object_offset)) { |
+ FieldIndex index = |
+ FieldIndex::ForInObjectOffset(object_offset, js_receiver->map()); |
+ return SimpleFieldLoad(index); |
+ } |
} |
- CallOptimization call_optimization(function); |
- NamedLoadHandlerCompiler compiler(isolate(), receiver_type(), holder, |
- cache_holder); |
- if (call_optimization.is_simple_api_call() && |
- call_optimization.IsCompatibleReceiver(receiver, holder)) { |
- return compiler.CompileLoadCallback(lookup->name(), call_optimization); |
+ |
+ Handle<Object> accessors = lookup->GetAccessors(); |
+ if (accessors->IsExecutableAccessorInfo()) { |
+ Handle<ExecutableAccessorInfo> info = |
+ Handle<ExecutableAccessorInfo>::cast(accessors); |
+ if (v8::ToCData<Address>(info->getter()) == 0) break; |
+ if (!ExecutableAccessorInfo::IsCompatibleReceiverType(isolate(), info, |
+ type)) { |
+ break; |
+ } |
+ if (!holder->HasFastProperties()) break; |
+ NamedLoadHandlerCompiler compiler(isolate(), receiver_type(), holder, |
+ cache_holder); |
+ return compiler.CompileLoadCallback(lookup->name(), info); |
} |
- return compiler.CompileLoadViaGetter(lookup->name(), function); |
+ if (accessors->IsAccessorPair()) { |
+ Handle<Object> getter(Handle<AccessorPair>::cast(accessors)->getter(), |
+ isolate()); |
+ if (!getter->IsJSFunction()) break; |
+ if (!holder->HasFastProperties()) break; |
+ Handle<JSFunction> function = Handle<JSFunction>::cast(getter); |
+ if (!receiver->IsJSObject() && !function->IsBuiltin() && |
+ function->shared()->strict_mode() == SLOPPY) { |
+ // Calling sloppy non-builtins with a value as the receiver |
+ // requires boxing. |
+ break; |
+ } |
+ CallOptimization call_optimization(function); |
+ NamedLoadHandlerCompiler compiler(isolate(), receiver_type(), holder, |
+ cache_holder); |
+ if (call_optimization.is_simple_api_call() && |
+ call_optimization.IsCompatibleReceiver(receiver, holder)) { |
+ return compiler.CompileLoadCallback(lookup->name(), |
+ call_optimization); |
+ } |
+ return compiler.CompileLoadViaGetter(lookup->name(), function); |
+ } |
+ // TODO(dcarney): Handle correctly. |
+ DCHECK(accessors->IsDeclaredAccessorInfo()); |
+ break; |
} |
- // TODO(dcarney): Handle correctly. |
- DCHECK(accessors->IsDeclaredAccessorInfo()); |
- return slow_stub(); |
- } |
- // -------------- Dictionary properties -------------- |
- DCHECK(lookup->state() == LookupIterator::DATA); |
- if (lookup->is_dictionary_holder()) { |
- if (kind() != Code::LOAD_IC) return slow_stub(); |
- if (holder->IsGlobalObject()) { |
+ case LookupIterator::DATA: { |
+ if (lookup->is_dictionary_holder()) { |
+ if (kind() != Code::LOAD_IC) break; |
+ if (holder->IsGlobalObject()) { |
+ NamedLoadHandlerCompiler compiler(isolate(), receiver_type(), holder, |
+ cache_holder); |
+ Handle<PropertyCell> cell = lookup->GetPropertyCell(); |
+ Handle<Code> code = compiler.CompileLoadGlobal( |
+ cell, lookup->name(), lookup->IsConfigurable()); |
+ // TODO(verwaest): Move caching of these NORMAL stubs outside as well. |
+ CacheHolderFlag flag; |
+ Handle<Map> stub_holder_map = GetHandlerCacheHolder( |
+ *type, receiver_is_holder, isolate(), &flag); |
+ Map::UpdateCodeCache(stub_holder_map, lookup->name(), code); |
+ return code; |
+ } |
+ // There is only one shared stub for loading normalized |
+ // properties. It does not traverse the prototype chain, so the |
+ // property must be found in the object for the stub to be |
+ // applicable. |
+ if (!receiver_is_holder) break; |
+ return isolate()->builtins()->LoadIC_Normal(); |
+ } |
+ |
+ // -------------- Fields -------------- |
+ if (lookup->property_details().type() == FIELD) { |
+ FieldIndex field = lookup->GetFieldIndex(); |
+ if (receiver_is_holder) { |
+ return SimpleFieldLoad(field); |
+ } |
+ NamedLoadHandlerCompiler compiler(isolate(), receiver_type(), holder, |
+ cache_holder); |
+ return compiler.CompileLoadField(lookup->name(), field); |
+ } |
+ |
+ // -------------- Constant properties -------------- |
+ DCHECK(lookup->property_details().type() == CONSTANT); |
+ if (receiver_is_holder) { |
+ LoadConstantStub stub(isolate(), lookup->GetConstantIndex()); |
+ return stub.GetCode(); |
+ } |
NamedLoadHandlerCompiler compiler(isolate(), receiver_type(), holder, |
cache_holder); |
- Handle<PropertyCell> cell = lookup->GetPropertyCell(); |
- Handle<Code> code = compiler.CompileLoadGlobal(cell, lookup->name(), |
- lookup->IsConfigurable()); |
- // TODO(verwaest): Move caching of these NORMAL stubs outside as well. |
- CacheHolderFlag flag; |
- Handle<Map> stub_holder_map = |
- GetHandlerCacheHolder(*type, receiver_is_holder, isolate(), &flag); |
- Map::UpdateCodeCache(stub_holder_map, lookup->name(), code); |
- return code; |
+ return compiler.CompileLoadConstant(lookup->name(), |
+ lookup->GetConstantIndex()); |
} |
- // There is only one shared stub for loading normalized |
- // properties. It does not traverse the prototype chain, so the |
- // property must be found in the object for the stub to be |
- // applicable. |
- if (!receiver_is_holder) return slow_stub(); |
- return isolate()->builtins()->LoadIC_Normal(); |
- } |
- |
- // -------------- Fields -------------- |
- if (lookup->property_details().type() == FIELD) { |
- FieldIndex field = lookup->GetFieldIndex(); |
- if (receiver_is_holder) { |
- return SimpleFieldLoad(field); |
- } |
- NamedLoadHandlerCompiler compiler(isolate(), receiver_type(), holder, |
- cache_holder); |
- return compiler.CompileLoadField(lookup->name(), field); |
- } |
- // -------------- Constant properties -------------- |
- DCHECK(lookup->property_details().type() == CONSTANT); |
- if (receiver_is_holder) { |
- LoadConstantStub stub(isolate(), lookup->GetConstantIndex()); |
- return stub.GetCode(); |
+ case LookupIterator::ACCESS_CHECK: |
+ case LookupIterator::JSPROXY: |
+ case LookupIterator::NOT_FOUND: |
+ case LookupIterator::TRANSITION: |
+ case LookupIterator::UNKNOWN: |
+ UNREACHABLE(); |
} |
- NamedLoadHandlerCompiler compiler(isolate(), receiver_type(), holder, |
- cache_holder); |
- return compiler.CompileLoadConstant(lookup->name(), |
- lookup->GetConstantIndex()); |
+ |
+ return slow_stub(); |
} |
@@ -1400,96 +1410,102 @@ Handle<Code> StoreIC::CompileHandler(LookupIterator* lookup, |
Handle<JSObject> holder = lookup->GetHolder<JSObject>(); |
DCHECK(!receiver->IsAccessCheckNeeded()); |
- // -------------- Transition -------------- |
- if (lookup->state() == LookupIterator::TRANSITION) { |
- Handle<Map> transition = lookup->transition_map(); |
- // Currently not handled by CompileStoreTransition. |
- if (!holder->HasFastProperties()) return slow_stub(); |
- |
- DCHECK(lookup->IsCacheableTransition()); |
- NamedStoreHandlerCompiler compiler(isolate(), receiver_type(), holder); |
- return compiler.CompileStoreTransition(transition, lookup->name()); |
- } |
- |
- // -------------- Interceptors -------------- |
- if (lookup->state() == LookupIterator::INTERCEPTOR) { |
- DCHECK(!holder->GetNamedInterceptor()->setter()->IsUndefined()); |
- NamedStoreHandlerCompiler compiler(isolate(), receiver_type(), holder); |
- return compiler.CompileStoreInterceptor(lookup->name()); |
- } |
- |
- // -------------- Accessors -------------- |
- if (lookup->state() == LookupIterator::ACCESSOR) { |
- if (!holder->HasFastProperties()) return slow_stub(); |
- Handle<Object> accessors = lookup->GetAccessors(); |
- if (accessors->IsExecutableAccessorInfo()) { |
- Handle<ExecutableAccessorInfo> info = |
- Handle<ExecutableAccessorInfo>::cast(accessors); |
- if (v8::ToCData<Address>(info->setter()) == 0) return slow_stub(); |
- if (!ExecutableAccessorInfo::IsCompatibleReceiverType(isolate(), info, |
- receiver_type())) { |
- return slow_stub(); |
- } |
- NamedStoreHandlerCompiler compiler(isolate(), receiver_type(), holder); |
- return compiler.CompileStoreCallback(receiver, lookup->name(), info); |
- } else if (accessors->IsAccessorPair()) { |
- Handle<Object> setter(Handle<AccessorPair>::cast(accessors)->setter(), |
- isolate()); |
- if (!setter->IsJSFunction()) return slow_stub(); |
- Handle<JSFunction> function = Handle<JSFunction>::cast(setter); |
- CallOptimization call_optimization(function); |
+ switch (lookup->state()) { |
+ case LookupIterator::TRANSITION: { |
+ Handle<Map> transition = lookup->transition_map(); |
+ // Currently not handled by CompileStoreTransition. |
+ if (!holder->HasFastProperties()) break; |
+ |
+ DCHECK(lookup->IsCacheableTransition()); |
NamedStoreHandlerCompiler compiler(isolate(), receiver_type(), holder); |
- if (call_optimization.is_simple_api_call() && |
- call_optimization.IsCompatibleReceiver(receiver, holder)) { |
- return compiler.CompileStoreCallback(receiver, lookup->name(), |
- call_optimization); |
- } |
- return compiler.CompileStoreViaSetter(receiver, lookup->name(), |
- Handle<JSFunction>::cast(setter)); |
+ return compiler.CompileStoreTransition(transition, lookup->name()); |
} |
- // TODO(dcarney): Handle correctly. |
- DCHECK(accessors->IsDeclaredAccessorInfo()); |
- return slow_stub(); |
- } |
- |
- // -------------- Dictionary properties -------------- |
- DCHECK(lookup->state() == LookupIterator::DATA); |
- if (lookup->is_dictionary_holder()) { |
- if (holder->IsGlobalObject()) { |
- Handle<PropertyCell> cell = lookup->GetPropertyCell(); |
- Handle<HeapType> union_type = PropertyCell::UpdatedType(cell, value); |
- StoreGlobalStub stub(isolate(), union_type->IsConstant(), |
- receiver->IsJSGlobalProxy()); |
- Handle<Code> code = stub.GetCodeCopyFromTemplate( |
- Handle<GlobalObject>::cast(holder), cell); |
- // TODO(verwaest): Move caching of these NORMAL stubs outside as well. |
- HeapObject::UpdateMapCodeCache(receiver, lookup->name(), code); |
- return code; |
+ |
+ case LookupIterator::INTERCEPTOR: { |
+ DCHECK(!holder->GetNamedInterceptor()->setter()->IsUndefined()); |
+ NamedStoreHandlerCompiler compiler(isolate(), receiver_type(), holder); |
+ return compiler.CompileStoreInterceptor(lookup->name()); |
} |
- DCHECK(holder.is_identical_to(receiver)); |
- return isolate()->builtins()->StoreIC_Normal(); |
- } |
- |
- // -------------- Fields -------------- |
- if (lookup->property_details().type() == FIELD) { |
- bool use_stub = true; |
- if (lookup->representation().IsHeapObject()) { |
- // Only use a generic stub if no types need to be tracked. |
- Handle<HeapType> field_type = lookup->GetFieldType(); |
- HeapType::Iterator<Map> it = field_type->Classes(); |
- use_stub = it.Done(); |
+ |
+ case LookupIterator::ACCESSOR: { |
+ if (!holder->HasFastProperties()) break; |
+ Handle<Object> accessors = lookup->GetAccessors(); |
+ if (accessors->IsExecutableAccessorInfo()) { |
+ Handle<ExecutableAccessorInfo> info = |
+ Handle<ExecutableAccessorInfo>::cast(accessors); |
+ if (v8::ToCData<Address>(info->setter()) == 0) break; |
+ if (!ExecutableAccessorInfo::IsCompatibleReceiverType( |
+ isolate(), info, receiver_type())) { |
+ break; |
+ } |
+ NamedStoreHandlerCompiler compiler(isolate(), receiver_type(), holder); |
+ return compiler.CompileStoreCallback(receiver, lookup->name(), info); |
+ } else if (accessors->IsAccessorPair()) { |
+ Handle<Object> setter(Handle<AccessorPair>::cast(accessors)->setter(), |
+ isolate()); |
+ if (!setter->IsJSFunction()) break; |
+ Handle<JSFunction> function = Handle<JSFunction>::cast(setter); |
+ CallOptimization call_optimization(function); |
+ NamedStoreHandlerCompiler compiler(isolate(), receiver_type(), holder); |
+ if (call_optimization.is_simple_api_call() && |
+ call_optimization.IsCompatibleReceiver(receiver, holder)) { |
+ return compiler.CompileStoreCallback(receiver, lookup->name(), |
+ call_optimization); |
+ } |
+ return compiler.CompileStoreViaSetter(receiver, lookup->name(), |
+ Handle<JSFunction>::cast(setter)); |
+ } |
+ // TODO(dcarney): Handle correctly. |
+ DCHECK(accessors->IsDeclaredAccessorInfo()); |
+ break; |
} |
- if (use_stub) { |
- StoreFieldStub stub(isolate(), lookup->GetFieldIndex(), |
- lookup->representation()); |
- return stub.GetCode(); |
+ |
+ case LookupIterator::DATA: { |
+ if (lookup->is_dictionary_holder()) { |
+ if (holder->IsGlobalObject()) { |
+ Handle<PropertyCell> cell = lookup->GetPropertyCell(); |
+ Handle<HeapType> union_type = PropertyCell::UpdatedType(cell, value); |
+ StoreGlobalStub stub(isolate(), union_type->IsConstant(), |
+ receiver->IsJSGlobalProxy()); |
+ Handle<Code> code = stub.GetCodeCopyFromTemplate( |
+ Handle<GlobalObject>::cast(holder), cell); |
+ // TODO(verwaest): Move caching of these NORMAL stubs outside as well. |
+ HeapObject::UpdateMapCodeCache(receiver, lookup->name(), code); |
+ return code; |
+ } |
+ DCHECK(holder.is_identical_to(receiver)); |
+ return isolate()->builtins()->StoreIC_Normal(); |
+ } |
+ |
+ // -------------- Fields -------------- |
+ if (lookup->property_details().type() == FIELD) { |
+ bool use_stub = true; |
+ if (lookup->representation().IsHeapObject()) { |
+ // Only use a generic stub if no types need to be tracked. |
+ Handle<HeapType> field_type = lookup->GetFieldType(); |
+ HeapType::Iterator<Map> it = field_type->Classes(); |
+ use_stub = it.Done(); |
+ } |
+ if (use_stub) { |
+ StoreFieldStub stub(isolate(), lookup->GetFieldIndex(), |
+ lookup->representation()); |
+ return stub.GetCode(); |
+ } |
+ NamedStoreHandlerCompiler compiler(isolate(), receiver_type(), holder); |
+ return compiler.CompileStoreField(lookup); |
+ } |
+ |
+ // -------------- Constant properties -------------- |
+ DCHECK(lookup->property_details().type() == CONSTANT); |
+ break; |
} |
- NamedStoreHandlerCompiler compiler(isolate(), receiver_type(), holder); |
- return compiler.CompileStoreField(lookup); |
- } |
- // -------------- Constant properties -------------- |
- DCHECK(lookup->property_details().type() == CONSTANT); |
+ case LookupIterator::ACCESS_CHECK: |
+ case LookupIterator::JSPROXY: |
+ case LookupIterator::NOT_FOUND: |
+ case LookupIterator::UNKNOWN: |
+ UNREACHABLE(); |
+ } |
return slow_stub(); |
} |