Commit 88643ae3 authored by Marja Hölttä's avatar Marja Hölttä Committed by Commit Bot

[in-place weak refs] Use in-place weak refs in ICs

BUG=v8:7308

Change-Id: I3de8160b28d2fccda895069c85a03f033152b1f6
Reviewed-on: https://chromium-review.googlesource.com/1140054
Commit-Queue: Marja Hölttä <marja@chromium.org>
Reviewed-by: 's avatarUlan Degenbaev <ulan@chromium.org>
Reviewed-by: 's avatarJakob Kummerow <jkummerow@chromium.org>
Cr-Commit-Position: refs/heads/master@{#54549}
parent 605f94b7
......@@ -479,12 +479,15 @@ void AccessorAssembler::HandleLoadICSmiHandlerCase(
// Context is stored either in data2 or data3 field depending on whether
// the access check is enabled for this handler or not.
TNode<Object> context_cell = Select<Object>(
TNode<MaybeObject> maybe_context = Select<MaybeObject>(
IsSetWord<LoadHandler::DoAccessCheckOnReceiverBits>(handler_word),
[=] { return CAST(LoadHandlerDataField(handler, 3)); },
[=] { return CAST(LoadHandlerDataField(handler, 2)); });
[=] { return LoadHandlerDataField(handler, 3); },
[=] { return LoadHandlerDataField(handler, 2); });
Node* context = LoadWeakCellValueUnchecked(CAST(context_cell));
CSA_ASSERT(this, IsWeakOrClearedHeapObject(maybe_context));
TNode<Object> context = Select<Object>(
IsClearedWeakHeapObject(maybe_context), [=] { return SmiConstant(0); },
[=] { return ToWeakHeapObject(maybe_context); });
Node* foreign =
LoadObjectField(call_handler_info, CallHandlerInfo::kJsCallbackOffset);
Node* callback = LoadObjectField(foreign, Foreign::kForeignAddressOffset,
......@@ -670,8 +673,9 @@ Node* AccessorAssembler::HandleProtoHandler(
BIND(&if_do_access_check);
{
TNode<WeakCell> data2 = CAST(LoadHandlerDataField(handler, 2));
Node* expected_native_context = LoadWeakCellValue(data2, miss);
TNode<MaybeObject> data2 = LoadHandlerDataField(handler, 2);
CSA_ASSERT(this, IsWeakOrClearedHeapObject(data2));
TNode<Object> expected_native_context = ToWeakHeapObject(data2, miss);
EmitAccessCheck(expected_native_context, p->context, p->receiver, &done,
miss);
}
......@@ -731,18 +735,20 @@ void AccessorAssembler::HandleLoadICProtoHandler(
},
miss, ic_mode);
TNode<Object> maybe_holder_cell = CAST(LoadHandlerDataField(handler, 1));
TNode<MaybeObject> maybe_holder = LoadHandlerDataField(handler, 1);
Label load_from_cached_holder(this), done(this);
Branch(IsNull(maybe_holder_cell), &done, &load_from_cached_holder);
Branch(IsStrongReferenceTo(maybe_holder, NullConstant()), &done,
&load_from_cached_holder);
BIND(&load_from_cached_holder);
{
// 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(CAST(maybe_holder_cell), miss);
// validity cell check implies that |holder| is alive. However, for global
// object receivers, |maybe_holder| may be cleared.
CSA_ASSERT(this, IsWeakOrClearedHeapObject(maybe_holder));
Node* holder = ToWeakHeapObject(maybe_holder, miss);
var_holder->Bind(holder);
Goto(&done);
......@@ -1277,8 +1283,9 @@ void AccessorAssembler::HandleStoreICProtoHandler(
GotoIf(WordEqual(handler_kind, IntPtrConstant(StoreHandler::kNormal)),
&if_add_normal);
TNode<WeakCell> holder_cell = CAST(LoadHandlerDataField(handler, 1));
Node* holder = LoadWeakCellValue(holder_cell, miss);
TNode<MaybeObject> maybe_holder = LoadHandlerDataField(handler, 1);
CSA_ASSERT(this, IsWeakOrClearedHeapObject(maybe_holder));
TNode<Object> holder = ToWeakHeapObject(maybe_holder, miss);
GotoIf(WordEqual(handler_kind, IntPtrConstant(StoreHandler::kGlobalProxy)),
&if_store_global_proxy);
......@@ -1334,12 +1341,16 @@ void AccessorAssembler::HandleStoreICProtoHandler(
// Context is stored either in data2 or data3 field depending on whether
// the access check is enabled for this handler or not.
TNode<Object> context_cell = Select<Object>(
TNode<MaybeObject> maybe_context = Select<MaybeObject>(
IsSetWord<LoadHandler::DoAccessCheckOnReceiverBits>(handler_word),
[=] { return CAST(LoadHandlerDataField(handler, 3)); },
[=] { return CAST(LoadHandlerDataField(handler, 2)); });
Node* context = LoadWeakCellValueUnchecked(CAST(context_cell));
[=] { return LoadHandlerDataField(handler, 3); },
[=] { return LoadHandlerDataField(handler, 2); });
CSA_ASSERT(this, IsWeakOrClearedHeapObject(maybe_context));
TNode<Object> context =
Select<Object>(IsClearedWeakHeapObject(maybe_context),
[=] { return SmiConstant(0); },
[=] { return ToWeakHeapObject(maybe_context); });
Node* foreign = LoadObjectField(call_handler_info,
CallHandlerInfo::kJsCallbackOffset);
......
......@@ -6,6 +6,7 @@
#include "src/code-stubs.h"
#include "src/ic/handler-configuration-inl.h"
#include "src/objects/maybe-object.h"
#include "src/transitions.h"
namespace v8 {
......@@ -26,8 +27,8 @@ Handle<Smi> SetBitFieldValue(Isolate* isolate, Handle<Smi> smi_handler,
template <typename ICHandler, bool fill_handler = true>
int InitPrototypeChecksImpl(Isolate* isolate, Handle<ICHandler> handler,
Handle<Smi>* smi_handler, Handle<Map> receiver_map,
Handle<JSReceiver> holder, Handle<Object> data1,
MaybeHandle<Object> maybe_data2) {
Handle<JSReceiver> holder, MaybeObjectHandle data1,
MaybeObjectHandle maybe_data2) {
int checks_count = 0;
// Holder-is-receiver case itself does not add entries unless there is an
// optional data2 value provided.
......@@ -43,7 +44,7 @@ int InitPrototypeChecksImpl(Isolate* isolate, Handle<ICHandler> handler,
// corresponds.
if (fill_handler) {
Handle<Context> native_context = isolate->native_context();
handler->set_data2(native_context->self_weak_cell());
handler->set_data2(HeapObjectReference::Weak(*native_context));
} else {
// Enable access checks on receiver.
typedef typename ICHandler::DoAccessCheckOnReceiverBits Bit;
......@@ -59,18 +60,17 @@ int InitPrototypeChecksImpl(Isolate* isolate, Handle<ICHandler> handler,
}
}
if (fill_handler) {
handler->set_data1(MaybeObject::FromObject(*data1));
handler->set_data1(*data1);
}
Handle<Object> data2;
if (maybe_data2.ToHandle(&data2)) {
if (!maybe_data2.is_null()) {
if (fill_handler) {
// This value will go either to data2 or data3 slot depending on whether
// data2 slot is already occupied by native context.
if (checks_count == 0) {
handler->set_data2(*data2);
handler->set_data2(*maybe_data2);
} else {
DCHECK_EQ(1, checks_count);
handler->set_data3(*data2);
handler->set_data3(*maybe_data2);
}
}
checks_count++;
......@@ -87,8 +87,8 @@ int InitPrototypeChecksImpl(Isolate* isolate, Handle<ICHandler> handler,
template <typename ICHandler>
int GetPrototypeCheckCount(
Isolate* isolate, Handle<Smi>* smi_handler, Handle<Map> receiver_map,
Handle<JSReceiver> holder, Handle<Object> data1,
MaybeHandle<Object> maybe_data2 = MaybeHandle<Object>()) {
Handle<JSReceiver> holder, MaybeObjectHandle data1,
MaybeObjectHandle maybe_data2 = MaybeObjectHandle()) {
DCHECK_NOT_NULL(smi_handler);
return InitPrototypeChecksImpl<ICHandler, false>(isolate, Handle<ICHandler>(),
smi_handler, receiver_map,
......@@ -96,10 +96,10 @@ int GetPrototypeCheckCount(
}
template <typename ICHandler>
void InitPrototypeChecks(
Isolate* isolate, Handle<ICHandler> handler, Handle<Map> receiver_map,
Handle<JSReceiver> holder, Handle<Object> data1,
MaybeHandle<Object> maybe_data2 = MaybeHandle<Object>()) {
void InitPrototypeChecks(Isolate* isolate, Handle<ICHandler> handler,
Handle<Map> receiver_map, Handle<JSReceiver> holder,
MaybeObjectHandle data1,
MaybeObjectHandle maybe_data2 = MaybeObjectHandle()) {
InitPrototypeChecksImpl<ICHandler, true>(
isolate, handler, nullptr, receiver_map, holder, data1, maybe_data2);
}
......@@ -111,11 +111,13 @@ Handle<Object> LoadHandler::LoadFromPrototype(Isolate* isolate,
Handle<Map> receiver_map,
Handle<JSReceiver> holder,
Handle<Smi> smi_handler,
MaybeHandle<Object> maybe_data1,
MaybeHandle<Object> maybe_data2) {
Handle<Object> data1;
if (!maybe_data1.ToHandle(&data1)) {
data1 = Map::GetOrCreatePrototypeWeakCell(holder, isolate);
MaybeObjectHandle maybe_data1,
MaybeObjectHandle maybe_data2) {
MaybeObjectHandle data1;
if (maybe_data1.is_null()) {
data1 = MaybeObjectHandle::Weak(holder);
} else {
data1 = maybe_data1;
}
int checks_count = GetPrototypeCheckCount<LoadHandler>(
......@@ -137,10 +139,10 @@ Handle<Object> LoadHandler::LoadFromPrototype(Isolate* isolate,
// static
Handle<Object> LoadHandler::LoadFullChain(Isolate* isolate,
Handle<Map> receiver_map,
Handle<Object> holder,
MaybeObjectHandle holder,
Handle<Smi> smi_handler) {
Handle<JSReceiver> end; // null handle, means full prototype chain lookup.
Handle<Object> data1 = holder;
MaybeObjectHandle data1 = holder;
int checks_count = GetPrototypeCheckCount<LoadHandler>(
isolate, &smi_handler, receiver_map, end, data1);
......@@ -243,11 +245,13 @@ MaybeObjectHandle StoreHandler::StoreTransition(Isolate* isolate,
// static
Handle<Object> StoreHandler::StoreThroughPrototype(
Isolate* isolate, Handle<Map> receiver_map, Handle<JSReceiver> holder,
Handle<Smi> smi_handler, MaybeHandle<Object> maybe_data1,
MaybeHandle<Object> maybe_data2) {
Handle<Object> data1;
if (!maybe_data1.ToHandle(&data1)) {
data1 = Map::GetOrCreatePrototypeWeakCell(holder, isolate);
Handle<Smi> smi_handler, MaybeObjectHandle maybe_data1,
MaybeObjectHandle maybe_data2) {
MaybeObjectHandle data1;
if (maybe_data1.is_null()) {
data1 = MaybeObjectHandle::Weak(holder);
} else {
data1 = maybe_data1;
}
int checks_count = GetPrototypeCheckCount<StoreHandler>(
......@@ -280,9 +284,8 @@ Handle<Object> StoreHandler::StoreProxy(Isolate* isolate,
Handle<JSReceiver> receiver) {
Handle<Smi> smi_handler = StoreProxy(isolate);
if (receiver.is_identical_to(proxy)) return smi_handler;
Handle<WeakCell> holder_cell = isolate->factory()->NewWeakCell(proxy);
return StoreThroughPrototype(isolate, receiver_map, proxy, smi_handler,
holder_cell);
MaybeObjectHandle::Weak(proxy));
}
} // namespace internal
......
......@@ -149,7 +149,7 @@ class LoadHandler final : public DataHandler {
// needed (e.g., for "nonexistent"), null_value() may be passed in.
static Handle<Object> LoadFullChain(Isolate* isolate,
Handle<Map> receiver_map,
Handle<Object> holder,
MaybeObjectHandle holder,
Handle<Smi> smi_handler);
// Creates a data handler that represents a prototype chain check followed
......@@ -158,8 +158,8 @@ class LoadHandler final : public DataHandler {
static Handle<Object> LoadFromPrototype(
Isolate* isolate, Handle<Map> receiver_map, Handle<JSReceiver> holder,
Handle<Smi> smi_handler,
MaybeHandle<Object> maybe_data1 = MaybeHandle<Object>(),
MaybeHandle<Object> maybe_data2 = MaybeHandle<Object>());
MaybeObjectHandle maybe_data1 = MaybeObjectHandle(),
MaybeObjectHandle maybe_data2 = MaybeObjectHandle());
// Creates a Smi-handler for loading a non-existent property. Works only as
// a part of prototype chain check.
......@@ -268,8 +268,8 @@ class StoreHandler final : public DataHandler {
static Handle<Object> StoreThroughPrototype(
Isolate* isolate, Handle<Map> receiver_map, Handle<JSReceiver> holder,
Handle<Smi> smi_handler,
MaybeHandle<Object> maybe_data1 = MaybeHandle<Object>(),
MaybeHandle<Object> maybe_data2 = MaybeHandle<Object>());
MaybeObjectHandle maybe_data1 = MaybeObjectHandle(),
MaybeObjectHandle maybe_data2 = MaybeObjectHandle());
static Handle<Object> StoreElementTransition(Isolate* isolate,
Handle<Map> receiver_map,
......
......@@ -687,9 +687,9 @@ void LoadIC::UpdateCaches(LookupIterator* lookup) {
} else if (!lookup->IsFound()) {
TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNonexistentDH);
Handle<Smi> smi_handler = LoadHandler::LoadNonExistent(isolate());
code = LoadHandler::LoadFullChain(isolate(), receiver_map(),
isolate()->factory()->null_value(),
smi_handler);
code = LoadHandler::LoadFullChain(
isolate(), receiver_map(),
MaybeObjectHandle(isolate()->factory()->null_value()), smi_handler);
} else {
if (IsLoadGlobalIC()) {
if (lookup->TryLookupCachedProperty()) {
......@@ -771,9 +771,9 @@ Handle<Object> LoadIC::ComputeHandler(LookupIterator* lookup) {
Handle<Smi> smi_handler = LoadHandler::LoadInterceptor(isolate());
if (holder->GetNamedInterceptor()->non_masking()) {
Handle<Object> holder_ref = isolate()->factory()->null_value();
MaybeObjectHandle holder_ref(isolate()->factory()->null_value());
if (!receiver_is_holder || IsLoadGlobalIC()) {
holder_ref = Map::GetOrCreatePrototypeWeakCell(holder, isolate());
holder_ref = MaybeObjectHandle::Weak(holder);
}
TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNonMaskingInterceptorDH);
return LoadHandler::LoadFullChain(isolate(), map, holder_ref,
......@@ -852,14 +852,12 @@ Handle<Object> LoadIC::ComputeHandler(LookupIterator* lookup) {
Handle<Context> context(
call_optimization.GetAccessorContext(holder->map()), isolate());
Handle<WeakCell> context_cell =
isolate()->factory()->NewWeakCell(context);
Handle<WeakCell> data_cell = isolate()->factory()->NewWeakCell(
call_optimization.api_call_info());
TRACE_HANDLER_STATS(isolate(), LoadIC_LoadApiGetterFromPrototypeDH);
return LoadHandler::LoadFromPrototype(
isolate(), map, holder, smi_handler, data_cell, context_cell);
isolate(), map, holder, smi_handler,
MaybeObjectHandle::Weak(call_optimization.api_call_info()),
MaybeObjectHandle::Weak(context));
}
if (holder->HasFastProperties()) {
......@@ -872,10 +870,9 @@ Handle<Object> LoadIC::ComputeHandler(LookupIterator* lookup) {
} else if (holder->IsJSGlobalObject()) {
TRACE_HANDLER_STATS(isolate(), LoadIC_LoadGlobalFromPrototypeDH);
smi_handler = LoadHandler::LoadGlobal(isolate());
Handle<WeakCell> cell =
isolate()->factory()->NewWeakCell(lookup->GetPropertyCell());
return LoadHandler::LoadFromPrototype(isolate(), map, holder,
smi_handler, cell);
return LoadHandler::LoadFromPrototype(
isolate(), map, holder, smi_handler,
MaybeObjectHandle::Weak(lookup->GetPropertyCell()));
} else {
smi_handler = LoadHandler::LoadNormal(isolate());
......@@ -917,10 +914,9 @@ Handle<Object> LoadIC::ComputeHandler(LookupIterator* lookup) {
// workaround for code that leaks the global object.
TRACE_HANDLER_STATS(isolate(), LoadIC_LoadGlobalDH);
smi_handler = LoadHandler::LoadGlobal(isolate());
Handle<WeakCell> cell =
isolate()->factory()->NewWeakCell(lookup->GetPropertyCell());
return LoadHandler::LoadFromPrototype(isolate(), map, holder,
smi_handler, cell);
return LoadHandler::LoadFromPrototype(
isolate(), map, holder, smi_handler,
MaybeObjectHandle::Weak(lookup->GetPropertyCell()));
}
smi_handler = LoadHandler::LoadNormal(isolate());
......@@ -1486,10 +1482,9 @@ MaybeObjectHandle StoreIC::ComputeHandler(LookupIterator* lookup) {
}
Handle<Smi> smi_handler = StoreHandler::StoreGlobalProxy(isolate());
Handle<WeakCell> cell =
isolate()->factory()->NewWeakCell(lookup->transition_cell());
Handle<Object> handler = StoreHandler::StoreThroughPrototype(
isolate(), receiver_map(), store_target, smi_handler, cell);
isolate(), receiver_map(), store_target, smi_handler,
MaybeObjectHandle::Weak(lookup->transition_cell()));
return MaybeObjectHandle(handler);
}
// Dictionary-to-fast transitions are not expected and not supported.
......@@ -1582,14 +1577,11 @@ MaybeObjectHandle StoreIC::ComputeHandler(LookupIterator* lookup) {
Handle<Context> context(
call_optimization.GetAccessorContext(holder->map()), isolate());
Handle<WeakCell> context_cell =
isolate()->factory()->NewWeakCell(context);
Handle<WeakCell> data_cell = isolate()->factory()->NewWeakCell(
call_optimization.api_call_info());
TRACE_HANDLER_STATS(isolate(), StoreIC_StoreApiSetterOnPrototypeDH);
return MaybeObjectHandle(StoreHandler::StoreThroughPrototype(
isolate(), receiver_map(), holder, smi_handler, data_cell,
context_cell));
isolate(), receiver_map(), holder, smi_handler,
MaybeObjectHandle::Weak(call_optimization.api_call_info()),
MaybeObjectHandle::Weak(context)));
}
set_slow_stub_reason("incompatible receiver");
TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
......
......@@ -616,10 +616,7 @@ class DataHandler::BodyDescriptor final : public BodyDescriptorBase {
static_assert(kData1Offset < kSizeWithData1,
"Field order must be in sync with this iteration code");
IteratePointers(obj, kSmiHandlerOffset, kData1Offset, v);
if (object_size >= kSizeWithData1) {
IterateMaybeWeakPointer(obj, kData1Offset, v);
IteratePointers(obj, kData1Offset + kPointerSize, object_size, v);
}
IterateMaybeWeakPointers(obj, kData1Offset, object_size, v);
}
static inline int SizeOf(Map* map, HeapObject* object) {
......
......@@ -1664,10 +1664,10 @@ void DataHandler::DataHandlerVerify(Isolate* isolate) {
VerifyMaybeObjectField(isolate, kData1Offset);
}
if (data_count >= 2) {
VerifyObjectField(isolate, kData2Offset);
VerifyMaybeObjectField(isolate, kData2Offset);
}
if (data_count >= 3) {
VerifyObjectField(isolate, kData3Offset);
VerifyMaybeObjectField(isolate, kData3Offset);
}
}
......
......@@ -1783,10 +1783,10 @@ void LoadHandler::LoadHandlerPrint(std::ostream& os) { // NOLINT
os << "\n - data1: " << MaybeObjectBrief(data1());
}
if (data_count >= 2) {
os << "\n - data2: " << Brief(data2());
os << "\n - data2: " << MaybeObjectBrief(data2());
}
if (data_count >= 3) {
os << "\n - data3: " << Brief(data3());
os << "\n - data3: " << MaybeObjectBrief(data3());
}
os << "\n";
}
......@@ -1801,10 +1801,10 @@ void StoreHandler::StoreHandlerPrint(std::ostream& os) { // NOLINT
os << "\n - data1: " << MaybeObjectBrief(data1());
}
if (data_count >= 2) {
os << "\n - data2: " << Brief(data2());
os << "\n - data2: " << MaybeObjectBrief(data2());
}
if (data_count >= 3) {
os << "\n - data3: " << Brief(data3());
os << "\n - data3: " << MaybeObjectBrief(data3());
}
os << "\n";
}
......
......@@ -28,10 +28,10 @@ int DataHandler::data_field_count() const {
WEAK_ACCESSORS_CHECKED(DataHandler, data1, kData1Offset,
map()->instance_size() >= kSizeWithData1)
ACCESSORS_CHECKED(DataHandler, data2, Object, kData2Offset,
map()->instance_size() >= kSizeWithData2)
ACCESSORS_CHECKED(DataHandler, data3, Object, kData3Offset,
map()->instance_size() >= kSizeWithData3)
WEAK_ACCESSORS_CHECKED(DataHandler, data2, kData2Offset,
map()->instance_size() >= kSizeWithData2)
WEAK_ACCESSORS_CHECKED(DataHandler, data3, kData3Offset,
map()->instance_size() >= kSizeWithData3)
} // namespace internal
} // namespace v8
......
......@@ -32,8 +32,8 @@ class DataHandler : public Struct {
// [data1-3]: These are optional general-purpose fields whose content and
// presence depends on the handler kind.
DECL_ACCESSORS(data1, MaybeObject)
DECL_ACCESSORS(data2, Object)
DECL_ACCESSORS(data3, Object)
DECL_ACCESSORS(data2, MaybeObject)
DECL_ACCESSORS(data3, MaybeObject)
// Layout description.
#define DATA_HANDLER_FIELDS(V) \
......
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