[runtime] Add a mode to lookup iterator that doesn't allocate

This CL adds a mode to the JSReceiver::GetDataProperty that does
not box unboxed double fields. This method can be used to fix a critical
bug in the heap snapshot generator that currently causes a GC in a place
where no GC should be caused.

Change-Id: If195f6811090281d364e3c8fa221a1d6b96bcd80
Bug: v8:9993
Fixed: chromium:1038490
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1993286
Commit-Queue: Sigurd Schneider <sigurds@chromium.org>
Reviewed-by: Jakob Kummerow <jkummerow@chromium.org>
Reviewed-by: Toon Verwaest <verwaest@chromium.org>
Cr-Commit-Position: refs/heads/master@{#65694}
This commit is contained in:
Sigurd Schneider 2020-01-10 14:05:59 +01:00 committed by Commit Bot
parent 328c166ef4
commit b44f8abb2a
4 changed files with 31 additions and 11 deletions

View File

@ -130,7 +130,8 @@ Maybe<bool> JSReceiver::HasOwnProperty(Handle<JSReceiver> object,
return Just(attributes.FromJust() != ABSENT);
}
Handle<Object> JSReceiver::GetDataProperty(LookupIterator* it) {
Handle<Object> JSReceiver::GetDataProperty(LookupIterator* it,
AllocationPolicy allocation_policy) {
for (; it->IsFound(); it->Next()) {
switch (it->state()) {
case LookupIterator::INTERCEPTOR:
@ -153,7 +154,7 @@ Handle<Object> JSReceiver::GetDataProperty(LookupIterator* it) {
case LookupIterator::INTEGER_INDEXED_EXOTIC:
return it->isolate()->factory()->undefined_value();
case LookupIterator::DATA:
return it->GetDataValue();
return it->GetDataValue(allocation_policy);
}
}
return it->isolate()->factory()->undefined_value();
@ -446,11 +447,15 @@ std::pair<MaybeHandle<JSFunction>, Handle<String>> GetConstructorHelper(
}
}
LookupIterator it_tag(isolate, receiver,
isolate->factory()->to_string_tag_symbol(), receiver,
LookupIterator::PROTOTYPE_CHAIN_SKIP_INTERCEPTOR);
Handle<Object> maybe_tag = JSReceiver::GetDataProperty(
receiver, isolate->factory()->to_string_tag_symbol());
if (maybe_tag->IsString())
&it_tag, AllocationPolicy::kAllocationDisallowed);
if (maybe_tag->IsString()) {
return std::make_pair(MaybeHandle<JSFunction>(),
Handle<String>::cast(maybe_tag));
}
PrototypeIterator iter(isolate, receiver);
if (iter.IsAtEnd()) {
@ -461,7 +466,8 @@ std::pair<MaybeHandle<JSFunction>, Handle<String>> GetConstructorHelper(
Handle<JSReceiver> start = PrototypeIterator::GetCurrent<JSReceiver>(iter);
LookupIterator it(isolate, receiver, isolate->factory()->constructor_string(),
start, LookupIterator::PROTOTYPE_CHAIN_SKIP_INTERCEPTOR);
Handle<Object> maybe_constructor = JSReceiver::GetDataProperty(&it);
Handle<Object> maybe_constructor =
JSReceiver::GetDataProperty(&it, AllocationPolicy::kAllocationDisallowed);
if (maybe_constructor->IsJSFunction()) {
JSFunction constructor = JSFunction::cast(*maybe_constructor);
String name = constructor.shared().DebugName();

View File

@ -19,6 +19,10 @@
namespace v8 {
namespace internal {
// Enum for functions that offer a second mode that does not cause allocations.
// Used in conjunction with LookupIterator and unboxed double fields.
enum class AllocationPolicy { kAllocationAllowed, kAllocationDisallowed };
enum InstanceType : uint16_t;
class JSGlobalObject;
class JSGlobalProxy;
@ -237,7 +241,9 @@ class JSReceiver : public HeapObject {
inline static Handle<Object> GetDataProperty(Handle<JSReceiver> object,
Handle<Name> name);
V8_EXPORT_PRIVATE static Handle<Object> GetDataProperty(LookupIterator* it);
V8_EXPORT_PRIVATE static Handle<Object> GetDataProperty(
LookupIterator* it, AllocationPolicy allocation_policy =
AllocationPolicy::kAllocationAllowed);
// Retrieves a permanent object identity hash code. The undefined value might
// be returned in case no hash was created yet.

View File

@ -840,7 +840,8 @@ bool LookupIterator::HolderIsReceiverOrHiddenPrototype() const {
isolate_) == *holder_;
}
Handle<Object> LookupIterator::FetchValue() const {
Handle<Object> LookupIterator::FetchValue(
AllocationPolicy allocation_policy) const {
Object result;
if (IsElement(*holder_)) {
Handle<JSObject> holder = GetHolder<JSObject>();
@ -858,6 +859,10 @@ Handle<Object> LookupIterator::FetchValue() const {
Handle<JSObject> holder = GetHolder<JSObject>();
FieldIndex field_index =
FieldIndex::ForDescriptor(holder->map(isolate_), descriptor_number());
if (allocation_policy == AllocationPolicy::kAllocationDisallowed &&
field_index.is_inobject() && field_index.is_double()) {
return isolate_->factory()->undefined_value();
}
return JSObject::FastPropertyAt(holder, property_details_.representation(),
field_index);
} else {
@ -975,9 +980,10 @@ Handle<Object> LookupIterator::GetAccessors() const {
return FetchValue();
}
Handle<Object> LookupIterator::GetDataValue() const {
Handle<Object> LookupIterator::GetDataValue(
AllocationPolicy allocation_policy) const {
DCHECK_EQ(DATA, state_);
Handle<Object> value = FetchValue();
Handle<Object> value = FetchValue(allocation_policy);
return value;
}

View File

@ -179,7 +179,8 @@ class V8_EXPORT_PRIVATE LookupIterator final {
Handle<Object> GetAccessors() const;
inline Handle<InterceptorInfo> GetInterceptor() const;
Handle<InterceptorInfo> GetInterceptorForFailedAccessCheck() const;
Handle<Object> GetDataValue() const;
Handle<Object> GetDataValue(AllocationPolicy allocation_policy =
AllocationPolicy::kAllocationAllowed) const;
void WriteDataValue(Handle<Object> value, bool initializing_store);
inline void UpdateProtector();
static inline void UpdateProtector(Isolate* isolate, Handle<Object> receiver,
@ -238,7 +239,8 @@ class V8_EXPORT_PRIVATE LookupIterator final {
}
template <bool is_element>
void RestartInternal(InterceptorState interceptor_state);
Handle<Object> FetchValue() const;
Handle<Object> FetchValue(AllocationPolicy allocation_policy =
AllocationPolicy::kAllocationAllowed) const;
bool IsConstFieldValueEqualTo(Object value) const;
template <bool is_element>
void ReloadPropertyInformation();