| 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
|
|
|
|
|
|
|