Commit 9a0d5d97 authored by Toon Verwaest's avatar Toon Verwaest Committed by Commit Bot

[ic] Move handler construction code from ic to handler-configuration

Bug: 
Change-Id: I91b08ad6d95e60f84cb083b444bf0eb2fff10e27
Reviewed-on: https://chromium-review.googlesource.com/663864Reviewed-by: 's avatarIgor Sheludko <ishell@chromium.org>
Commit-Queue: Toon Verwaest <verwaest@chromium.org>
Cr-Commit-Position: refs/heads/master@{#47998}
parent 9c3dc33e
......@@ -10,6 +10,204 @@
namespace v8 {
namespace internal {
namespace {
template <bool fill_array = true>
int InitPrototypeChecks(Isolate* isolate, Handle<Map> receiver_map,
Handle<JSReceiver> holder, Handle<Name> name,
Handle<FixedArray> array, int first_index) {
if (!holder.is_null() && holder->map() == *receiver_map) return 0;
HandleScope scope(isolate);
int checks_count = 0;
if (receiver_map->IsPrimitiveMap() || receiver_map->IsJSGlobalProxyMap()) {
// The validity cell check for primitive and global proxy receivers does
// not guarantee that certain native context ever had access to other
// native context. However, a handler created for one native context could
// be used in other native context through the megamorphic stub cache.
// So we record the original native context to which this handler
// corresponds.
if (fill_array) {
Handle<Context> native_context = isolate->native_context();
array->set(first_index + checks_count, native_context->self_weak_cell());
}
checks_count++;
} else if (receiver_map->IsJSGlobalObjectMap()) {
// If we are creating a handler for [Load/Store]GlobalIC then we need to
// check that the property did not appear in the global object.
if (fill_array) {
Handle<JSGlobalObject> global = isolate->global_object();
Handle<PropertyCell> cell = JSGlobalObject::EnsureEmptyPropertyCell(
global, name, PropertyCellType::kInvalidated);
DCHECK(cell->value()->IsTheHole(isolate));
Handle<WeakCell> weak_cell = isolate->factory()->NewWeakCell(cell);
array->set(first_index + checks_count, *weak_cell);
}
checks_count++;
}
// Create/count entries for each global or dictionary prototype appeared in
// the prototype chain contains from receiver till holder.
PrototypeIterator::WhereToEnd end = name->IsPrivate()
? PrototypeIterator::END_AT_NON_HIDDEN
: PrototypeIterator::END_AT_NULL;
for (PrototypeIterator iter(receiver_map, end); !iter.IsAtEnd();
iter.Advance()) {
Handle<JSReceiver> current =
PrototypeIterator::GetCurrent<JSReceiver>(iter);
if (holder.is_identical_to(current)) break;
Handle<Map> current_map(current->map(), isolate);
if (current_map->IsJSGlobalObjectMap()) {
if (fill_array) {
Handle<JSGlobalObject> global = Handle<JSGlobalObject>::cast(current);
Handle<PropertyCell> cell = JSGlobalObject::EnsureEmptyPropertyCell(
global, name, PropertyCellType::kInvalidated);
DCHECK(cell->value()->IsTheHole(isolate));
Handle<WeakCell> weak_cell = isolate->factory()->NewWeakCell(cell);
array->set(first_index + checks_count, *weak_cell);
}
checks_count++;
} else if (current_map->is_dictionary_map()) {
DCHECK(!current_map->IsJSGlobalProxyMap()); // Proxy maps are fast.
if (fill_array) {
DCHECK_EQ(NameDictionary::kNotFound,
current->property_dictionary()->FindEntry(name));
Handle<WeakCell> weak_cell =
Map::GetOrCreatePrototypeWeakCell(current, isolate);
array->set(first_index + checks_count, *weak_cell);
}
checks_count++;
}
}
return checks_count;
}
// Returns 0 if the validity cell check is enough to ensure that the
// prototype chain from |receiver_map| till |holder| did not change.
// If the |holder| is an empty handle then the full prototype chain is
// checked.
// Returns -1 if the handler has to be compiled or the number of prototype
// checks otherwise.
int GetPrototypeCheckCount(Isolate* isolate, Handle<Map> receiver_map,
Handle<JSReceiver> holder, Handle<Name> name) {
return InitPrototypeChecks<false>(isolate, receiver_map, holder, name,
Handle<FixedArray>(), 0);
}
enum class HolderCellRequest {
kGlobalPropertyCell,
kHolder,
};
Handle<WeakCell> HolderCell(Isolate* isolate, Handle<JSReceiver> holder,
Handle<Name> name, HolderCellRequest request) {
if (request == HolderCellRequest::kGlobalPropertyCell) {
DCHECK(holder->IsJSGlobalObject());
Handle<JSGlobalObject> global = Handle<JSGlobalObject>::cast(holder);
GlobalDictionary* dict = global->global_dictionary();
int number = dict->FindEntry(name);
DCHECK_NE(NameDictionary::kNotFound, number);
Handle<PropertyCell> cell(dict->CellAt(number), isolate);
return isolate->factory()->NewWeakCell(cell);
}
return Map::GetOrCreatePrototypeWeakCell(holder, isolate);
}
} // namespace
// static
Handle<Object> LoadHandler::LoadFromPrototype(Isolate* isolate,
Handle<Map> receiver_map,
Handle<JSReceiver> holder,
Handle<Name> name,
Handle<Smi> smi_handler) {
int checks_count =
GetPrototypeCheckCount(isolate, receiver_map, holder, name);
DCHECK_LE(0, checks_count);
if (receiver_map->IsPrimitiveMap() ||
receiver_map->is_access_check_needed()) {
DCHECK(!receiver_map->is_dictionary_map());
DCHECK_LE(1, checks_count); // For native context.
smi_handler = EnableAccessCheckOnReceiver(isolate, smi_handler);
} else if (receiver_map->is_dictionary_map() &&
!receiver_map->IsJSGlobalObjectMap()) {
smi_handler = EnableLookupOnReceiver(isolate, smi_handler);
}
Handle<Cell> validity_cell =
Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate);
DCHECK(!validity_cell.is_null());
// LoadIC dispatcher expects PropertyCell as a "holder" in case of kGlobal
// handler kind.
HolderCellRequest request = GetHandlerKind(*smi_handler) == kGlobal
? HolderCellRequest::kGlobalPropertyCell
: HolderCellRequest::kHolder;
Handle<WeakCell> holder_cell = HolderCell(isolate, holder, name, request);
if (checks_count == 0) {
return isolate->factory()->NewTuple3(holder_cell, smi_handler,
validity_cell, TENURED);
}
Handle<FixedArray> handler_array(isolate->factory()->NewFixedArray(
kFirstPrototypeIndex + checks_count, TENURED));
handler_array->set(kSmiHandlerIndex, *smi_handler);
handler_array->set(kValidityCellIndex, *validity_cell);
handler_array->set(kHolderCellIndex, *holder_cell);
InitPrototypeChecks(isolate, receiver_map, holder, name, handler_array,
kFirstPrototypeIndex);
return handler_array;
}
// static
Handle<Object> LoadHandler::LoadFullChain(Isolate* isolate,
Handle<Map> receiver_map,
Handle<Object> holder,
Handle<Name> name,
Handle<Smi> smi_handler) {
Handle<JSReceiver> end; // null handle
int checks_count = GetPrototypeCheckCount(isolate, receiver_map, end, name);
DCHECK_LE(0, checks_count);
if (receiver_map->IsPrimitiveMap() ||
receiver_map->is_access_check_needed()) {
DCHECK(!receiver_map->is_dictionary_map());
DCHECK_LE(1, checks_count); // For native context.
smi_handler = EnableAccessCheckOnReceiver(isolate, smi_handler);
} else if (receiver_map->is_dictionary_map() &&
!receiver_map->IsJSGlobalObjectMap()) {
smi_handler = EnableLookupOnReceiver(isolate, smi_handler);
}
Handle<Object> validity_cell =
Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate);
if (validity_cell.is_null()) {
DCHECK_EQ(0, checks_count);
// Lookup on receiver isn't supported in case of a simple smi handler.
if (!LookupOnReceiverBits::decode(smi_handler->value())) return smi_handler;
validity_cell = handle(Smi::kZero, isolate);
}
Factory* factory = isolate->factory();
if (checks_count == 0) {
return factory->NewTuple3(holder, smi_handler, validity_cell, TENURED);
}
Handle<FixedArray> handler_array(factory->NewFixedArray(
LoadHandler::kFirstPrototypeIndex + checks_count, TENURED));
handler_array->set(kSmiHandlerIndex, *smi_handler);
handler_array->set(kValidityCellIndex, *validity_cell);
handler_array->set(kHolderCellIndex, *holder);
InitPrototypeChecks(isolate, receiver_map, end, name, handler_array,
kFirstPrototypeIndex);
return handler_array;
}
// |name| can be nullptr if no name/details check needs to be performed.
Object* StoreHandler::ValidTuple3HandlerOrNull(Object* handler, Name* name,
Handle<Map>* out_transition) {
......@@ -25,7 +223,7 @@ Object* StoreHandler::ValidTuple3HandlerOrNull(Object* handler, Name* name,
return nullptr;
}
// Step 2 (optional): Check transition key.
WeakCell* target_cell = StoreHandler::GetTuple3TransitionCell(handler);
WeakCell* target_cell = GetTuple3TransitionCell(handler);
if (name != nullptr) {
if (!TransitionsAccessor::IsMatchingMap(target_cell, name, kData, NONE)) {
return nullptr;
......@@ -38,6 +236,113 @@ Object* StoreHandler::ValidTuple3HandlerOrNull(Object* handler, Name* name,
return handler;
}
// static
Handle<Object> StoreHandler::StoreTransition(Isolate* isolate,
Handle<Map> receiver_map,
Handle<JSObject> holder,
Handle<Map> transition,
Handle<Name> name) {
Handle<Object> smi_handler;
if (transition->is_dictionary_map()) {
smi_handler = StoreNormal(isolate);
} else {
int descriptor = transition->LastAdded();
Handle<DescriptorArray> descriptors(transition->instance_descriptors());
PropertyDetails details = descriptors->GetDetails(descriptor);
Representation representation = details.representation();
DCHECK(!representation.IsNone());
// Declarative handlers don't support access checks.
DCHECK(!transition->is_access_check_needed());
DCHECK_EQ(kData, details.kind());
if (details.location() == kDescriptor) {
smi_handler = TransitionToConstant(isolate, descriptor);
} else {
DCHECK_EQ(kField, details.location());
bool extend_storage =
Map::cast(transition->GetBackPointer())->unused_property_fields() ==
0;
FieldIndex index = FieldIndex::ForDescriptor(*transition, descriptor);
smi_handler = TransitionToField(isolate, descriptor, index,
representation, extend_storage);
}
}
// |holder| is either a receiver if the property is non-existent or
// one of the prototypes.
DCHECK(!holder.is_null());
bool is_nonexistent = holder->map() == transition->GetBackPointer();
if (is_nonexistent) holder = Handle<JSObject>::null();
int checks_count =
GetPrototypeCheckCount(isolate, receiver_map, holder, name);
DCHECK_LE(0, checks_count);
DCHECK(!receiver_map->IsJSGlobalObjectMap());
Handle<Object> validity_cell =
Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate);
if (validity_cell.is_null()) {
DCHECK_EQ(0, checks_count);
validity_cell = handle(Smi::kZero, isolate);
}
Handle<WeakCell> transition_cell = Map::WeakCellForMap(transition);
Factory* factory = isolate->factory();
if (checks_count == 0) {
return factory->NewTuple3(transition_cell, smi_handler, validity_cell,
TENURED);
}
Handle<FixedArray> handler_array(
factory->NewFixedArray(kFirstPrototypeIndex + checks_count, TENURED));
handler_array->set(kSmiHandlerIndex, *smi_handler);
handler_array->set(kValidityCellIndex, *validity_cell);
handler_array->set(kTransitionCellIndex, *transition_cell);
InitPrototypeChecks(isolate, receiver_map, holder, name, handler_array,
kFirstPrototypeIndex);
return handler_array;
}
// static
Handle<Object> StoreHandler::StoreProxy(Isolate* isolate,
Handle<Map> receiver_map,
Handle<JSProxy> proxy,
Handle<JSReceiver> receiver,
Handle<Name> name) {
Handle<Object> smi_handler = StoreProxy(isolate);
if (receiver.is_identical_to(proxy)) return smi_handler;
int checks_count = GetPrototypeCheckCount(isolate, receiver_map, proxy, name);
DCHECK_LE(0, checks_count);
Handle<Object> validity_cell =
Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate);
if (validity_cell.is_null()) {
DCHECK_EQ(0, checks_count);
validity_cell = handle(Smi::kZero, isolate);
}
Factory* factory = isolate->factory();
Handle<WeakCell> holder_cell = factory->NewWeakCell(proxy);
if (checks_count == 0) {
return factory->NewTuple3(holder_cell, smi_handler, validity_cell, TENURED);
}
Handle<FixedArray> handler_array(
factory->NewFixedArray(kFirstPrototypeIndex + checks_count, TENURED));
handler_array->set(kSmiHandlerIndex, *smi_handler);
handler_array->set(kValidityCellIndex, *validity_cell);
handler_array->set(kTransitionCellIndex, *holder_cell);
InitPrototypeChecks(isolate, receiver_map, proxy, name, handler_array,
kFirstPrototypeIndex);
return handler_array;
}
Object* StoreHandler::ValidFixedArrayHandlerOrNull(
Object* raw_handler, Name* name, Handle<Map>* out_transition) {
DCHECK(raw_handler->IsFixedArray());
......@@ -46,7 +351,7 @@ Object* StoreHandler::ValidFixedArrayHandlerOrNull(
Object* value = Cell::cast(handler->get(kValidityCellIndex))->value();
if (value != Smi::FromInt(Map::kPrototypeChainValid)) return nullptr;
// Step 2: Check transition key.
WeakCell* target_cell = StoreHandler::GetArrayTransitionCell(handler);
WeakCell* target_cell = GetArrayTransitionCell(handler);
if (!TransitionsAccessor::IsMatchingMap(target_cell, name, kData, NONE)) {
return nullptr;
}
......
......@@ -132,15 +132,22 @@ class LoadHandler {
// dictionary.
static inline Handle<Smi> LoadModuleExport(Isolate* isolate, int index);
// Sets DoAccessCheckOnReceiverBits in given Smi-handler. The receiver
// check is a part of a prototype chain check.
static inline Handle<Smi> EnableAccessCheckOnReceiver(
Isolate* isolate, Handle<Smi> smi_handler);
// Sets LookupOnReceiverBits in given Smi-handler. The receiver
// check is a part of a prototype chain check.
static inline Handle<Smi> EnableLookupOnReceiver(Isolate* isolate,
Handle<Smi> smi_handler);
// Creates a data handler that represents a load of a non-existent property.
// {holder} is the object from which the property is loaded. If no holder is
// needed (e.g., for "nonexistent"), null_value() may be passed in.
static Handle<Object> LoadFullChain(Isolate* isolate,
Handle<Map> receiver_map,
Handle<Object> holder, Handle<Name> name,
Handle<Smi> smi_handler);
// Creates a data handler that represents a prototype chain check followed
// by given Smi-handler that encoded a load from the holder.
// Can be used only if GetPrototypeCheckCount() returns non negative value.
static Handle<Object> LoadFromPrototype(Isolate* isolate,
Handle<Map> receiver_map,
Handle<JSReceiver> holder,
Handle<Name> name,
Handle<Smi> smi_handler);
// Creates a Smi-handler for loading a non-existent property. Works only as
// a part of prototype chain check.
......@@ -151,6 +158,17 @@ class LoadHandler {
ElementsKind elements_kind,
bool convert_hole_to_undefined,
bool is_js_array);
private:
// Sets DoAccessCheckOnReceiverBits in given Smi-handler. The receiver
// check is a part of a prototype chain check.
static inline Handle<Smi> EnableAccessCheckOnReceiver(
Isolate* isolate, Handle<Smi> smi_handler);
// Sets LookupOnReceiverBits in given Smi-handler. The receiver
// check is a part of a prototype chain check.
static inline Handle<Smi> EnableLookupOnReceiver(Isolate* isolate,
Handle<Smi> smi_handler);
};
// A set of bit fields representing Smi handlers for stores.
......@@ -226,12 +244,29 @@ class StoreHandler {
PropertyConstness constness,
Representation representation);
static Handle<Object> StoreTransition(Isolate* isolate,
Handle<Map> receiver_map,
Handle<JSObject> holder,
Handle<Map> transition,
Handle<Name> name);
static Handle<Object> StoreProxy(Isolate* isolate, Handle<Map> receiver_map,
Handle<JSProxy> proxy,
Handle<JSReceiver> receiver,
Handle<Name> name);
// Creates a Smi-handler for storing a property to a slow object.
static inline Handle<Smi> StoreNormal(Isolate* isolate);
// Creates a Smi-handler for storing a property on a proxy.
static inline Handle<Smi> StoreProxy(Isolate* isolate);
private:
static inline Handle<Smi> StoreField(Isolate* isolate, Kind kind,
int descriptor, FieldIndex field_index,
Representation representation,
bool extend_storage);
// Creates a Smi-handler for transitioning store to a field.
static inline Handle<Smi> TransitionToField(Isolate* isolate, int descriptor,
FieldIndex field_index,
......@@ -242,12 +277,6 @@ class StoreHandler {
// case the only thing that needs to be done is an update of a map).
static inline Handle<Smi> TransitionToConstant(Isolate* isolate,
int descriptor);
private:
static inline Handle<Smi> StoreField(Isolate* isolate, Kind kind,
int descriptor, FieldIndex field_index,
Representation representation,
bool extend_storage);
};
} // namespace internal
......
......@@ -647,204 +647,6 @@ Handle<Smi> LoadIC::SimpleFieldLoad(Isolate* isolate, FieldIndex index) {
return LoadHandler::LoadField(isolate, index);
}
namespace {
template <bool fill_array = true>
int InitPrototypeChecks(Isolate* isolate, Handle<Map> receiver_map,
Handle<JSReceiver> holder, Handle<Name> name,
Handle<FixedArray> array, int first_index) {
if (!holder.is_null() && holder->map() == *receiver_map) return 0;
HandleScope scope(isolate);
int checks_count = 0;
if (receiver_map->IsPrimitiveMap() || receiver_map->IsJSGlobalProxyMap()) {
// The validity cell check for primitive and global proxy receivers does
// not guarantee that certain native context ever had access to other
// native context. However, a handler created for one native context could
// be used in other native context through the megamorphic stub cache.
// So we record the original native context to which this handler
// corresponds.
if (fill_array) {
Handle<Context> native_context = isolate->native_context();
array->set(first_index + checks_count, native_context->self_weak_cell());
}
checks_count++;
} else if (receiver_map->IsJSGlobalObjectMap()) {
// If we are creating a handler for [Load/Store]GlobalIC then we need to
// check that the property did not appear in the global object.
if (fill_array) {
Handle<JSGlobalObject> global = isolate->global_object();
Handle<PropertyCell> cell = JSGlobalObject::EnsureEmptyPropertyCell(
global, name, PropertyCellType::kInvalidated);
DCHECK(cell->value()->IsTheHole(isolate));
Handle<WeakCell> weak_cell = isolate->factory()->NewWeakCell(cell);
array->set(first_index + checks_count, *weak_cell);
}
checks_count++;
}
// Create/count entries for each global or dictionary prototype appeared in
// the prototype chain contains from receiver till holder.
PrototypeIterator::WhereToEnd end = name->IsPrivate()
? PrototypeIterator::END_AT_NON_HIDDEN
: PrototypeIterator::END_AT_NULL;
for (PrototypeIterator iter(receiver_map, end); !iter.IsAtEnd();
iter.Advance()) {
Handle<JSReceiver> current =
PrototypeIterator::GetCurrent<JSReceiver>(iter);
if (holder.is_identical_to(current)) break;
Handle<Map> current_map(current->map(), isolate);
if (current_map->IsJSGlobalObjectMap()) {
if (fill_array) {
Handle<JSGlobalObject> global = Handle<JSGlobalObject>::cast(current);
Handle<PropertyCell> cell = JSGlobalObject::EnsureEmptyPropertyCell(
global, name, PropertyCellType::kInvalidated);
DCHECK(cell->value()->IsTheHole(isolate));
Handle<WeakCell> weak_cell = isolate->factory()->NewWeakCell(cell);
array->set(first_index + checks_count, *weak_cell);
}
checks_count++;
} else if (current_map->is_dictionary_map()) {
DCHECK(!current_map->IsJSGlobalProxyMap()); // Proxy maps are fast.
if (fill_array) {
DCHECK_EQ(NameDictionary::kNotFound,
current->property_dictionary()->FindEntry(name));
Handle<WeakCell> weak_cell =
Map::GetOrCreatePrototypeWeakCell(current, isolate);
array->set(first_index + checks_count, *weak_cell);
}
checks_count++;
}
}
return checks_count;
}
// Returns 0 if the validity cell check is enough to ensure that the
// prototype chain from |receiver_map| till |holder| did not change.
// If the |holder| is an empty handle then the full prototype chain is
// checked.
// Returns -1 if the handler has to be compiled or the number of prototype
// checks otherwise.
int GetPrototypeCheckCount(Isolate* isolate, Handle<Map> receiver_map,
Handle<JSReceiver> holder, Handle<Name> name) {
return InitPrototypeChecks<false>(isolate, receiver_map, holder, name,
Handle<FixedArray>(), 0);
}
enum class HolderCellRequest {
kGlobalPropertyCell,
kHolder,
};
Handle<WeakCell> HolderCell(Isolate* isolate, Handle<JSReceiver> holder,
Handle<Name> name, HolderCellRequest request) {
if (request == HolderCellRequest::kGlobalPropertyCell) {
DCHECK(holder->IsJSGlobalObject());
Handle<JSGlobalObject> global = Handle<JSGlobalObject>::cast(holder);
GlobalDictionary* dict = global->global_dictionary();
int number = dict->FindEntry(name);
DCHECK_NE(NameDictionary::kNotFound, number);
Handle<PropertyCell> cell(dict->CellAt(number), isolate);
return isolate->factory()->NewWeakCell(cell);
}
return Map::GetOrCreatePrototypeWeakCell(holder, isolate);
}
} // namespace
Handle<Object> LoadIC::LoadFromPrototype(Handle<Map> receiver_map,
Handle<JSReceiver> holder,
Handle<Name> name,
Handle<Smi> smi_handler) {
int checks_count =
GetPrototypeCheckCount(isolate(), receiver_map, holder, name);
DCHECK_LE(0, checks_count);
if (receiver_map->IsPrimitiveMap() ||
receiver_map->is_access_check_needed()) {
DCHECK(!receiver_map->is_dictionary_map());
DCHECK_LE(1, checks_count); // For native context.
smi_handler =
LoadHandler::EnableAccessCheckOnReceiver(isolate(), smi_handler);
} else if (receiver_map->is_dictionary_map() &&
!receiver_map->IsJSGlobalObjectMap()) {
smi_handler = LoadHandler::EnableLookupOnReceiver(isolate(), smi_handler);
}
Handle<Cell> validity_cell =
Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate());
DCHECK(!validity_cell.is_null());
// LoadIC dispatcher expects PropertyCell as a "holder" in case of kGlobal
// handler kind.
HolderCellRequest request =
LoadHandler::GetHandlerKind(*smi_handler) == LoadHandler::kGlobal
? HolderCellRequest::kGlobalPropertyCell
: HolderCellRequest::kHolder;
Handle<WeakCell> holder_cell = HolderCell(isolate(), holder, name, request);
if (checks_count == 0) {
return isolate()->factory()->NewTuple3(holder_cell, smi_handler,
validity_cell, TENURED);
}
Handle<FixedArray> handler_array(isolate()->factory()->NewFixedArray(
LoadHandler::kFirstPrototypeIndex + checks_count, TENURED));
handler_array->set(LoadHandler::kSmiHandlerIndex, *smi_handler);
handler_array->set(LoadHandler::kValidityCellIndex, *validity_cell);
handler_array->set(LoadHandler::kHolderCellIndex, *holder_cell);
InitPrototypeChecks(isolate(), receiver_map, holder, name, handler_array,
LoadHandler::kFirstPrototypeIndex);
return handler_array;
}
Handle<Object> LoadIC::LoadFullChain(Handle<Map> receiver_map,
Handle<Object> holder, Handle<Name> name,
Handle<Smi> smi_handler) {
Handle<JSReceiver> end; // null handle
int checks_count = GetPrototypeCheckCount(isolate(), receiver_map, end, name);
DCHECK_LE(0, checks_count);
if (receiver_map->IsPrimitiveMap() ||
receiver_map->is_access_check_needed()) {
DCHECK(!receiver_map->is_dictionary_map());
DCHECK_LE(1, checks_count); // For native context.
smi_handler =
LoadHandler::EnableAccessCheckOnReceiver(isolate(), smi_handler);
} else if (receiver_map->is_dictionary_map() &&
!receiver_map->IsJSGlobalObjectMap()) {
smi_handler = LoadHandler::EnableLookupOnReceiver(isolate(), smi_handler);
}
Handle<Object> validity_cell =
Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate());
if (validity_cell.is_null()) {
DCHECK_EQ(0, checks_count);
// Lookup on receiver isn't supported in case of a simple smi handler.
if (!LoadHandler::LookupOnReceiverBits::decode(smi_handler->value())) {
return smi_handler;
}
validity_cell = handle(Smi::kZero, isolate());
}
Factory* factory = isolate()->factory();
if (checks_count == 0) {
return factory->NewTuple3(holder, smi_handler, validity_cell, TENURED);
}
Handle<FixedArray> handler_array(factory->NewFixedArray(
LoadHandler::kFirstPrototypeIndex + checks_count, TENURED));
handler_array->set(LoadHandler::kSmiHandlerIndex, *smi_handler);
handler_array->set(LoadHandler::kValidityCellIndex, *validity_cell);
handler_array->set(LoadHandler::kHolderCellIndex, *holder);
InitPrototypeChecks(isolate(), receiver_map, end, name, handler_array,
LoadHandler::kFirstPrototypeIndex);
return handler_array;
}
void LoadIC::UpdateCaches(LookupIterator* lookup) {
if (state() == UNINITIALIZED && !IsLoadGlobalIC()) {
// This is the first time we execute this inline cache. Set the target to
......@@ -861,8 +663,9 @@ void LoadIC::UpdateCaches(LookupIterator* lookup) {
} else if (!lookup->IsFound()) {
TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNonexistentDH);
Handle<Smi> smi_handler = LoadHandler::LoadNonExistent(isolate());
code = LoadFullChain(receiver_map(), isolate()->factory()->null_value(),
lookup->name(), smi_handler);
code = LoadHandler::LoadFullChain(isolate(), receiver_map(),
isolate()->factory()->null_value(),
lookup->name(), smi_handler);
} else {
if (IsLoadGlobalIC()) {
if (lookup->TryLookupCachedProperty()) {
......@@ -997,7 +800,8 @@ Handle<Object> LoadIC::GetMapIndependentHandler(LookupIterator* lookup) {
holder_ref = Map::GetOrCreatePrototypeWeakCell(holder, isolate());
}
TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNonMaskingInterceptorDH);
return LoadFullChain(map, holder_ref, lookup->name(), smi_handler);
return LoadHandler::LoadFullChain(isolate(), map, holder_ref,
lookup->name(), smi_handler);
}
if (receiver_is_holder) {
......@@ -1007,7 +811,8 @@ Handle<Object> LoadIC::GetMapIndependentHandler(LookupIterator* lookup) {
}
TRACE_HANDLER_STATS(isolate(), LoadIC_LoadInterceptorFromPrototypeDH);
return LoadFromPrototype(map, holder, lookup->name(), smi_handler);
return LoadHandler::LoadFromPrototype(isolate(), map, holder,
lookup->name(), smi_handler);
}
case LookupIterator::ACCESSOR: {
......@@ -1094,7 +899,8 @@ Handle<Object> LoadIC::GetMapIndependentHandler(LookupIterator* lookup) {
TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNormalFromPrototypeDH);
}
return LoadFromPrototype(map, holder, lookup->name(), smi_handler);
return LoadHandler::LoadFromPrototype(isolate(), map, holder,
lookup->name(), smi_handler);
}
Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(accessors);
......@@ -1112,7 +918,8 @@ Handle<Object> LoadIC::GetMapIndependentHandler(LookupIterator* lookup) {
TRACE_HANDLER_STATS(isolate(), LoadIC_LoadApiGetterDH);
if (receiver_is_holder) return smi_handler;
TRACE_HANDLER_STATS(isolate(), LoadIC_LoadApiGetterFromPrototypeDH);
return LoadFromPrototype(map, holder, lookup->name(), smi_handler);
return LoadHandler::LoadFromPrototype(isolate(), map, holder,
lookup->name(), smi_handler);
}
case LookupIterator::DATA: {
......@@ -1126,7 +933,8 @@ Handle<Object> LoadIC::GetMapIndependentHandler(LookupIterator* lookup) {
// global object.
TRACE_HANDLER_STATS(isolate(), LoadIC_LoadGlobalDH);
smi_handler = LoadHandler::LoadGlobal(isolate());
return LoadFromPrototype(map, holder, lookup->name(), smi_handler);
return LoadHandler::LoadFromPrototype(isolate(), map, holder,
lookup->name(), smi_handler);
}
DCHECK(!holder->IsJSGlobalObject());
TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNormalDH);
......@@ -1153,7 +961,8 @@ Handle<Object> LoadIC::GetMapIndependentHandler(LookupIterator* lookup) {
if (receiver_is_holder) return smi_handler;
TRACE_HANDLER_STATS(isolate(), LoadIC_LoadConstantFromPrototypeDH);
}
return LoadFromPrototype(map, holder, lookup->name(), smi_handler);
return LoadHandler::LoadFromPrototype(isolate(), map, holder,
lookup->name(), smi_handler);
}
case LookupIterator::INTEGER_INDEXED_EXOTIC:
TRACE_HANDLER_STATS(isolate(), LoadIC_LoadIntegerIndexedExoticDH);
......@@ -1165,7 +974,8 @@ Handle<Object> LoadIC::GetMapIndependentHandler(LookupIterator* lookup) {
if (receiver_is_holder_proxy) {
return smi_handler;
}
return LoadFromPrototype(map, holder_proxy, lookup->name(), smi_handler);
return LoadHandler::LoadFromPrototype(isolate(), map, holder_proxy,
lookup->name(), smi_handler);
}
case LookupIterator::ACCESS_CHECK:
case LookupIterator::NOT_FOUND:
......@@ -1596,112 +1406,6 @@ void StoreIC::UpdateCaches(LookupIterator* lookup, Handle<Object> value,
TRACE_IC("StoreIC", lookup->name());
}
Handle<Object> StoreIC::StoreTransition(Handle<Map> receiver_map,
Handle<JSObject> holder,
Handle<Map> transition,
Handle<Name> name) {
Handle<Object> smi_handler;
if (transition->is_dictionary_map()) {
smi_handler = StoreHandler::StoreNormal(isolate());
} else {
int descriptor = transition->LastAdded();
Handle<DescriptorArray> descriptors(transition->instance_descriptors());
PropertyDetails details = descriptors->GetDetails(descriptor);
Representation representation = details.representation();
DCHECK(!representation.IsNone());
// Declarative handlers don't support access checks.
DCHECK(!transition->is_access_check_needed());
DCHECK_EQ(kData, details.kind());
if (details.location() == kDescriptor) {
smi_handler = StoreHandler::TransitionToConstant(isolate(), descriptor);
} else {
DCHECK_EQ(kField, details.location());
bool extend_storage =
Map::cast(transition->GetBackPointer())->unused_property_fields() ==
0;
FieldIndex index = FieldIndex::ForDescriptor(*transition, descriptor);
smi_handler = StoreHandler::TransitionToField(
isolate(), descriptor, index, representation, extend_storage);
}
}
// |holder| is either a receiver if the property is non-existent or
// one of the prototypes.
DCHECK(!holder.is_null());
bool is_nonexistent = holder->map() == transition->GetBackPointer();
if (is_nonexistent) holder = Handle<JSObject>::null();
int checks_count =
GetPrototypeCheckCount(isolate(), receiver_map, holder, name);
DCHECK_LE(0, checks_count);
DCHECK(!receiver_map->IsJSGlobalObjectMap());
Handle<Object> validity_cell =
Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate());
if (validity_cell.is_null()) {
DCHECK_EQ(0, checks_count);
validity_cell = handle(Smi::kZero, isolate());
}
Handle<WeakCell> transition_cell = Map::WeakCellForMap(transition);
Factory* factory = isolate()->factory();
if (checks_count == 0) {
return factory->NewTuple3(transition_cell, smi_handler, validity_cell,
TENURED);
}
Handle<FixedArray> handler_array(factory->NewFixedArray(
StoreHandler::kFirstPrototypeIndex + checks_count, TENURED));
handler_array->set(StoreHandler::kSmiHandlerIndex, *smi_handler);
handler_array->set(StoreHandler::kValidityCellIndex, *validity_cell);
handler_array->set(StoreHandler::kTransitionCellIndex, *transition_cell);
InitPrototypeChecks(isolate(), receiver_map, holder, name, handler_array,
StoreHandler::kFirstPrototypeIndex);
return handler_array;
}
Handle<Object> StoreIC::StoreProxy(Handle<Map> receiver_map,
Handle<JSProxy> proxy,
Handle<JSReceiver> receiver,
Handle<Name> name) {
Handle<Object> smi_handler = StoreHandler::StoreProxy(isolate());
if (receiver.is_identical_to(proxy)) {
return smi_handler;
}
int checks_count =
GetPrototypeCheckCount(isolate(), receiver_map, proxy, name);
DCHECK_LE(0, checks_count);
Handle<Object> validity_cell =
Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate());
if (validity_cell.is_null()) {
DCHECK_EQ(0, checks_count);
validity_cell = handle(Smi::kZero, isolate());
}
Factory* factory = isolate()->factory();
Handle<WeakCell> holder_cell = factory->NewWeakCell(proxy);
if (checks_count == 0) {
return factory->NewTuple3(holder_cell, smi_handler, validity_cell, TENURED);
}
Handle<FixedArray> handler_array(factory->NewFixedArray(
StoreHandler::kFirstPrototypeIndex + checks_count, TENURED));
handler_array->set(StoreHandler::kSmiHandlerIndex, *smi_handler);
handler_array->set(StoreHandler::kValidityCellIndex, *validity_cell);
handler_array->set(StoreHandler::kTransitionCellIndex, *holder_cell);
InitPrototypeChecks(isolate(), receiver_map, proxy, name, handler_array,
StoreHandler::kFirstPrototypeIndex);
return handler_array;
}
namespace {
Handle<Object> StoreGlobal(Isolate* isolate, Handle<PropertyCell> cell) {
......@@ -1730,8 +1434,8 @@ Handle<Object> StoreIC::GetMapIndependentHandler(LookupIterator* lookup) {
DCHECK(lookup->IsCacheableTransition());
Handle<Map> transition = lookup->transition_map();
TRACE_HANDLER_STATS(isolate(), StoreIC_StoreTransitionDH);
Handle<Object> handler =
StoreTransition(receiver_map(), holder, transition, lookup->name());
Handle<Object> handler = StoreHandler::StoreTransition(
isolate(), receiver_map(), holder, transition, lookup->name());
TransitionsAccessor(receiver_map())
.UpdateHandler(*lookup->name(), *handler);
return handler;
......@@ -1845,8 +1549,8 @@ Handle<Object> StoreIC::GetMapIndependentHandler(LookupIterator* lookup) {
Handle<JSReceiver> receiver =
Handle<JSReceiver>::cast(lookup->GetReceiver());
Handle<JSProxy> holder = lookup->GetHolder<JSProxy>();
return StoreIC::StoreProxy(receiver_map(), holder, receiver,
lookup->name());
return StoreHandler::StoreProxy(isolate(), receiver_map(), holder,
receiver, lookup->name());
}
case LookupIterator::INTEGER_INDEXED_EXOTIC:
......
......@@ -271,19 +271,6 @@ class LoadIC : public IC {
// Creates a data handler that represents a load of a field by given index.
static Handle<Smi> SimpleFieldLoad(Isolate* isolate, FieldIndex index);
// Creates a data handler that represents a prototype chain check followed
// by given Smi-handler that encoded a load from the holder.
// Can be used only if GetPrototypeCheckCount() returns non negative value.
Handle<Object> LoadFromPrototype(Handle<Map> receiver_map,
Handle<JSReceiver> holder, Handle<Name> name,
Handle<Smi> smi_handler);
// Creates a data handler that represents a load of a non-existent property.
// {holder} is the object from which the property is loaded. If no holder is
// needed (e.g., for "nonexistent"), null_value() may be passed in.
Handle<Object> LoadFullChain(Handle<Map> receiver_map, Handle<Object> holder,
Handle<Name> name, Handle<Smi> smi_handler);
friend class IC;
friend class NamedLoadHandlerCompiler;
};
......@@ -360,13 +347,6 @@ class StoreIC : public IC {
Handle<Code> CompileHandler(LookupIterator* lookup) override;
private:
Handle<Object> StoreTransition(Handle<Map> receiver_map,
Handle<JSObject> holder,
Handle<Map> transition, Handle<Name> name);
Handle<Object> StoreProxy(Handle<Map> receiver_map, Handle<JSProxy> proxy,
Handle<JSReceiver> receiver, Handle<Name> name);
friend class IC;
bool created_new_transition_ = false;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment