Index: src/ic.cc |
diff --git a/src/ic.cc b/src/ic.cc |
index 80cd033c7bc9970006483194aa3256fc7ba71e92..a6ffb13ad40a84b16073b7d6b8a4bbb43ab7e702 100644 |
--- a/src/ic.cc |
+++ b/src/ic.cc |
@@ -1105,6 +1105,18 @@ void IC::PatchCache(Handle<HeapObject> receiver, |
} |
+Handle<Code> LoadIC::SimpleFieldLoad(int offset, |
+ bool inobject, |
+ Representation representation) { |
+ if (kind() == Code::LOAD_IC) { |
+ LoadFieldStub stub(inobject, offset, representation); |
+ return stub.GetCode(isolate()); |
+ } else { |
+ KeyedLoadFieldStub stub(inobject, offset, representation); |
+ return stub.GetCode(isolate()); |
+ } |
+} |
+ |
void LoadIC::UpdateCaches(LookupResult* lookup, |
Handle<Object> object, |
Handle<String> name) { |
@@ -1126,13 +1138,7 @@ void LoadIC::UpdateCaches(LookupResult* lookup, |
} else if (object->IsString() && |
name->Equals(isolate()->heap()->length_string())) { |
int length_index = String::kLengthOffset / kPointerSize; |
- if (target()->is_load_stub()) { |
- LoadFieldStub stub(true, length_index, Representation::Tagged()); |
- code = stub.GetCode(isolate()); |
- } else { |
- KeyedLoadFieldStub stub(true, length_index, Representation::Tagged()); |
- code = stub.GetCode(isolate()); |
- } |
+ code = SimpleFieldLoad(length_index); |
} else if (!object->IsJSObject()) { |
// TODO(jkummerow): It would be nice to support non-JSObjects in |
// ComputeLoadHandler, then we wouldn't need to go generic here. |
@@ -1167,7 +1173,6 @@ Handle<Code> IC::ComputeHandler(LookupResult* lookup, |
if (!code.is_null()) return code; |
code = CompileHandler(lookup, receiver, name, value); |
- if (code.is_null()) return slow_stub(); |
if (code->is_handler() && code->type() != Code::NORMAL) { |
HeapObject::UpdateMapCodeCache(receiver, name, code); |
@@ -1182,24 +1187,33 @@ Handle<Code> LoadIC::CompileHandler(LookupResult* lookup, |
Handle<String> name, |
Handle<Object> unused) { |
Handle<JSObject> holder(lookup->holder()); |
+ LoadStubCompiler compiler(isolate(), kind()); |
+ |
switch (lookup->type()) { |
- case FIELD: |
- return isolate()->stub_cache()->ComputeLoadField( |
- name, receiver, holder, |
- lookup->GetFieldIndex(), lookup->representation()); |
+ case FIELD: { |
+ PropertyIndex field = lookup->GetFieldIndex(); |
+ if (receiver.is_identical_to(holder)) { |
+ return SimpleFieldLoad(field.translate(holder), |
+ field.is_inobject(holder), |
+ lookup->representation()); |
+ } |
+ return compiler.CompileLoadField( |
+ receiver, holder, name, field, lookup->representation()); |
+ } |
case CONSTANT: { |
Handle<Object> constant(lookup->GetConstant(), isolate()); |
// TODO(2803): Don't compute a stub for cons strings because they cannot |
// be embedded into code. |
- if (constant->IsConsString()) return Handle<Code>::null(); |
- return isolate()->stub_cache()->ComputeLoadConstant( |
- name, receiver, holder, constant); |
+ if (constant->IsConsString()) break; |
+ return compiler.CompileLoadConstant(receiver, holder, name, constant); |
} |
case NORMAL: |
+ if (kind() != Code::LOAD_IC) break; |
if (holder->IsGlobalObject()) { |
Handle<GlobalObject> global = Handle<GlobalObject>::cast(holder); |
Handle<PropertyCell> cell( |
global->GetPropertyCell(lookup), isolate()); |
+ // TODO(verwaest): Turn into a handler. |
return isolate()->stub_cache()->ComputeLoadGlobal( |
name, receiver, global, cell, lookup->IsDontDelete()); |
} |
@@ -1208,18 +1222,16 @@ Handle<Code> LoadIC::CompileHandler(LookupResult* lookup, |
// property must be found in the receiver for the stub to be |
// applicable. |
if (!holder.is_identical_to(receiver)) break; |
- return isolate()->stub_cache()->ComputeLoadNormal(name, receiver); |
+ return isolate()->builtins()->LoadIC_Normal(); |
case CALLBACKS: { |
- { |
- // Use simple field loads for some well-known callback properties. |
- int object_offset; |
- Handle<Map> map(receiver->map()); |
- if (Accessors::IsJSObjectFieldAccessor(map, name, &object_offset)) { |
- PropertyIndex index = |
- PropertyIndex::NewHeaderIndex(object_offset / kPointerSize); |
- return isolate()->stub_cache()->ComputeLoadField( |
- name, receiver, receiver, index, Representation::Tagged()); |
- } |
+ // Use simple field loads for some well-known callback properties. |
+ int object_offset; |
+ Handle<Map> map(receiver->map()); |
+ if (Accessors::IsJSObjectFieldAccessor(map, name, &object_offset)) { |
+ PropertyIndex index = |
+ PropertyIndex::NewHeaderIndex(object_offset / kPointerSize); |
+ return compiler.CompileLoadField( |
+ receiver, receiver, name, index, Representation::Tagged()); |
} |
Handle<Object> callback(lookup->GetCallbackObject(), isolate()); |
@@ -1228,8 +1240,7 @@ Handle<Code> LoadIC::CompileHandler(LookupResult* lookup, |
Handle<ExecutableAccessorInfo>::cast(callback); |
if (v8::ToCData<Address>(info->getter()) == 0) break; |
if (!info->IsCompatibleReceiver(*receiver)) break; |
- return isolate()->stub_cache()->ComputeLoadCallback( |
- name, receiver, holder, info); |
+ return compiler.CompileLoadCallback(receiver, holder, name, info); |
} else if (callback->IsAccessorPair()) { |
Handle<Object> getter(Handle<AccessorPair>::cast(callback)->getter(), |
isolate()); |
@@ -1240,11 +1251,10 @@ Handle<Code> LoadIC::CompileHandler(LookupResult* lookup, |
CallOptimization call_optimization(function); |
if (call_optimization.is_simple_api_call() && |
call_optimization.IsCompatibleReceiver(*receiver)) { |
- return isolate()->stub_cache()->ComputeLoadCallback( |
- name, receiver, holder, call_optimization); |
+ return compiler.CompileLoadCallback( |
+ receiver, holder, name, call_optimization); |
} |
- return isolate()->stub_cache()->ComputeLoadViaGetter( |
- name, receiver, holder, function); |
+ return compiler.CompileLoadViaGetter(receiver, holder, name, function); |
} |
// TODO(dcarney): Handle correctly. |
if (callback->IsDeclaredAccessorInfo()) break; |
@@ -1254,12 +1264,12 @@ Handle<Code> LoadIC::CompileHandler(LookupResult* lookup, |
} |
case INTERCEPTOR: |
ASSERT(HasInterceptorGetter(*holder)); |
- return isolate()->stub_cache()->ComputeLoadInterceptor( |
- name, receiver, holder); |
+ return compiler.CompileLoadInterceptor(receiver, holder, name); |
default: |
break; |
} |
- return Handle<Code>::null(); |
+ |
+ return slow_stub(); |
} |
@@ -1391,65 +1401,6 @@ MaybeObject* KeyedLoadIC::Load(Handle<Object> object, |
} |
-Handle<Code> KeyedLoadIC::CompileHandler(LookupResult* lookup, |
- Handle<JSObject> receiver, |
- Handle<String> name, |
- Handle<Object> value) { |
- // Compute a monomorphic stub. |
- Handle<JSObject> holder(lookup->holder(), isolate()); |
- switch (lookup->type()) { |
- case FIELD: |
- return isolate()->stub_cache()->ComputeKeyedLoadField( |
- name, receiver, holder, |
- lookup->GetFieldIndex(), lookup->representation()); |
- case CONSTANT: { |
- Handle<Object> constant(lookup->GetConstant(), isolate()); |
- // TODO(2803): Don't compute a stub for cons strings because they cannot |
- // be embedded into code. |
- if (constant->IsConsString()) return Handle<Code>::null(); |
- return isolate()->stub_cache()->ComputeKeyedLoadConstant( |
- name, receiver, holder, constant); |
- } |
- case CALLBACKS: { |
- Handle<Object> callback_object(lookup->GetCallbackObject(), isolate()); |
- // TODO(dcarney): Handle DeclaredAccessorInfo correctly. |
- if (callback_object->IsExecutableAccessorInfo()) { |
- Handle<ExecutableAccessorInfo> callback = |
- Handle<ExecutableAccessorInfo>::cast(callback_object); |
- if (v8::ToCData<Address>(callback->getter()) == 0) break; |
- if (!callback->IsCompatibleReceiver(*receiver)) break; |
- return isolate()->stub_cache()->ComputeKeyedLoadCallback( |
- name, receiver, holder, callback); |
- } else if (callback_object->IsAccessorPair()) { |
- Handle<Object> getter( |
- Handle<AccessorPair>::cast(callback_object)->getter(), |
- isolate()); |
- if (!getter->IsJSFunction()) break; |
- if (holder->IsGlobalObject()) break; |
- if (!holder->HasFastProperties()) break; |
- Handle<JSFunction> function = Handle<JSFunction>::cast(getter); |
- CallOptimization call_optimization(function); |
- if (call_optimization.is_simple_api_call() && |
- call_optimization.IsCompatibleReceiver(*receiver)) { |
- return isolate()->stub_cache()->ComputeKeyedLoadCallback( |
- name, receiver, holder, call_optimization); |
- } |
- } |
- break; |
- } |
- case INTERCEPTOR: |
- ASSERT(HasInterceptorGetter(lookup->holder())); |
- return isolate()->stub_cache()->ComputeKeyedLoadInterceptor( |
- name, receiver, holder); |
- default: |
- // Always rewrite to the generic case so that we do not |
- // repeatedly try to rewrite. |
- return generic_stub(); |
- } |
- return Handle<Code>::null(); |
-} |
- |
- |
static bool LookupForWrite(Handle<JSObject> receiver, |
Handle<String> name, |
Handle<Object> value, |
@@ -1647,11 +1598,27 @@ Handle<Code> StoreIC::CompileHandler(LookupResult* lookup, |
Handle<String> name, |
Handle<Object> value) { |
Handle<JSObject> holder(lookup->holder()); |
+ StoreStubCompiler compiler(isolate(), strict_mode(), kind()); |
switch (lookup->type()) { |
case FIELD: |
- return isolate()->stub_cache()->ComputeStoreField( |
- name, receiver, lookup, strict_mode()); |
+ return compiler.CompileStoreField(receiver, lookup, name); |
+ case TRANSITION: { |
+ // Explicitly pass in the receiver map since LookupForWrite may have |
+ // stored something else than the receiver in the holder. |
+ Handle<Map> transition( |
+ lookup->GetTransitionTarget(receiver->map()), isolate()); |
+ int descriptor = transition->LastAdded(); |
+ |
+ DescriptorArray* target_descriptors = transition->instance_descriptors(); |
+ PropertyDetails details = target_descriptors->GetDetails(descriptor); |
+ |
+ if (details.type() == CALLBACKS || details.attributes() != NONE) break; |
+ |
+ return compiler.CompileStoreTransition( |
+ receiver, lookup, transition, name); |
+ } |
case NORMAL: |
+ if (kind() == Code::KEYED_STORE_IC) break; |
if (receiver->IsGlobalObject()) { |
// The stub generated for the global object picks the value directly |
// from the property cell. So the property must be directly on the |
@@ -1659,12 +1626,16 @@ Handle<Code> StoreIC::CompileHandler(LookupResult* lookup, |
Handle<GlobalObject> global = Handle<GlobalObject>::cast(receiver); |
Handle<PropertyCell> cell( |
global->GetPropertyCell(lookup), isolate()); |
+ // TODO(verwaest): Turn into a handler. |
return isolate()->stub_cache()->ComputeStoreGlobal( |
name, global, cell, value, strict_mode()); |
} |
ASSERT(holder.is_identical_to(receiver)); |
- return isolate()->stub_cache()->ComputeStoreNormal(strict_mode()); |
+ return strict_mode() == kStrictMode |
+ ? isolate()->builtins()->StoreIC_Normal_Strict() |
+ : isolate()->builtins()->StoreIC_Normal(); |
case CALLBACKS: { |
+ if (kind() == Code::KEYED_STORE_IC) break; |
Handle<Object> callback(lookup->GetCallbackObject(), isolate()); |
if (callback->IsExecutableAccessorInfo()) { |
Handle<ExecutableAccessorInfo> info = |
@@ -1672,8 +1643,7 @@ Handle<Code> StoreIC::CompileHandler(LookupResult* lookup, |
if (v8::ToCData<Address>(info->setter()) == 0) break; |
if (!holder->HasFastProperties()) break; |
if (!info->IsCompatibleReceiver(*receiver)) break; |
- return isolate()->stub_cache()->ComputeStoreCallback( |
- name, receiver, holder, info, strict_mode()); |
+ return compiler.CompileStoreCallback(receiver, holder, name, info); |
} else if (callback->IsAccessorPair()) { |
Handle<Object> setter( |
Handle<AccessorPair>::cast(callback)->setter(), isolate()); |
@@ -1684,12 +1654,11 @@ Handle<Code> StoreIC::CompileHandler(LookupResult* lookup, |
CallOptimization call_optimization(function); |
if (call_optimization.is_simple_api_call() && |
call_optimization.IsCompatibleReceiver(*receiver)) { |
- return isolate()->stub_cache()->ComputeStoreCallback( |
- name, receiver, holder, call_optimization, strict_mode()); |
+ return compiler.CompileStoreCallback( |
+ receiver, holder, name, call_optimization); |
} |
- return isolate()->stub_cache()->ComputeStoreViaSetter( |
- name, receiver, holder, Handle<JSFunction>::cast(setter), |
- strict_mode()); |
+ return compiler.CompileStoreViaSetter( |
+ receiver, holder, name, Handle<JSFunction>::cast(setter)); |
} |
// TODO(dcarney): Handle correctly. |
if (callback->IsDeclaredAccessorInfo()) break; |
@@ -1698,32 +1667,17 @@ Handle<Code> StoreIC::CompileHandler(LookupResult* lookup, |
break; |
} |
case INTERCEPTOR: |
+ if (kind() == Code::KEYED_STORE_IC) break; |
ASSERT(HasInterceptorSetter(*receiver)); |
- return isolate()->stub_cache()->ComputeStoreInterceptor( |
- name, receiver, strict_mode()); |
+ return compiler.CompileStoreInterceptor(receiver, name); |
case CONSTANT: |
break; |
- case TRANSITION: { |
- // Explicitly pass in the receiver map since LookupForWrite may have |
- // stored something else than the receiver in the holder. |
- Handle<Map> transition( |
- lookup->GetTransitionTarget(receiver->map()), isolate()); |
- int descriptor = transition->LastAdded(); |
- |
- DescriptorArray* target_descriptors = transition->instance_descriptors(); |
- PropertyDetails details = target_descriptors->GetDetails(descriptor); |
- |
- if (details.type() == CALLBACKS || details.attributes() != NONE) break; |
- |
- return isolate()->stub_cache()->ComputeStoreTransition( |
- name, receiver, lookup, transition, strict_mode()); |
- } |
case NONEXISTENT: |
case HANDLER: |
UNREACHABLE(); |
break; |
} |
- return Handle<Code>::null(); |
+ return slow_stub(); |
} |
@@ -2034,49 +1988,6 @@ MaybeObject* KeyedStoreIC::Store(Handle<Object> object, |
} |
-Handle<Code> KeyedStoreIC::CompileHandler(LookupResult* lookup, |
- Handle<JSObject> receiver, |
- Handle<String> name, |
- Handle<Object> value) { |
- // If the property has a non-field type allowing map transitions |
- // where there is extra room in the object, we leave the IC in its |
- // current state. |
- switch (lookup->type()) { |
- case FIELD: |
- return isolate()->stub_cache()->ComputeKeyedStoreField( |
- name, receiver, lookup, strict_mode()); |
- case TRANSITION: { |
- // Explicitly pass in the receiver map since LookupForWrite may have |
- // stored something else than the receiver in the holder. |
- Handle<Map> transition( |
- lookup->GetTransitionTarget(receiver->map()), isolate()); |
- int descriptor = transition->LastAdded(); |
- |
- DescriptorArray* target_descriptors = transition->instance_descriptors(); |
- PropertyDetails details = target_descriptors->GetDetails(descriptor); |
- |
- if (details.type() != CALLBACKS && details.attributes() == NONE) { |
- return isolate()->stub_cache()->ComputeKeyedStoreTransition( |
- name, receiver, lookup, transition, strict_mode()); |
- } |
- // fall through. |
- } |
- case NORMAL: |
- case CONSTANT: |
- case CALLBACKS: |
- case INTERCEPTOR: |
- // Always rewrite to the generic case so that we do not |
- // repeatedly try to rewrite. |
- return generic_stub(); |
- case HANDLER: |
- case NONEXISTENT: |
- UNREACHABLE(); |
- break; |
- } |
- return Handle<Code>::null(); |
-} |
- |
- |
#undef TRACE_IC |