Commit ccca1739 authored by Igor Sheludko's avatar Igor Sheludko Committed by Commit Bot

[ic] Use Load/StoreHandlerStruct objects instead of Tuple3/FixedArray.

This CL also removes LoadICProtoArray* builtins which are no longer necessary.

Bug: v8:7206, v8:5561
Change-Id: Ic5d9a3d4d21c4bd5e5e1cd110bd029ced157a000
Reviewed-on: https://chromium-review.googlesource.com/819252
Commit-Queue: Igor Sheludko <ishell@chromium.org>
Reviewed-by: 's avatarToon Verwaest <verwaest@chromium.org>
Cr-Commit-Position: refs/heads/master@{#50104}
parent 674402ff
......@@ -45,8 +45,6 @@ const Register LoadDescriptor::SlotRegister() { return r0; }
const Register LoadWithVectorDescriptor::VectorRegister() { return r3; }
const Register LoadICProtoArrayDescriptor::HandlerRegister() { return r4; }
const Register StoreDescriptor::ReceiverRegister() { return r1; }
const Register StoreDescriptor::NameRegister() { return r2; }
const Register StoreDescriptor::ValueRegister() { return r0; }
......
......@@ -45,8 +45,6 @@ const Register LoadDescriptor::SlotRegister() { return x0; }
const Register LoadWithVectorDescriptor::VectorRegister() { return x3; }
const Register LoadICProtoArrayDescriptor::HandlerRegister() { return x4; }
const Register StoreDescriptor::ReceiverRegister() { return x1; }
const Register StoreDescriptor::NameRegister() { return x2; }
const Register StoreDescriptor::ValueRegister() { return x0; }
......
......@@ -199,8 +199,6 @@ namespace internal {
TFC(ToBooleanLazyDeoptContinuation, TypeConversionStackParameter, 1) \
\
/* Handlers */ \
TFH(LoadICProtoArray, LoadICProtoArray) \
TFH(LoadICProtoArrayThrowIfNonexistent, LoadICProtoArray) \
TFH(KeyedLoadIC_Megamorphic, LoadWithVector) \
TFH(KeyedLoadIC_Miss, LoadWithVector) \
TFH(KeyedLoadIC_PolymorphicName, LoadWithVector) \
......
......@@ -42,8 +42,6 @@ IC_BUILTIN_PARAM(LoadGlobalICTrampoline, LoadGlobalICTrampoline,
NOT_INSIDE_TYPEOF)
IC_BUILTIN_PARAM(LoadGlobalICInsideTypeofTrampoline, LoadGlobalICTrampoline,
INSIDE_TYPEOF)
IC_BUILTIN_PARAM(LoadICProtoArray, LoadICProtoArray, false)
IC_BUILTIN_PARAM(LoadICProtoArrayThrowIfNonexistent, LoadICProtoArray, true)
} // namespace internal
} // namespace v8
......@@ -29,16 +29,6 @@ Handle<Code> CodeFactory::RuntimeCEntry(Isolate* isolate, int result_size) {
return stub.GetCode();
}
// static
Callable CodeFactory::LoadICProtoArray(Isolate* isolate,
bool throw_if_nonexistent) {
return Callable(
throw_if_nonexistent
? BUILTIN_CODE(isolate, LoadICProtoArrayThrowIfNonexistent)
: BUILTIN_CODE(isolate, LoadICProtoArray),
LoadICProtoArrayDescriptor(isolate));
}
// static
Callable CodeFactory::ApiGetter(Isolate* isolate) {
CallApiGetterStub stub(isolate);
......
......@@ -24,7 +24,6 @@ class V8_EXPORT_PRIVATE CodeFactory final {
static Handle<Code> RuntimeCEntry(Isolate* isolate, int result_size = 1);
// Initial states for ICs.
static Callable LoadICProtoArray(Isolate* isolate, bool throw_if_nonexistent);
static Callable LoadGlobalIC(Isolate* isolate, TypeofMode typeof_mode);
static Callable LoadGlobalICInOptimizedCode(Isolate* isolate,
TypeofMode typeof_mode);
......
......@@ -957,10 +957,11 @@ KeyedAccessStoreMode KeyedStoreICNexus::GetKeyedAccessStoreMode() const {
for (const Handle<Object>& maybe_code_handler : handlers) {
// The first handler that isn't the slow handler will have the bits we need.
Handle<Code> handler;
if (maybe_code_handler->IsTuple3()) {
if (maybe_code_handler->IsStoreHandler()) {
// Elements transition.
Handle<Tuple3> data_handler = Handle<Tuple3>::cast(maybe_code_handler);
handler = handle(Code::cast(data_handler->value2()));
Handle<StoreHandler> data_handler =
Handle<StoreHandler>::cast(maybe_code_handler);
handler = handle(Code::cast(data_handler->smi_handler()));
} else if (maybe_code_handler->IsTuple2()) {
// Element store with prototype chain check.
Handle<Tuple2> data_handler = Handle<Tuple2>::cast(maybe_code_handler);
......
......@@ -44,8 +44,6 @@ const Register LoadDescriptor::SlotRegister() { return eax; }
const Register LoadWithVectorDescriptor::VectorRegister() { return ebx; }
const Register LoadICProtoArrayDescriptor::HandlerRegister() { return edi; }
const Register StoreDescriptor::ReceiverRegister() { return edx; }
const Register StoreDescriptor::NameRegister() { return ecx; }
const Register StoreDescriptor::ValueRegister() { return eax; }
......
......@@ -128,7 +128,7 @@ void AccessorAssembler::HandlePolymorphicCase(Node* receiver_map,
void AccessorAssembler::HandleLoadICHandlerCase(
const LoadICParameters* p, Node* handler, Label* miss,
ExitPoint* exit_point, ElementSupport support_elements) {
ExitPoint* exit_point, ICMode ic_mode, ElementSupport support_elements) {
Comment("have_handler");
VARIABLE(var_holder, MachineRepresentation::kTagged, p->receiver);
......@@ -153,7 +153,8 @@ void AccessorAssembler::HandleLoadICHandlerCase(
{
GotoIf(IsCodeMap(LoadMap(handler)), &call_handler);
HandleLoadICProtoHandlerCase(p, handler, &var_holder, &var_smi_handler,
&if_smi_handler, miss, exit_point, false);
&if_smi_handler, miss, exit_point, false,
ic_mode);
}
BIND(&call_handler);
......@@ -541,18 +542,11 @@ void AccessorAssembler::HandleLoadICSmiHandlerCase(
void AccessorAssembler::HandleLoadICProtoHandlerCase(
const LoadICParameters* p, Node* handler, Variable* var_holder,
Variable* var_smi_handler, Label* if_smi_handler, Label* miss,
ExitPoint* exit_point, bool throw_reference_error_if_nonexistent) {
ExitPoint* exit_point, bool throw_reference_error_if_nonexistent,
ICMode ic_mode) {
DCHECK_EQ(MachineRepresentation::kTagged, var_holder->rep());
DCHECK_EQ(MachineRepresentation::kTagged, var_smi_handler->rep());
// IC dispatchers rely on these assumptions to be held.
STATIC_ASSERT(FixedArray::kLengthOffset == LoadHandler::kDataOffset);
DCHECK_EQ(FixedArray::OffsetOfElementAt(LoadHandler::kSmiHandlerIndex),
LoadHandler::kSmiHandlerOffset);
DCHECK_EQ(FixedArray::OffsetOfElementAt(LoadHandler::kValidityCellIndex),
LoadHandler::kValidityCellOffset);
// Both FixedArray and Tuple3 handlers have validity cell at the same offset.
Label validity_cell_check_done(this);
Node* validity_cell =
LoadObjectField(handler, LoadHandler::kValidityCellOffset);
......@@ -568,131 +562,72 @@ void AccessorAssembler::HandleLoadICProtoHandlerCase(
CSA_ASSERT(this, TaggedIsSmi(smi_handler));
Node* handler_flags = SmiUntag(smi_handler);
Label check_prototypes(this);
GotoIfNot(IsSetWord<LoadHandler::LookupOnReceiverBits>(handler_flags),
&check_prototypes);
{
CSA_ASSERT(this, Word32BinaryNot(
HasInstanceType(p->receiver, JS_GLOBAL_OBJECT_TYPE)));
Node* properties = LoadSlowProperties(p->receiver);
VARIABLE(var_name_index, MachineType::PointerRepresentation());
Label found(this, &var_name_index);
NameDictionaryLookup<NameDictionary>(properties, p->name, &found,
&var_name_index, &check_prototypes);
BIND(&found);
{
VARIABLE(var_details, MachineRepresentation::kWord32);
VARIABLE(var_value, MachineRepresentation::kTagged);
LoadPropertyFromNameDictionary(properties, var_name_index.value(),
&var_details, &var_value);
Node* value = CallGetterIfAccessor(var_value.value(), var_details.value(),
p->context, p->receiver, miss);
exit_point->Return(value);
}
}
BIND(&check_prototypes);
Node* maybe_holder_cell = LoadObjectField(handler, LoadHandler::kDataOffset);
Label array_handler(this), tuple_handler(this);
Branch(TaggedIsSmi(maybe_holder_cell), &array_handler, &tuple_handler);
BIND(&tuple_handler);
{
Label load_from_cached_holder(this), done(this);
// Lookup on receiver and access checks are not necessary for global ICs
// because in the former case the validity cell check guards modifications
// of the global object and the latter is not applicable to the global object.
int mask = LoadHandler::LookupOnReceiverBits::kMask |
LoadHandler::DoAccessCheckOnReceiverBits::kMask;
if (ic_mode == ICMode::kGlobalIC) {
CSA_ASSERT(this, IsClearWord(handler_flags, mask));
Branch(IsNull(maybe_holder_cell), &done, &load_from_cached_holder);
} else {
DCHECK_EQ(ICMode::kNonGlobalIC, ic_mode);
Label do_load(this), if_do_access_check(this), if_lookup_on_receiver(this);
GotoIf(IsClearWord(handler_flags, mask), &do_load);
// Only one of the bits can be set at a time.
CSA_ASSERT(this, WordNotEqual(WordAnd(handler_flags, IntPtrConstant(mask)),
IntPtrConstant(mask)));
if (ic_mode == ICMode::kGlobalIC) {
Goto(&if_do_access_check);
} else {
DCHECK_EQ(ICMode::kNonGlobalIC, ic_mode);
Branch(IsSetWord<LoadHandler::DoAccessCheckOnReceiverBits>(handler_flags),
&if_do_access_check, &if_lookup_on_receiver);
}
BIND(&load_from_cached_holder);
BIND(&if_do_access_check);
{
Label unwrap_cell(this), bind_holder(this);
Branch(IsWeakCell(maybe_holder_cell), &unwrap_cell, &bind_holder);
BIND(&unwrap_cell);
{
// For regular holders, having passed the receiver map check and the
// validity cell check implies that |holder| is alive. However, for
// global object receivers, the |maybe_holder_cell| may be cleared.
Node* holder = LoadWeakCellValue(maybe_holder_cell, miss);
Node* data2 = LoadObjectField(handler, LoadHandler::kData2Offset);
Node* expected_native_context = LoadWeakCellValue(data2, miss);
EmitAccessCheck(expected_native_context, p->context, p->receiver,
&do_load, miss);
}
var_holder->Bind(holder);
Goto(&done);
}
// Lookups on receiver are not necessary for LoadGlobalIC.
BIND(&if_lookup_on_receiver);
{
DCHECK_EQ(ICMode::kNonGlobalIC, ic_mode);
CSA_ASSERT(this, Word32BinaryNot(HasInstanceType(p->receiver,
JS_GLOBAL_OBJECT_TYPE)));
BIND(&bind_holder);
Node* properties = LoadSlowProperties(p->receiver);
VARIABLE(var_name_index, MachineType::PointerRepresentation());
Label found(this, &var_name_index);
NameDictionaryLookup<NameDictionary>(properties, p->name, &found,
&var_name_index, &do_load);
BIND(&found);
{
var_holder->Bind(maybe_holder_cell);
Goto(&done);
VARIABLE(var_details, MachineRepresentation::kWord32);
VARIABLE(var_value, MachineRepresentation::kTagged);
LoadPropertyFromNameDictionary(properties, var_name_index.value(),
&var_details, &var_value);
Node* value =
CallGetterIfAccessor(var_value.value(), var_details.value(),
p->context, p->receiver, miss);
exit_point->Return(value);
}
}
BIND(&done);
var_smi_handler->Bind(smi_handler);
Goto(if_smi_handler);
}
BIND(&array_handler);
{
exit_point->ReturnCallStub(
CodeFactory::LoadICProtoArray(isolate(),
throw_reference_error_if_nonexistent),
p->context, p->receiver, p->name, p->slot, p->vector, handler);
BIND(&do_load);
}
}
void AccessorAssembler::EmitAccessCheck(Node* expected_native_context,
Node* context, Node* receiver,
Label* can_access, Label* miss) {
CSA_ASSERT(this, IsNativeContext(expected_native_context));
Node* maybe_holder_cell = LoadObjectField(handler, LoadHandler::kData1Offset);
Node* native_context = LoadNativeContext(context);
GotoIf(WordEqual(expected_native_context, native_context), can_access);
// If the receiver is not a JSGlobalProxy then we miss.
GotoIfNot(IsJSGlobalProxy(receiver), miss);
// For JSGlobalProxy receiver try to compare security tokens of current
// and expected native contexts.
Node* expected_token = LoadContextElement(expected_native_context,
Context::SECURITY_TOKEN_INDEX);
Node* current_token =
LoadContextElement(native_context, Context::SECURITY_TOKEN_INDEX);
Branch(WordEqual(expected_token, current_token), can_access, miss);
}
Label load_from_cached_holder(this), done(this);
Node* AccessorAssembler::EmitLoadICProtoArrayCheck(const LoadICParameters* p,
Node* handler,
Node* handler_length,
Node* handler_flags,
Label* miss) {
VARIABLE(var_start_index, MachineType::PointerRepresentation(),
IntPtrConstant(LoadHandler::kFirstPrototypeIndex));
Label can_access(this);
GotoIfNot(IsSetWord<LoadHandler::DoAccessCheckOnReceiverBits>(handler_flags),
&can_access);
{
// Skip this entry of a handler.
var_start_index.Bind(IntPtrConstant(LoadHandler::kFirstPrototypeIndex + 1));
int offset =
FixedArray::OffsetOfElementAt(LoadHandler::kFirstPrototypeIndex);
Node* expected_native_context =
LoadWeakCellValue(LoadObjectField(handler, offset), miss);
EmitAccessCheck(expected_native_context, p->context, p->receiver,
&can_access, miss);
}
BIND(&can_access);
// TODO(ishell): Use LoadHandler with data2 field instead of FixedArray
// handlers.
CSA_ASSERT(this, WordEqual(var_start_index.value(), handler_length));
Node* maybe_holder_cell =
LoadFixedArrayElement(handler, LoadHandler::kDataIndex);
VARIABLE(var_holder, MachineRepresentation::kTagged, p->receiver);
Label done(this);
GotoIf(IsNull(maybe_holder_cell), &done);
Branch(IsNull(maybe_holder_cell), &done, &load_from_cached_holder);
BIND(&load_from_cached_holder);
{
Label unwrap_cell(this), bind_holder(this);
Branch(IsWeakCell(maybe_holder_cell), &unwrap_cell, &bind_holder);
......@@ -704,19 +639,38 @@ Node* AccessorAssembler::EmitLoadICProtoArrayCheck(const LoadICParameters* p,
// global object receivers, the |maybe_holder_cell| may be cleared.
Node* holder = LoadWeakCellValue(maybe_holder_cell, miss);
var_holder.Bind(holder);
var_holder->Bind(holder);
Goto(&done);
}
BIND(&bind_holder);
{
var_holder.Bind(maybe_holder_cell);
var_holder->Bind(maybe_holder_cell);
Goto(&done);
}
}
BIND(&done);
return var_holder.value();
var_smi_handler->Bind(smi_handler);
Goto(if_smi_handler);
}
void AccessorAssembler::EmitAccessCheck(Node* expected_native_context,
Node* context, Node* receiver,
Label* can_access, Label* miss) {
CSA_ASSERT(this, IsNativeContext(expected_native_context));
Node* native_context = LoadNativeContext(context);
GotoIf(WordEqual(expected_native_context, native_context), can_access);
// If the receiver is not a JSGlobalProxy then we miss.
GotoIfNot(IsJSGlobalProxy(receiver), miss);
// For JSGlobalProxy receiver try to compare security tokens of current
// and expected native contexts.
Node* expected_token = LoadContextElement(expected_native_context,
Context::SECURITY_TOKEN_INDEX);
Node* current_token =
LoadContextElement(native_context, Context::SECURITY_TOKEN_INDEX);
Branch(WordEqual(expected_token, current_token), can_access, miss);
}
void AccessorAssembler::HandleLoadGlobalICHandlerCase(
......@@ -732,9 +686,9 @@ void AccessorAssembler::HandleLoadGlobalICHandlerCase(
VARIABLE(var_smi_handler, MachineRepresentation::kTagged);
Label if_smi_handler(this);
HandleLoadICProtoHandlerCase(&p, handler, &var_holder, &var_smi_handler,
&if_smi_handler, miss, exit_point,
throw_reference_error_if_nonexistent);
HandleLoadICProtoHandlerCase(
&p, handler, &var_holder, &var_smi_handler, &if_smi_handler, miss,
exit_point, throw_reference_error_if_nonexistent, ICMode::kGlobalIC);
BIND(&if_smi_handler);
HandleLoadICSmiHandlerCase(
&p, var_holder.value(), var_smi_handler.value(), miss, exit_point,
......@@ -911,14 +865,6 @@ void AccessorAssembler::HandleStoreICProtoHandler(
ElementSupport support_elements) {
Comment("HandleStoreICProtoHandler");
// IC dispatchers rely on these assumptions to be held.
STATIC_ASSERT(FixedArray::kLengthOffset == StoreHandler::kDataOffset);
DCHECK_EQ(FixedArray::OffsetOfElementAt(StoreHandler::kSmiHandlerIndex),
StoreHandler::kSmiHandlerOffset);
DCHECK_EQ(FixedArray::OffsetOfElementAt(StoreHandler::kValidityCellIndex),
StoreHandler::kValidityCellOffset);
// Both FixedArray and Tuple3 handlers have validity cell at the same offset.
Label validity_cell_check_done(this);
Node* validity_cell =
LoadObjectField(handler, StoreHandler::kValidityCellOffset);
......@@ -932,60 +878,32 @@ void AccessorAssembler::HandleStoreICProtoHandler(
BIND(&validity_cell_check_done);
Node* smi_or_code = LoadObjectField(handler, StoreHandler::kSmiHandlerOffset);
Node* maybe_transition_cell =
LoadObjectField(handler, StoreHandler::kDataOffset);
Label array_handler(this), do_store(this);
VARIABLE(var_transition_map_or_holder, MachineRepresentation::kTagged,
maybe_transition_cell);
Label do_store(this);
GotoIfNot(TaggedIsSmi(smi_or_code), &do_store);
Branch(TaggedIsSmi(maybe_transition_cell), &array_handler, &do_store);
BIND(&array_handler);
Label if_do_access_check(this);
{
VARIABLE(var_start_index, MachineType::PointerRepresentation(),
IntPtrConstant(StoreHandler::kFirstPrototypeIndex));
Comment("array_handler");
Label can_access(this);
// Only Tuple3 handlers are allowed to have code handlers.
CSA_ASSERT(this, TaggedIsSmi(smi_or_code));
GotoIfNot(
IsSetSmi(smi_or_code, StoreHandler::DoAccessCheckOnReceiverBits::kMask),
&can_access);
{
// Skip this entry of a handler.
var_start_index.Bind(
IntPtrConstant(StoreHandler::kFirstPrototypeIndex + 1));
int offset =
FixedArray::OffsetOfElementAt(StoreHandler::kFirstPrototypeIndex);
Node* expected_native_context =
LoadWeakCellValue(LoadObjectField(handler, offset), miss);
EmitAccessCheck(expected_native_context, p->context, p->receiver,
&can_access, miss);
}
BIND(&can_access);
// TODO(ishell): Use StoreHandler with data2 field instead of FixedArray
// handlers.
Node* length = SmiUntag(maybe_transition_cell);
CSA_ASSERT(this, WordEqual(var_start_index.value(), length));
USE(length);
Node* handler_flags = SmiUntag(smi_or_code);
Branch(IsSetWord<StoreHandler::DoAccessCheckOnReceiverBits>(handler_flags),
&if_do_access_check, &do_store);
}
BIND(&if_do_access_check);
{
Node* data2 = LoadObjectField(handler, StoreHandler::kData2Offset);
Node* expected_native_context = LoadWeakCellValue(data2, miss);
Node* maybe_transition_cell =
LoadFixedArrayElement(handler, StoreHandler::kDataIndex);
var_transition_map_or_holder.Bind(maybe_transition_cell);
Goto(&do_store);
EmitAccessCheck(expected_native_context, p->context, p->receiver, &do_store,
miss);
}
VARIABLE(var_transition_map_or_holder, MachineRepresentation::kTagged);
Label if_transition_map(this), if_holder_object(this);
BIND(&do_store);
{
Node* maybe_transition_cell = var_transition_map_or_holder.value();
Node* maybe_transition_cell =
LoadObjectField(handler, StoreHandler::kData1Offset);
var_transition_map_or_holder.Bind(maybe_transition_cell);
Label unwrap_cell(this);
Branch(IsWeakCell(maybe_transition_cell), &unwrap_cell, &if_holder_object);
......@@ -2329,34 +2247,6 @@ void AccessorAssembler::LoadIC_Uninitialized(const LoadICParameters* p) {
}
}
void AccessorAssembler::LoadICProtoArray(
const LoadICParameters* p, Node* handler,
bool throw_reference_error_if_nonexistent) {
Label miss(this);
CSA_ASSERT(this, Word32BinaryNot(TaggedIsSmi(handler)));
CSA_ASSERT(this, IsFixedArrayMap(LoadMap(handler)));
ExitPoint direct_exit(this);
Node* smi_handler = LoadObjectField(handler, LoadHandler::kSmiHandlerOffset);
Node* handler_flags = SmiUntag(smi_handler);
Node* handler_length = LoadAndUntagFixedArrayBaseLength(handler);
Node* holder = EmitLoadICProtoArrayCheck(p, handler, handler_length,
handler_flags, &miss);
HandleLoadICSmiHandlerCase(p, holder, smi_handler, &miss, &direct_exit,
throw_reference_error_if_nonexistent,
kOnlyProperties);
BIND(&miss);
{
TailCallRuntime(Runtime::kLoadIC_Miss, p->context, p->receiver, p->name,
p->slot, p->vector);
}
}
void AccessorAssembler::LoadGlobalIC_TryPropertyCellCase(
Node* vector, Node* slot, ExitPoint* exit_point, Label* try_handler,
Label* miss, ParameterMode slot_mode) {
......@@ -2464,7 +2354,7 @@ void AccessorAssembler::KeyedLoadIC(const LoadICParameters* p) {
BIND(&if_handler);
{
HandleLoadICHandlerCase(p, var_handler.value(), &miss, &direct_exit,
kSupportElements);
ICMode::kNonGlobalIC, kSupportElements);
}
BIND(&try_polymorphic);
......@@ -2634,7 +2524,7 @@ void AccessorAssembler::KeyedLoadICPolymorphicName(const LoadICParameters* p) {
{
ExitPoint direct_exit(this);
HandleLoadICHandlerCase(p, var_handler.value(), &miss, &direct_exit,
kOnlyProperties);
ICMode::kNonGlobalIC, kOnlyProperties);
}
BIND(&miss);
......@@ -2936,21 +2826,6 @@ void AccessorAssembler::GenerateLoadICTrampoline() {
TailCallBuiltin(Builtins::kLoadIC, context, receiver, name, slot, vector);
}
void AccessorAssembler::GenerateLoadICProtoArray(
bool throw_reference_error_if_nonexistent) {
typedef LoadICProtoArrayDescriptor Descriptor;
Node* receiver = Parameter(Descriptor::kReceiver);
Node* name = Parameter(Descriptor::kName);
Node* slot = Parameter(Descriptor::kSlot);
Node* vector = Parameter(Descriptor::kVector);
Node* handler = Parameter(Descriptor::kHandler);
Node* context = Parameter(Descriptor::kContext);
LoadICParameters p(context, receiver, name, slot, vector);
LoadICProtoArray(&p, handler, throw_reference_error_if_nonexistent);
}
void AccessorAssembler::GenerateLoadField() {
typedef LoadFieldDescriptor Descriptor;
......
......@@ -37,8 +37,6 @@ class AccessorAssembler : public CodeStubAssembler {
void GenerateStoreGlobalIC();
void GenerateStoreGlobalICTrampoline();
void GenerateLoadICProtoArray(bool throw_reference_error_if_nonexistent);
void GenerateLoadGlobalIC(TypeofMode typeof_mode);
void GenerateLoadGlobalICTrampoline(TypeofMode typeof_mode);
......@@ -116,8 +114,6 @@ class AccessorAssembler : public CodeStubAssembler {
Node* LoadDescriptorValue(Node* map, Node* descriptor);
void LoadIC_Uninitialized(const LoadICParameters* p);
void LoadICProtoArray(const LoadICParameters* p, Node* handler,
bool throw_reference_error_if_nonexistent);
void LoadGlobalIC(const LoadICParameters* p, TypeofMode typeof_mode);
void KeyedLoadIC(const LoadICParameters* p);
void KeyedLoadICGeneric(const LoadICParameters* p);
......@@ -140,9 +136,11 @@ class AccessorAssembler : public CodeStubAssembler {
// LoadIC implementation.
enum class ICMode { kNonGlobalIC, kGlobalIC };
void HandleLoadICHandlerCase(
const LoadICParameters* p, Node* handler, Label* miss,
ExitPoint* exit_point, ElementSupport support_elements = kOnlyProperties);
ExitPoint* exit_point, ICMode ic_mode = ICMode::kNonGlobalIC,
ElementSupport support_elements = kOnlyProperties);
void HandleLoadICSmiHandlerCase(const LoadICParameters* p, Node* holder,
Node* smi_handler, Label* miss,
......@@ -155,7 +153,8 @@ class AccessorAssembler : public CodeStubAssembler {
Variable* var_smi_handler,
Label* if_smi_handler, Label* miss,
ExitPoint* exit_point,
bool throw_reference_error_if_nonexistent);
bool throw_reference_error_if_nonexistent,
ICMode ic_mode);
void HandleLoadField(Node* holder, Node* handler_word,
Variable* var_double_value, Label* rebox_double,
......@@ -164,10 +163,6 @@ class AccessorAssembler : public CodeStubAssembler {
void EmitAccessCheck(Node* expected_native_context, Node* context,
Node* receiver, Label* can_access, Label* miss);
Node* EmitLoadICProtoArrayCheck(const LoadICParameters* p, Node* handler,
Node* handler_length, Node* handler_flags,
Label* miss);
// LoadGlobalIC implementation.
void HandleLoadGlobalICHandlerCase(const LoadICParameters* p, Node* handler,
......
......@@ -240,22 +240,15 @@ Handle<Smi> StoreHandler::StoreApiSetter(Isolate* isolate,
// static
WeakCell* StoreHandler::GetTransitionCell(Object* handler) {
if (handler->IsTuple3()) {
STATIC_ASSERT(kDataOffset == Tuple3::kValue1Offset);
WeakCell* cell = WeakCell::cast(Tuple3::cast(handler)->value1());
DCHECK(!cell->cleared());
return cell;
}
DCHECK(handler->IsFixedArrayExact());
WeakCell* cell = WeakCell::cast(FixedArray::cast(handler)->get(kDataIndex));
DCHECK(handler->IsStoreHandler());
WeakCell* cell = WeakCell::cast(StoreHandler::cast(handler)->data1());
DCHECK(!cell->cleared());
return cell;
}
// static
bool StoreHandler::IsHandler(Object* maybe_handler) {
return maybe_handler->IsFixedArrayExact() || maybe_handler->IsTuple3();
return maybe_handler->IsStoreHandler();
}
} // namespace internal
......
......@@ -16,7 +16,7 @@ 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) {
Handle<DataHandler> handler) {
if (!holder.is_null() && holder->map() == *receiver_map) return 0;
HandleScope scope(isolate);
......@@ -31,7 +31,7 @@ int InitPrototypeChecks(Isolate* isolate, Handle<Map> receiver_map,
// corresponds.
if (fill_array) {
Handle<Context> native_context = isolate->native_context();
array->set(first_index + checks_count, native_context->self_weak_cell());
handler->set_data2(native_context->self_weak_cell());
}
checks_count++;
}
......@@ -47,7 +47,7 @@ int InitPrototypeChecks(Isolate* isolate, Handle<Map> receiver_map,
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);
Handle<DataHandler>());
}
} // namespace
......@@ -62,11 +62,12 @@ Handle<Object> LoadHandler::LoadFromPrototype(Isolate* isolate,
int checks_count =
GetPrototypeCheckCount(isolate, receiver_map, holder, name);
DCHECK_LE(0, checks_count);
DCHECK_LE(checks_count, 1);
if (receiver_map->IsPrimitiveMap() ||
receiver_map->is_access_check_needed()) {
DCHECK(!receiver_map->is_dictionary_map());
DCHECK_LE(1, checks_count); // For native context.
DCHECK_EQ(1, checks_count); // For native context.
smi_handler = EnableAccessCheckOnReceiver(isolate, smi_handler);
} else if (receiver_map->is_dictionary_map() &&
!receiver_map->IsJSGlobalObjectMap()) {
......@@ -82,18 +83,14 @@ Handle<Object> LoadHandler::LoadFromPrototype(Isolate* isolate,
data = Map::GetOrCreatePrototypeWeakCell(holder, isolate);
}
if (checks_count == 0) {
return isolate->factory()->NewTuple3(data, 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(kDataIndex, *data);
InitPrototypeChecks(isolate, receiver_map, holder, name, handler_array,
kFirstPrototypeIndex);
return handler_array;
int data_count = 1 + checks_count;
Handle<LoadHandler> handler = isolate->factory()->NewLoadHandler(data_count);
handler->set_smi_handler(*smi_handler);
handler->set_validity_cell(*validity_cell);
handler->set_data1(*data);
InitPrototypeChecks(isolate, receiver_map, holder, name, handler);
return handler;
}
// static
......@@ -105,11 +102,12 @@ Handle<Object> LoadHandler::LoadFullChain(Isolate* isolate,
Handle<JSReceiver> end; // null handle
int checks_count = GetPrototypeCheckCount(isolate, receiver_map, end, name);
DCHECK_LE(0, checks_count);
DCHECK_LE(checks_count, 1);
if (receiver_map->IsPrimitiveMap() ||
receiver_map->is_access_check_needed()) {
DCHECK(!receiver_map->is_dictionary_map());
DCHECK_LE(1, checks_count); // For native context.
DCHECK_EQ(1, checks_count); // For native context.
smi_handler = EnableAccessCheckOnReceiver(isolate, smi_handler);
} else if (receiver_map->is_dictionary_map() &&
!receiver_map->IsJSGlobalObjectMap()) {
......@@ -125,18 +123,14 @@ Handle<Object> LoadHandler::LoadFullChain(Isolate* isolate,
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(kDataIndex, *holder);
InitPrototypeChecks(isolate, receiver_map, end, name, handler_array,
kFirstPrototypeIndex);
return handler_array;
int data_count = 1 + checks_count;
Handle<LoadHandler> handler = isolate->factory()->NewLoadHandler(data_count);
handler->set_smi_handler(*smi_handler);
handler->set_validity_cell(*validity_cell);
handler->set_data1(*holder);
InitPrototypeChecks(isolate, receiver_map, end, name, handler);
return handler;
}
// static
......@@ -169,7 +163,11 @@ Handle<Object> StoreHandler::StoreElementTransition(
validity_cell = handle(Smi::kZero, isolate);
}
Handle<WeakCell> cell = Map::WeakCellForMap(transition);
return isolate->factory()->NewTuple3(cell, stub, validity_cell, TENURED);
Handle<StoreHandler> handler = isolate->factory()->NewStoreHandler(1);
handler->set_smi_handler(*stub);
handler->set_validity_cell(*validity_cell);
handler->set_data1(*cell);
return handler;
}
Handle<Smi> StoreHandler::StoreTransition(Isolate* isolate,
......@@ -224,18 +222,15 @@ Handle<Object> StoreHandler::StoreThroughPrototype(
data = Map::GetOrCreatePrototypeWeakCell(holder, isolate);
}
Factory* factory = isolate->factory();
if (checks_count == 0) {
return factory->NewTuple3(data, 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(kDataIndex, *data);
InitPrototypeChecks(isolate, receiver_map, holder, name, handler_array,
kFirstPrototypeIndex);
return handler_array;
int data_count = 1 + checks_count;
Handle<StoreHandler> handler =
isolate->factory()->NewStoreHandler(data_count);
handler->set_smi_handler(*smi_handler);
handler->set_validity_cell(*validity_cell);
handler->set_data1(*data);
InitPrototypeChecks(isolate, receiver_map, holder, name, handler);
return handler;
}
// static
......@@ -259,57 +254,25 @@ Handle<Object> StoreHandler::StoreProxy(Isolate* isolate,
Object* StoreHandler::ValidHandlerOrNull(Object* raw_handler, Name* name,
Handle<Map>* out_transition) {
STATIC_ASSERT(kValidityCellOffset == Tuple3::kValue3Offset);
Smi* valid = Smi::FromInt(Map::kPrototypeChainValid);
if (raw_handler->IsTuple3()) {
// Check validity cell.
Tuple3* handler = Tuple3::cast(raw_handler);
DCHECK(raw_handler->IsStoreHandler());
Object* raw_validity_cell = handler->value3();
// |raw_valitity_cell| can be Smi::kZero if no validity cell is required
// (which counts as valid).
if (raw_validity_cell->IsCell() &&
Cell::cast(raw_validity_cell)->value() != valid) {
return nullptr;
}
// Check validity cell.
StoreHandler* handler = StoreHandler::cast(raw_handler);
} else {
DCHECK(raw_handler->IsFixedArrayExact());
FixedArray* handler = FixedArray::cast(raw_handler);
// Check validity cell.
Object* value = Cell::cast(handler->get(kValidityCellIndex))->value();
if (value != valid) return nullptr;
// Check prototypes.
Heap* heap = handler->GetHeap();
Isolate* isolate = heap->isolate();
Handle<Name> name_handle(name, isolate);
for (int i = kFirstPrototypeIndex; i < handler->length(); i++) {
// This mirrors AccessorAssembler::CheckPrototype.
WeakCell* prototype_cell = WeakCell::cast(handler->get(i));
if (prototype_cell->cleared()) return nullptr;
HeapObject* maybe_prototype = HeapObject::cast(prototype_cell->value());
if (maybe_prototype->IsPropertyCell()) {
Object* value = PropertyCell::cast(maybe_prototype)->value();
if (value != heap->the_hole_value()) return nullptr;
} else {
DCHECK(maybe_prototype->map()->is_dictionary_map());
// Do a negative dictionary lookup.
NameDictionary* dict =
JSObject::cast(maybe_prototype)->property_dictionary();
int number = dict->FindEntry(isolate, name_handle);
if (number != NameDictionary::kNotFound) {
PropertyDetails details = dict->DetailsAt(number);
if (details.IsReadOnly()) return nullptr;
if (details.kind() == PropertyKind::kAccessor) return nullptr;
break;
}
}
}
Object* raw_validity_cell = handler->validity_cell();
// |raw_valitity_cell| can be Smi::kZero if no validity cell is required
// (which counts as valid).
if (raw_validity_cell->IsCell() &&
Cell::cast(raw_validity_cell)->value() != valid) {
return nullptr;
}
// We use this ValidHandlerOrNull() function only for transitioning store
// handlers which are not applicable to receivers that require access checks.
DCHECK(handler->smi_handler()->IsSmi());
DCHECK(
!DoAccessCheckOnReceiverBits::decode(Smi::ToInt(handler->smi_handler())));
// Check if the transition target is deprecated.
WeakCell* target_cell = GetTransitionCell(raw_handler);
......
......@@ -102,21 +102,6 @@ class LoadHandler final : public DataHandler {
class ExportsIndexBits : public BitField<unsigned, KindBits::kNext,
kSmiValueSize - KindBits::kNext> {};
// The layout of an Tuple3 handler representing a load of a field from
// prototype when prototype chain checks do not include non-existing lookups
// or access checks.
static const int kDataOffset = Tuple3::kValue1Offset;
static const int kSmiHandlerOffset = Tuple3::kValue2Offset;
static const int kValidityCellOffset = Tuple3::kValue3Offset;
// The layout of an array handler representing a load of a field from
// prototype when prototype chain checks include non-existing lookups and
// access checks.
static const int kSmiHandlerIndex = 0;
static const int kValidityCellIndex = 1;
static const int kDataIndex = 2;
static const int kFirstPrototypeIndex = 3;
// Decodes kind from Smi-handler.
static inline Kind GetHandlerKind(Smi* smi_handler);
......@@ -267,24 +252,10 @@ class StoreHandler final : public DataHandler {
// Make sure we don't overflow the smi.
STATIC_ASSERT(FieldIndexBits::kNext <= kSmiValueSize);
// The layout of an Tuple3 handler representing a transitioning store
// when prototype chain checks do not include non-existing lookups or access
// checks.
static const int kDataOffset = Tuple3::kValue1Offset;
static const int kSmiHandlerOffset = Tuple3::kValue2Offset;
static const int kValidityCellOffset = Tuple3::kValue3Offset;
static inline WeakCell* GetTransitionCell(Object* handler);
static Object* ValidHandlerOrNull(Object* handler, Name* name,
Handle<Map>* out_transition);
// The layout of an array handler representing a transitioning store
// when prototype chain checks include non-existing lookups and access checks.
static const int kSmiHandlerIndex = 0;
static const int kValidityCellIndex = 1;
static const int kDataIndex = 2;
static const int kFirstPrototypeIndex = 3;
// Creates a Smi-handler for storing a field to fast object.
static inline Handle<Smi> StoreField(Isolate* isolate, int descriptor,
FieldIndex field_index,
......
......@@ -42,8 +42,7 @@ Address IC::raw_constant_pool() const {
bool IC::IsHandler(Object* object) {
return (object->IsSmi() && (object != nullptr)) || object->IsTuple2() ||
object->IsTuple3() || object->IsFixedArrayExact() ||
object->IsWeakCell() || object->IsCode();
object->IsDataHandler() || object->IsWeakCell() || object->IsCode();
}
bool IC::AddressIsDeoptimizedCode() const {
......
......@@ -795,36 +795,20 @@ void KeyedStoreGenericAssembler::EmitGenericPropertyStore(
{
Comment("lookup transition");
VARIABLE(var_handler, MachineRepresentation::kTagged);
Label tuple3(this), fixedarray(this), found_handler(this, &var_handler);
Label check_key(this), found_handler(this, &var_handler);
Node* maybe_handler =
LoadObjectField(receiver_map, Map::kTransitionsOrPrototypeInfoOffset);
GotoIf(TaggedIsSmi(maybe_handler), notfound);
Node* handler_map = LoadMap(maybe_handler);
GotoIf(WordEqual(handler_map, Tuple3MapConstant()), &tuple3);
GotoIf(WordEqual(handler_map, FixedArrayMapConstant()), &fixedarray);
GotoIf(HasInstanceType(maybe_handler, STORE_HANDLER_TYPE), &check_key);
// TODO(jkummerow): Consider implementing TransitionArray search.
Goto(notfound);
VARIABLE(var_transition_cell, MachineRepresentation::kTagged);
Label check_key(this, &var_transition_cell);
BIND(&tuple3);
{
var_transition_cell.Bind(
LoadObjectField(maybe_handler, StoreHandler::kDataOffset));
Goto(&check_key);
}
BIND(&fixedarray);
{
var_transition_cell.Bind(
LoadFixedArrayElement(maybe_handler, StoreHandler::kDataIndex));
Goto(&check_key);
}
BIND(&check_key);
{
Node* transition = LoadWeakCellValue(var_transition_cell.value(), slow);
Node* transition_cell =
LoadObjectField(maybe_handler, StoreHandler::kData1Offset);
Node* transition = LoadWeakCellValue(transition_cell, slow);
Node* transition_bitfield3 = LoadMapBitField3(transition);
GotoIf(IsSetWord32<Map::IsDeprecatedBit>(transition_bitfield3), slow);
Node* nof =
......
......@@ -356,24 +356,6 @@ void LoadWithVectorDescriptor::InitializePlatformSpecific(
data->InitializePlatformSpecific(arraysize(registers), registers);
}
void LoadICProtoArrayDescriptor::InitializePlatformIndependent(
CallInterfaceDescriptorData* data) {
// kReceiver, kName, kSlot, kVector, kHandler
MachineType machine_types[] = {
MachineType::AnyTagged(), MachineType::AnyTagged(),
MachineType::TaggedSigned(), MachineType::AnyTagged(),
MachineType::AnyTagged()};
data->InitializePlatformIndependent(arraysize(machine_types), 0,
machine_types);
}
void LoadICProtoArrayDescriptor::InitializePlatformSpecific(
CallInterfaceDescriptorData* data) {
Register registers[] = {ReceiverRegister(), NameRegister(), SlotRegister(),
VectorRegister(), HandlerRegister()};
data->InitializePlatformSpecific(arraysize(registers), registers);
}
void StoreWithVectorDescriptor::InitializePlatformIndependent(
CallInterfaceDescriptorData* data) {
// kReceiver, kName, kValue, kSlot, kVector
......
......@@ -22,7 +22,6 @@ class PlatformInterfaceDescriptor;
V(Load) \
V(LoadWithVector) \
V(LoadField) \
V(LoadICProtoArray) \
V(LoadGlobal) \
V(LoadGlobalWithVector) \
V(Store) \
......@@ -504,15 +503,6 @@ class LoadWithVectorDescriptor : public LoadDescriptor {
static const Register VectorRegister();
};
class LoadICProtoArrayDescriptor : public LoadWithVectorDescriptor {
public:
DEFINE_PARAMETERS(kReceiver, kName, kSlot, kVector, kHandler)
DECLARE_DESCRIPTOR_WITH_CUSTOM_FUNCTION_TYPE(LoadICProtoArrayDescriptor,
LoadWithVectorDescriptor)
static const Register HandlerRegister();
};
class LoadGlobalWithVectorDescriptor : public LoadGlobalDescriptor {
public:
DEFINE_PARAMETERS(kName, kSlot, kVector)
......
......@@ -43,8 +43,6 @@ const Register LoadDescriptor::SlotRegister() { return a0; }
const Register LoadWithVectorDescriptor::VectorRegister() { return a3; }
const Register LoadICProtoArrayDescriptor::HandlerRegister() { return t0; }
const Register StoreDescriptor::ReceiverRegister() { return a1; }
const Register StoreDescriptor::NameRegister() { return a2; }
const Register StoreDescriptor::ValueRegister() { return a0; }
......
......@@ -43,8 +43,6 @@ const Register LoadDescriptor::SlotRegister() { return a0; }
const Register LoadWithVectorDescriptor::VectorRegister() { return a3; }
const Register LoadICProtoArrayDescriptor::HandlerRegister() { return a4; }
const Register StoreDescriptor::ReceiverRegister() { return a1; }
const Register StoreDescriptor::NameRegister() { return a2; }
const Register StoreDescriptor::ValueRegister() { return a0; }
......
......@@ -43,8 +43,6 @@ const Register LoadDescriptor::SlotRegister() { return r3; }
const Register LoadWithVectorDescriptor::VectorRegister() { return r6; }
const Register LoadICProtoArrayDescriptor::HandlerRegister() { return r7; }
const Register StoreDescriptor::ReceiverRegister() { return r4; }
const Register StoreDescriptor::NameRegister() { return r5; }
const Register StoreDescriptor::ValueRegister() { return r3; }
......
......@@ -43,8 +43,6 @@ const Register LoadDescriptor::SlotRegister() { return r2; }
const Register LoadWithVectorDescriptor::VectorRegister() { return r5; }
const Register LoadICProtoArrayDescriptor::HandlerRegister() { return r6; }
const Register StoreDescriptor::ReceiverRegister() { return r3; }
const Register StoreDescriptor::NameRegister() { return r4; }
const Register StoreDescriptor::ValueRegister() { return r2; }
......
......@@ -44,8 +44,6 @@ const Register LoadDescriptor::SlotRegister() { return rax; }
const Register LoadWithVectorDescriptor::VectorRegister() { return rbx; }
const Register LoadICProtoArrayDescriptor::HandlerRegister() { return rdi; }
const Register StoreDescriptor::ReceiverRegister() { return rdx; }
const Register StoreDescriptor::NameRegister() { return rcx; }
const Register StoreDescriptor::ValueRegister() { return rax; }
......
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