| Index: src/ic/ic.cc
|
| diff --git a/src/ic/ic.cc b/src/ic/ic.cc
|
| index 05255522d0d5b809250318746b895d080236c94f..1de52b08c571fc929aed9b239bb3afec302a2501 100644
|
| --- a/src/ic/ic.cc
|
| +++ b/src/ic/ic.cc
|
| @@ -936,14 +936,28 @@ void IC::UpdateMegamorphicCache(Map* map, Name* name, Code* code) {
|
|
|
|
|
| Handle<Code> IC::ComputeHandler(LookupIterator* lookup, Handle<Object> value) {
|
| + // Try to find a globally shared handler stub.
|
| + Handle<Code> code = GetMapIndependentHandler(lookup);
|
| + if (!code.is_null()) return code;
|
| +
|
| + // Otherwise check the map's handler cache for a map-specific handler, and
|
| + // compile one if the cache comes up empty.
|
| bool receiver_is_holder =
|
| lookup->GetReceiver().is_identical_to(lookup->GetHolder<JSObject>());
|
| CacheHolderFlag flag;
|
| - Handle<Map> stub_holder_map = IC::GetHandlerCacheHolder(
|
| - receiver_map(), receiver_is_holder, isolate(), &flag);
|
| + Handle<Map> stub_holder_map;
|
| + if (kind() == Code::LOAD_IC || kind() == Code::KEYED_LOAD_IC) {
|
| + stub_holder_map = IC::GetHandlerCacheHolder(
|
| + receiver_map(), receiver_is_holder, isolate(), &flag);
|
| + } else {
|
| + DCHECK(kind() == Code::STORE_IC || kind() == Code::KEYED_STORE_IC);
|
| + // Store handlers cannot be cached on prototypes.
|
| + flag = kCacheOnReceiver;
|
| + stub_holder_map = receiver_map();
|
| + }
|
|
|
| - Handle<Code> code = PropertyHandlerCompiler::Find(
|
| - lookup->name(), stub_holder_map, kind(), flag);
|
| + code = PropertyHandlerCompiler::Find(lookup->name(), stub_holder_map, kind(),
|
| + flag);
|
| // Use the cached value if it exists, and if it is different from the
|
| // handler that just missed.
|
| if (!code.is_null()) {
|
| @@ -974,25 +988,13 @@ Handle<Code> IC::ComputeHandler(LookupIterator* lookup, Handle<Object> value) {
|
|
|
| code = CompileHandler(lookup, value, flag);
|
| DCHECK(code->is_handler());
|
| -
|
| - // TODO(mvstanton): we'd only like to cache code on the map when it's custom
|
| - // code compiled for this map, otherwise it's already cached in the global
|
| - // code cache. We are also guarding against installing code with flags that
|
| - // don't match the desired CacheHolderFlag computed above, which would lead to
|
| - // invalid lookups later.
|
| - bool is_normal = receiver_is_holder &&
|
| - !lookup->GetHolder<JSReceiver>()->HasFastProperties();
|
| - if (!is_normal && Code::ExtractCacheHolderFromFlags(code->flags()) == flag) {
|
| - Map::UpdateCodeCache(stub_holder_map, lookup->name(), code);
|
| - }
|
| + DCHECK(Code::ExtractCacheHolderFromFlags(code->flags()) == flag);
|
| + Map::UpdateCodeCache(stub_holder_map, lookup->name(), code);
|
|
|
| return code;
|
| }
|
|
|
| -
|
| -Handle<Code> LoadIC::CompileHandler(LookupIterator* lookup,
|
| - Handle<Object> unused,
|
| - CacheHolderFlag cache_holder) {
|
| +Handle<Code> LoadIC::GetMapIndependentHandler(LookupIterator* lookup) {
|
| Handle<Object> receiver = lookup->GetReceiver();
|
| if (receiver->IsString() &&
|
| Name::Equals(isolate()->factory()->length_string(), lookup->name())) {
|
| @@ -1024,17 +1026,8 @@ Handle<Code> LoadIC::CompileHandler(LookupIterator* lookup,
|
| Handle<JSObject> holder = lookup->GetHolder<JSObject>();
|
| bool receiver_is_holder = receiver.is_identical_to(holder);
|
| switch (lookup->state()) {
|
| - case LookupIterator::INTERCEPTOR: {
|
| - DCHECK(!holder->GetNamedInterceptor()->getter()->IsUndefined());
|
| - TRACE_HANDLER_STATS(isolate(), LoadIC_LoadInterceptor);
|
| - NamedLoadHandlerCompiler compiler(isolate(), map, 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);
|
| - }
|
| + case LookupIterator::INTERCEPTOR:
|
| + break; // Custom-compiled handler.
|
|
|
| case LookupIterator::ACCESSOR: {
|
| // Use simple field loads for some well-known callback properties.
|
| @@ -1057,73 +1050,59 @@ Handle<Code> LoadIC::CompileHandler(LookupIterator* lookup,
|
| if (IsCompatibleReceiver(lookup, map)) {
|
| Handle<Object> accessors = lookup->GetAccessors();
|
| if (accessors->IsAccessorPair()) {
|
| - if (!holder->HasFastProperties()) break;
|
| + if (!holder->HasFastProperties()) {
|
| + TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub);
|
| + return slow_stub();
|
| + }
|
| // When debugging we need to go the slow path to flood the accessor.
|
| - if (GetSharedFunctionInfo()->HasDebugInfo()) break;
|
| - Handle<Object> getter(Handle<AccessorPair>::cast(accessors)->getter(),
|
| - isolate());
|
| - CallOptimization call_optimization(getter);
|
| - NamedLoadHandlerCompiler compiler(isolate(), map, holder,
|
| - cache_holder);
|
| - if (call_optimization.is_simple_api_call()) {
|
| - TRACE_HANDLER_STATS(isolate(), LoadIC_LoadCallback);
|
| - int index = lookup->GetAccessorIndex();
|
| - return compiler.CompileLoadCallback(lookup->name(),
|
| - call_optimization, index);
|
| + if (GetSharedFunctionInfo()->HasDebugInfo()) {
|
| + TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub);
|
| + return slow_stub();
|
| }
|
| - TRACE_HANDLER_STATS(isolate(), LoadIC_LoadViaGetter);
|
| - int expected_arguments = Handle<JSFunction>::cast(getter)
|
| - ->shared()
|
| - ->internal_formal_parameter_count();
|
| - return compiler.CompileLoadViaGetter(
|
| - lookup->name(), lookup->GetAccessorIndex(), expected_arguments);
|
| + break; // Custom-compiled handler.
|
| } else if (accessors->IsAccessorInfo()) {
|
| Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(accessors);
|
| - if (v8::ToCData<Address>(info->getter()) == nullptr) break;
|
| - if (!AccessorInfo::IsCompatibleReceiverMap(isolate(), info, map)) {
|
| - // This case should be already handled in LoadIC::UpdateCaches.
|
| - UNREACHABLE();
|
| - break;
|
| + if (v8::ToCData<Address>(info->getter()) == nullptr) {
|
| + TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub);
|
| + return slow_stub();
|
| }
|
| - if (!holder->HasFastProperties()) break;
|
| + // Ruled out by IsCompatibleReceiver() above.
|
| + DCHECK(AccessorInfo::IsCompatibleReceiverMap(isolate(), info, map));
|
| + if (!holder->HasFastProperties()) return slow_stub();
|
| if (receiver_is_holder) {
|
| TRACE_HANDLER_STATS(isolate(), LoadIC_LoadApiGetterStub);
|
| int index = lookup->GetAccessorIndex();
|
| LoadApiGetterStub stub(isolate(), true, index);
|
| return stub.GetCode();
|
| }
|
| - if (info->is_sloppy() && !receiver->IsJSReceiver()) break;
|
| - TRACE_HANDLER_STATS(isolate(), LoadIC_LoadCallback);
|
| - NamedLoadHandlerCompiler compiler(isolate(), map, holder,
|
| - cache_holder);
|
| - return compiler.CompileLoadCallback(lookup->name(), info);
|
| + if (info->is_sloppy() && !receiver->IsJSReceiver()) {
|
| + TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub);
|
| + return slow_stub();
|
| + }
|
| + break; // Custom-compiled handler.
|
| }
|
| }
|
| - break;
|
| + TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub);
|
| + return slow_stub();
|
| }
|
|
|
| case LookupIterator::DATA: {
|
| if (lookup->is_dictionary_holder()) {
|
| - if (kind() != Code::LOAD_IC) break;
|
| + if (kind() != Code::LOAD_IC) {
|
| + TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub);
|
| + return slow_stub();
|
| + }
|
| if (holder->IsJSGlobalObject()) {
|
| - TRACE_HANDLER_STATS(isolate(), LoadIC_LoadGlobal);
|
| - NamedLoadHandlerCompiler compiler(isolate(), map, 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(map, receiver_is_holder, isolate(), &flag);
|
| - Map::UpdateCodeCache(stub_holder_map, lookup->name(), code);
|
| - return code;
|
| + break; // Custom-compiled handler.
|
| }
|
| // 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;
|
| + if (!receiver_is_holder) {
|
| + TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub);
|
| + return slow_stub();
|
| + }
|
| TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNormal);
|
| return isolate()->builtins()->LoadIC_Normal();
|
| }
|
| @@ -1134,9 +1113,7 @@ Handle<Code> LoadIC::CompileHandler(LookupIterator* lookup,
|
| if (receiver_is_holder) {
|
| return SimpleFieldLoad(field);
|
| }
|
| - TRACE_HANDLER_STATS(isolate(), LoadIC_LoadField);
|
| - NamedLoadHandlerCompiler compiler(isolate(), map, holder, cache_holder);
|
| - return compiler.CompileLoadField(lookup->name(), field);
|
| + break; // Custom-compiled handler.
|
| }
|
|
|
| // -------------- Constant properties --------------
|
| @@ -1146,6 +1123,128 @@ Handle<Code> LoadIC::CompileHandler(LookupIterator* lookup,
|
| LoadConstantStub stub(isolate(), lookup->GetConstantIndex());
|
| return stub.GetCode();
|
| }
|
| + break; // Custom-compiled handler.
|
| + }
|
| +
|
| + case LookupIterator::INTEGER_INDEXED_EXOTIC:
|
| + TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub);
|
| + return slow_stub();
|
| + case LookupIterator::ACCESS_CHECK:
|
| + case LookupIterator::JSPROXY:
|
| + case LookupIterator::NOT_FOUND:
|
| + case LookupIterator::TRANSITION:
|
| + UNREACHABLE();
|
| + }
|
| +
|
| + return Handle<Code>::null();
|
| +}
|
| +
|
| +Handle<Code> LoadIC::CompileHandler(LookupIterator* lookup,
|
| + Handle<Object> unused,
|
| + CacheHolderFlag cache_holder) {
|
| + Handle<JSObject> holder = lookup->GetHolder<JSObject>();
|
| +#ifdef DEBUG
|
| + // Only used by DCHECKs below.
|
| + Handle<Object> receiver = lookup->GetReceiver();
|
| + bool receiver_is_holder = receiver.is_identical_to(holder);
|
| +#endif
|
| + // Non-map-specific handler stubs have already been selected.
|
| + DCHECK(!receiver->IsString() ||
|
| + !Name::Equals(isolate()->factory()->length_string(), lookup->name()));
|
| + DCHECK(!receiver->IsStringWrapper() ||
|
| + !Name::Equals(isolate()->factory()->length_string(), lookup->name()));
|
| +
|
| + DCHECK(!(
|
| + receiver->IsJSFunction() &&
|
| + Name::Equals(isolate()->factory()->prototype_string(), lookup->name()) &&
|
| + receiver->IsConstructor() &&
|
| + !Handle<JSFunction>::cast(receiver)
|
| + ->map()
|
| + ->has_non_instance_prototype()));
|
| +
|
| + Handle<Map> map = receiver_map();
|
| + switch (lookup->state()) {
|
| + case LookupIterator::INTERCEPTOR: {
|
| + DCHECK(!holder->GetNamedInterceptor()->getter()->IsUndefined());
|
| + TRACE_HANDLER_STATS(isolate(), LoadIC_LoadInterceptor);
|
| + NamedLoadHandlerCompiler compiler(isolate(), map, 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);
|
| + }
|
| +
|
| + case LookupIterator::ACCESSOR: {
|
| +#ifdef DEBUG
|
| + int object_offset;
|
| + DCHECK(!Accessors::IsJSObjectFieldAccessor(map, lookup->name(),
|
| + &object_offset));
|
| + DCHECK(!Accessors::IsJSArrayBufferViewFieldAccessor(map, lookup->name(),
|
| + &object_offset));
|
| +#endif
|
| +
|
| + DCHECK(IsCompatibleReceiver(lookup, map));
|
| + Handle<Object> accessors = lookup->GetAccessors();
|
| + if (accessors->IsAccessorPair()) {
|
| + DCHECK(holder->HasFastProperties());
|
| + DCHECK(!GetSharedFunctionInfo()->HasDebugInfo());
|
| + Handle<Object> getter(Handle<AccessorPair>::cast(accessors)->getter(),
|
| + isolate());
|
| + CallOptimization call_optimization(getter);
|
| + NamedLoadHandlerCompiler compiler(isolate(), map, holder, cache_holder);
|
| + if (call_optimization.is_simple_api_call()) {
|
| + TRACE_HANDLER_STATS(isolate(), LoadIC_LoadCallback);
|
| + int index = lookup->GetAccessorIndex();
|
| + return compiler.CompileLoadCallback(lookup->name(), call_optimization,
|
| + index);
|
| + }
|
| + TRACE_HANDLER_STATS(isolate(), LoadIC_LoadViaGetter);
|
| + int expected_arguments = Handle<JSFunction>::cast(getter)
|
| + ->shared()
|
| + ->internal_formal_parameter_count();
|
| + return compiler.CompileLoadViaGetter(
|
| + lookup->name(), lookup->GetAccessorIndex(), expected_arguments);
|
| + } else {
|
| + DCHECK(accessors->IsAccessorInfo());
|
| + Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(accessors);
|
| + DCHECK(v8::ToCData<Address>(info->getter()) != nullptr);
|
| + DCHECK(AccessorInfo::IsCompatibleReceiverMap(isolate(), info, map));
|
| + DCHECK(holder->HasFastProperties());
|
| + DCHECK(!receiver_is_holder);
|
| + DCHECK(!info->is_sloppy() || receiver->IsJSReceiver());
|
| + TRACE_HANDLER_STATS(isolate(), LoadIC_LoadCallback);
|
| + NamedLoadHandlerCompiler compiler(isolate(), map, holder, cache_holder);
|
| + return compiler.CompileLoadCallback(lookup->name(), info);
|
| + }
|
| + UNREACHABLE();
|
| + }
|
| +
|
| + case LookupIterator::DATA: {
|
| + if (lookup->is_dictionary_holder()) {
|
| + DCHECK(kind() == Code::LOAD_IC);
|
| + DCHECK(holder->IsJSGlobalObject());
|
| + TRACE_HANDLER_STATS(isolate(), LoadIC_LoadGlobal);
|
| + NamedLoadHandlerCompiler compiler(isolate(), map, holder, cache_holder);
|
| + Handle<PropertyCell> cell = lookup->GetPropertyCell();
|
| + Handle<Code> code = compiler.CompileLoadGlobal(
|
| + cell, lookup->name(), lookup->IsConfigurable());
|
| + return code;
|
| + }
|
| +
|
| + // -------------- Fields --------------
|
| + if (lookup->property_details().type() == DATA) {
|
| + FieldIndex field = lookup->GetFieldIndex();
|
| + DCHECK(!receiver_is_holder);
|
| + TRACE_HANDLER_STATS(isolate(), LoadIC_LoadField);
|
| + NamedLoadHandlerCompiler compiler(isolate(), map, holder, cache_holder);
|
| + return compiler.CompileLoadField(lookup->name(), field);
|
| + }
|
| +
|
| + // -------------- Constant properties --------------
|
| + DCHECK(lookup->property_details().type() == DATA_CONSTANT);
|
| + DCHECK(!receiver_is_holder);
|
| TRACE_HANDLER_STATS(isolate(), LoadIC_LoadConstant);
|
| NamedLoadHandlerCompiler compiler(isolate(), map, holder, cache_holder);
|
| return compiler.CompileLoadConstant(lookup->name(),
|
| @@ -1153,15 +1252,13 @@ Handle<Code> LoadIC::CompileHandler(LookupIterator* lookup,
|
| }
|
|
|
| case LookupIterator::INTEGER_INDEXED_EXOTIC:
|
| - break;
|
| case LookupIterator::ACCESS_CHECK:
|
| case LookupIterator::JSPROXY:
|
| case LookupIterator::NOT_FOUND:
|
| case LookupIterator::TRANSITION:
|
| UNREACHABLE();
|
| }
|
| -
|
| - TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub);
|
| + UNREACHABLE();
|
| return slow_stub();
|
| }
|
|
|
| @@ -1513,10 +1610,7 @@ static Handle<Code> PropertyCellStoreHandler(
|
| return code;
|
| }
|
|
|
| -
|
| -Handle<Code> StoreIC::CompileHandler(LookupIterator* lookup,
|
| - Handle<Object> value,
|
| - CacheHolderFlag cache_holder) {
|
| +Handle<Code> StoreIC::GetMapIndependentHandler(LookupIterator* lookup) {
|
| DCHECK_NE(LookupIterator::JSPROXY, lookup->state());
|
|
|
| // This is currently guaranteed by checks in StoreIC::Store.
|
| @@ -1528,27 +1622,17 @@ Handle<Code> StoreIC::CompileHandler(LookupIterator* lookup,
|
| case LookupIterator::TRANSITION: {
|
| auto store_target = lookup->GetStoreTarget();
|
| if (store_target->IsJSGlobalObject()) {
|
| - // TODO(dcarney): this currently just deopts. Use the transition cell.
|
| - TRACE_HANDLER_STATS(isolate(), StoreIC_StoreGlobalTransition);
|
| - auto cell = isolate()->factory()->NewPropertyCell();
|
| - cell->set_value(*value);
|
| - auto code = PropertyCellStoreHandler(
|
| - isolate(), store_target, Handle<JSGlobalObject>::cast(store_target),
|
| - lookup->name(), cell, PropertyCellType::kConstant);
|
| - cell->set_value(isolate()->heap()->the_hole_value());
|
| - return code;
|
| + break; // Custom-compiled handler.
|
| }
|
| - Handle<Map> transition = lookup->transition_map();
|
| // Currently not handled by CompileStoreTransition.
|
| if (!holder->HasFastProperties()) {
|
| TRACE_GENERIC_IC(isolate(), "StoreIC", "transition from slow");
|
| - break;
|
| + TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
|
| + return slow_stub();
|
| }
|
|
|
| DCHECK(lookup->IsCacheableTransition());
|
| - TRACE_HANDLER_STATS(isolate(), StoreIC_StoreTransition);
|
| - NamedStoreHandlerCompiler compiler(isolate(), receiver_map(), holder);
|
| - return compiler.CompileStoreTransition(transition, lookup->name());
|
| + break; // Custom-compiled handler.
|
| }
|
|
|
| case LookupIterator::INTERCEPTOR: {
|
| @@ -1561,74 +1645,62 @@ Handle<Code> StoreIC::CompileHandler(LookupIterator* lookup,
|
| case LookupIterator::ACCESSOR: {
|
| if (!holder->HasFastProperties()) {
|
| TRACE_GENERIC_IC(isolate(), "StoreIC", "accessor on slow map");
|
| - break;
|
| + TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
|
| + return slow_stub();
|
| }
|
| Handle<Object> accessors = lookup->GetAccessors();
|
| if (accessors->IsAccessorInfo()) {
|
| Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(accessors);
|
| - if (v8::ToCData<Address>(info->setter()) == 0) {
|
| - TRACE_GENERIC_IC(isolate(), "StoreIC", "setter == 0");
|
| - break;
|
| + if (v8::ToCData<Address>(info->setter()) == nullptr) {
|
| + TRACE_GENERIC_IC(isolate(), "StoreIC", "setter == nullptr");
|
| + TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
|
| + return slow_stub();
|
| }
|
| if (AccessorInfo::cast(*accessors)->is_special_data_property() &&
|
| !lookup->HolderIsReceiverOrHiddenPrototype()) {
|
| TRACE_GENERIC_IC(isolate(), "StoreIC",
|
| "special data property in prototype chain");
|
| - break;
|
| + TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
|
| + return slow_stub();
|
| }
|
| if (!AccessorInfo::IsCompatibleReceiverMap(isolate(), info,
|
| receiver_map())) {
|
| TRACE_GENERIC_IC(isolate(), "StoreIC", "incompatible receiver type");
|
| - break;
|
| + TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
|
| + return slow_stub();
|
| }
|
| - if (info->is_sloppy() && !receiver->IsJSReceiver()) break;
|
| - TRACE_HANDLER_STATS(isolate(), StoreIC_StoreCallback);
|
| - NamedStoreHandlerCompiler compiler(isolate(), receiver_map(), holder);
|
| - return compiler.CompileStoreCallback(receiver, lookup->name(), info,
|
| - language_mode());
|
| + if (info->is_sloppy() && !receiver->IsJSReceiver()) {
|
| + TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
|
| + return slow_stub();
|
| + }
|
| + break; // Custom-compiled handler.
|
| } else if (accessors->IsAccessorPair()) {
|
| Handle<Object> setter(Handle<AccessorPair>::cast(accessors)->setter(),
|
| isolate());
|
| if (!setter->IsJSFunction() && !setter->IsFunctionTemplateInfo()) {
|
| TRACE_GENERIC_IC(isolate(), "StoreIC", "setter not a function");
|
| - break;
|
| + TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
|
| + return slow_stub();
|
| }
|
| CallOptimization call_optimization(setter);
|
| - NamedStoreHandlerCompiler compiler(isolate(), receiver_map(), holder);
|
| if (call_optimization.is_simple_api_call()) {
|
| if (call_optimization.IsCompatibleReceiver(receiver, holder)) {
|
| - TRACE_HANDLER_STATS(isolate(), StoreIC_StoreCallback);
|
| - return compiler.CompileStoreCallback(receiver, lookup->name(),
|
| - call_optimization,
|
| - lookup->GetAccessorIndex());
|
| + break; // Custom-compiled handler.
|
| }
|
| TRACE_GENERIC_IC(isolate(), "StoreIC", "incompatible receiver");
|
| - break;
|
| + TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
|
| + return slow_stub();
|
| }
|
| - TRACE_HANDLER_STATS(isolate(), StoreIC_StoreViaSetter);
|
| - int expected_arguments = JSFunction::cast(*setter)
|
| - ->shared()
|
| - ->internal_formal_parameter_count();
|
| - return compiler.CompileStoreViaSetter(receiver, lookup->name(),
|
| - lookup->GetAccessorIndex(),
|
| - expected_arguments);
|
| + break; // Custom-compiled handler.
|
| }
|
| - break;
|
| + TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
|
| + return slow_stub();
|
| }
|
|
|
| case LookupIterator::DATA: {
|
| if (lookup->is_dictionary_holder()) {
|
| if (holder->IsJSGlobalObject()) {
|
| - TRACE_HANDLER_STATS(isolate(), StoreIC_StoreGlobal);
|
| - DCHECK(holder.is_identical_to(receiver) ||
|
| - receiver->map()->prototype() == *holder);
|
| - auto cell = lookup->GetPropertyCell();
|
| - auto updated_type = PropertyCell::UpdatedType(
|
| - cell, value, lookup->property_details());
|
| - auto code = PropertyCellStoreHandler(
|
| - isolate(), receiver, Handle<JSGlobalObject>::cast(holder),
|
| - lookup->name(), cell, updated_type);
|
| - return code;
|
| + break; // Custom-compiled handler.
|
| }
|
| TRACE_HANDLER_STATS(isolate(), StoreIC_StoreNormal);
|
| DCHECK(holder.is_identical_to(receiver));
|
| @@ -1649,6 +1721,127 @@ Handle<Code> StoreIC::CompileHandler(LookupIterator* lookup,
|
| lookup->representation());
|
| return stub.GetCode();
|
| }
|
| + break; // Custom-compiled handler.
|
| + }
|
| +
|
| + // -------------- Constant properties --------------
|
| + DCHECK(lookup->property_details().type() == DATA_CONSTANT);
|
| + TRACE_GENERIC_IC(isolate(), "StoreIC", "constant property");
|
| + TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
|
| + return slow_stub();
|
| + }
|
| +
|
| + case LookupIterator::INTEGER_INDEXED_EXOTIC:
|
| + case LookupIterator::ACCESS_CHECK:
|
| + case LookupIterator::JSPROXY:
|
| + case LookupIterator::NOT_FOUND:
|
| + UNREACHABLE();
|
| + }
|
| + return Handle<Code>::null();
|
| +}
|
| +
|
| +Handle<Code> StoreIC::CompileHandler(LookupIterator* lookup,
|
| + Handle<Object> value,
|
| + CacheHolderFlag cache_holder) {
|
| + DCHECK_NE(LookupIterator::JSPROXY, lookup->state());
|
| +
|
| + // This is currently guaranteed by checks in StoreIC::Store.
|
| + Handle<JSObject> receiver = Handle<JSObject>::cast(lookup->GetReceiver());
|
| + Handle<JSObject> holder = lookup->GetHolder<JSObject>();
|
| + DCHECK(!receiver->IsAccessCheckNeeded() || lookup->name()->IsPrivate());
|
| +
|
| + switch (lookup->state()) {
|
| + case LookupIterator::TRANSITION: {
|
| + auto store_target = lookup->GetStoreTarget();
|
| + if (store_target->IsJSGlobalObject()) {
|
| + // TODO(dcarney): this currently just deopts. Use the transition cell.
|
| + TRACE_HANDLER_STATS(isolate(), StoreIC_StoreGlobalTransition);
|
| + auto cell = isolate()->factory()->NewPropertyCell();
|
| + cell->set_value(*value);
|
| + auto code = PropertyCellStoreHandler(
|
| + isolate(), store_target, Handle<JSGlobalObject>::cast(store_target),
|
| + lookup->name(), cell, PropertyCellType::kConstant);
|
| + cell->set_value(isolate()->heap()->the_hole_value());
|
| + return code;
|
| + }
|
| + Handle<Map> transition = lookup->transition_map();
|
| + // Currently not handled by CompileStoreTransition.
|
| + DCHECK(holder->HasFastProperties());
|
| +
|
| + DCHECK(lookup->IsCacheableTransition());
|
| + TRACE_HANDLER_STATS(isolate(), StoreIC_StoreTransition);
|
| + NamedStoreHandlerCompiler compiler(isolate(), receiver_map(), holder);
|
| + return compiler.CompileStoreTransition(transition, lookup->name());
|
| + }
|
| +
|
| + case LookupIterator::INTERCEPTOR:
|
| + UNREACHABLE();
|
| +
|
| + case LookupIterator::ACCESSOR: {
|
| + DCHECK(holder->HasFastProperties());
|
| + Handle<Object> accessors = lookup->GetAccessors();
|
| + if (accessors->IsAccessorInfo()) {
|
| + Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(accessors);
|
| + DCHECK(v8::ToCData<Address>(info->setter()) != 0);
|
| + DCHECK(!AccessorInfo::cast(*accessors)->is_special_data_property() ||
|
| + lookup->HolderIsReceiverOrHiddenPrototype());
|
| + DCHECK(AccessorInfo::IsCompatibleReceiverMap(isolate(), info,
|
| + receiver_map()));
|
| + DCHECK(!info->is_sloppy() || receiver->IsJSReceiver());
|
| + TRACE_HANDLER_STATS(isolate(), StoreIC_StoreCallback);
|
| + NamedStoreHandlerCompiler compiler(isolate(), receiver_map(), holder);
|
| + return compiler.CompileStoreCallback(receiver, lookup->name(), info,
|
| + language_mode());
|
| + } else {
|
| + DCHECK(accessors->IsAccessorPair());
|
| + Handle<Object> setter(Handle<AccessorPair>::cast(accessors)->setter(),
|
| + isolate());
|
| + DCHECK(setter->IsJSFunction() || setter->IsFunctionTemplateInfo());
|
| + CallOptimization call_optimization(setter);
|
| + NamedStoreHandlerCompiler compiler(isolate(), receiver_map(), holder);
|
| + if (call_optimization.is_simple_api_call()) {
|
| + DCHECK(call_optimization.IsCompatibleReceiver(receiver, holder));
|
| + TRACE_HANDLER_STATS(isolate(), StoreIC_StoreCallback);
|
| + return compiler.CompileStoreCallback(receiver, lookup->name(),
|
| + call_optimization,
|
| + lookup->GetAccessorIndex());
|
| + }
|
| + TRACE_HANDLER_STATS(isolate(), StoreIC_StoreViaSetter);
|
| + int expected_arguments = JSFunction::cast(*setter)
|
| + ->shared()
|
| + ->internal_formal_parameter_count();
|
| + return compiler.CompileStoreViaSetter(receiver, lookup->name(),
|
| + lookup->GetAccessorIndex(),
|
| + expected_arguments);
|
| + }
|
| + }
|
| +
|
| + case LookupIterator::DATA: {
|
| + if (lookup->is_dictionary_holder()) {
|
| + DCHECK(holder->IsJSGlobalObject());
|
| + TRACE_HANDLER_STATS(isolate(), StoreIC_StoreGlobal);
|
| + DCHECK(holder.is_identical_to(receiver) ||
|
| + receiver->map()->prototype() == *holder);
|
| + auto cell = lookup->GetPropertyCell();
|
| + auto updated_type =
|
| + PropertyCell::UpdatedType(cell, value, lookup->property_details());
|
| + auto code = PropertyCellStoreHandler(
|
| + isolate(), receiver, Handle<JSGlobalObject>::cast(holder),
|
| + lookup->name(), cell, updated_type);
|
| + return code;
|
| + }
|
| +
|
| + // -------------- Fields --------------
|
| + if (lookup->property_details().type() == DATA) {
|
| +#ifdef DEBUG
|
| + bool use_stub = true;
|
| + if (lookup->representation().IsHeapObject()) {
|
| + // Only use a generic stub if no types need to be tracked.
|
| + Handle<FieldType> field_type = lookup->GetFieldType();
|
| + use_stub = !field_type->IsClass();
|
| + }
|
| + DCHECK(!use_stub);
|
| +#endif
|
| TRACE_HANDLER_STATS(isolate(), StoreIC_StoreField);
|
| NamedStoreHandlerCompiler compiler(isolate(), receiver_map(), holder);
|
| return compiler.CompileStoreField(lookup);
|
| @@ -1656,8 +1849,7 @@ Handle<Code> StoreIC::CompileHandler(LookupIterator* lookup,
|
|
|
| // -------------- Constant properties --------------
|
| DCHECK(lookup->property_details().type() == DATA_CONSTANT);
|
| - TRACE_GENERIC_IC(isolate(), "StoreIC", "constant property");
|
| - break;
|
| + UNREACHABLE();
|
| }
|
|
|
| case LookupIterator::INTEGER_INDEXED_EXOTIC:
|
| @@ -1666,7 +1858,7 @@ Handle<Code> StoreIC::CompileHandler(LookupIterator* lookup,
|
| case LookupIterator::NOT_FOUND:
|
| UNREACHABLE();
|
| }
|
| - TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
|
| + UNREACHABLE();
|
| return slow_stub();
|
| }
|
|
|
|
|