Commit 16f1d16c authored by Georg Neis's avatar Georg Neis Committed by Commit Bot

[turbofan] Brokerize DependOnStablePrototypeChains.

As well as a few other things in JSNativeContextSpecialization.

Bug: v8:7790
Change-Id: Ic13abec45797bb4c6cc66a140180122529c7288d
Reviewed-on: https://chromium-review.googlesource.com/c/1280327Reviewed-by: 's avatarJaroslav Sevcik <jarin@chromium.org>
Reviewed-by: 's avatarMaya Lekova <mslekova@chromium.org>
Commit-Queue: Georg Neis <neis@chromium.org>
Cr-Commit-Position: refs/heads/master@{#56670}
parent 34ec9ec7
......@@ -388,37 +388,34 @@ bool CompilationDependencies::Commit(Handle<Code> code) {
}
namespace {
// This function expects to never see a JSProxy.
void DependOnStablePrototypeChain(JSHeapBroker* broker,
CompilationDependencies* deps,
Handle<Map> map,
MaybeHandle<JSReceiver> last_prototype) {
for (PrototypeIterator i(broker->isolate(), map); !i.IsAtEnd(); i.Advance()) {
Handle<JSReceiver> const current =
PrototypeIterator::GetCurrent<JSReceiver>(i);
deps->DependOnStableMap(
MapRef(broker, handle(current->map(), broker->isolate())));
Handle<JSReceiver> last;
if (last_prototype.ToHandle(&last) && last.is_identical_to(current)) {
break;
}
CompilationDependencies* deps, MapRef map,
const JSObjectRef& last_prototype) {
while (true) {
map.SerializePrototype();
JSObjectRef proto = map.prototype().AsJSObject();
map = proto.map();
deps->DependOnStableMap(map);
if (proto.equals(last_prototype)) break;
}
}
} // namespace
void CompilationDependencies::DependOnStablePrototypeChains(
JSHeapBroker* broker, Handle<Context> native_context,
std::vector<Handle<Map>> const& receiver_maps, Handle<JSObject> holder) {
Isolate* isolate = holder->GetIsolate();
JSHeapBroker* broker, std::vector<Handle<Map>> const& receiver_maps,
const JSObjectRef& holder) {
// Determine actual holder and perform prototype chain checks.
for (auto map : receiver_maps) {
// Perform the implicit ToObject for primitives here.
// Implemented according to ES6 section 7.3.2 GetV (V, P).
Handle<JSFunction> constructor;
if (Map::GetConstructorFunction(map, native_context)
.ToHandle(&constructor)) {
map = handle(constructor->initial_map(), isolate);
MapRef receiver_map(broker, map);
if (receiver_map.IsPrimitiveMap()) {
// Perform the implicit ToObject for primitives here.
// Implemented according to ES6 section 7.3.2 GetV (V, P).
base::Optional<JSFunctionRef> constructor =
broker->native_context().GetConstructorFunction(receiver_map);
if (constructor.has_value()) receiver_map = constructor->initial_map();
}
DependOnStablePrototypeChain(broker, this, map, holder);
DependOnStablePrototypeChain(broker, this, receiver_map, holder);
}
}
......
......@@ -67,10 +67,9 @@ class V8_EXPORT_PRIVATE CompilationDependencies : public ZoneObject {
// Depend on the stability of (the maps of) all prototypes of every class in
// {receiver_type} up to (and including) the {holder}.
// TODO(neis): Fully brokerize!
void DependOnStablePrototypeChains(
JSHeapBroker* broker, Handle<Context> native_context,
std::vector<Handle<Map>> const& receiver_maps, Handle<JSObject> holder);
JSHeapBroker* broker, std::vector<Handle<Map>> const& receiver_maps,
const JSObjectRef& holder);
// Like DependOnElementsKind but also applies to all nested allocation sites.
void DependOnElementsKinds(const AllocationSiteRef& site);
......
......@@ -7072,7 +7072,7 @@ Reduction JSCallReducer::ReduceRegExpPrototypeTest(Node* node) {
Handle<JSObject> holder;
if (ai_exec.holder().ToHandle(&holder)) {
dependencies()->DependOnStablePrototypeChains(
broker(), native_context(), ai_exec.receiver_maps(), holder);
broker(), ai_exec.receiver_maps(), JSObjectRef(broker(), holder));
}
if (need_map_check) {
......
......@@ -610,6 +610,7 @@ class MapData : public HeapObjectData {
CHECK(InstanceTypeChecker::IsJSObject(instance_type()));
return in_object_properties_;
}
int constructor_function_index() const { return constructor_function_index_; }
// Extra information.
......@@ -649,6 +650,7 @@ class MapData : public HeapObjectData {
bool const can_transition_;
int const in_object_properties_start_in_words_;
int const in_object_properties_;
int const constructor_function_index_;
bool serialized_elements_kind_generalizations_ = false;
ZoneVector<MapData*> elements_kind_generalizations_;
......@@ -726,6 +728,9 @@ MapData::MapData(JSHeapBroker* broker, ObjectData** storage, Handle<Map> object)
: 0),
in_object_properties_(
object->IsJSObjectMap() ? object->GetInObjectProperties() : 0),
constructor_function_index_(object->IsPrimitiveMap()
? object->GetConstructorFunctionIndex()
: Map::kNoConstructorFunctionIndex),
elements_kind_generalizations_(broker->zone()) {}
JSFunctionData::JSFunctionData(JSHeapBroker* broker, ObjectData** storage,
......@@ -1893,6 +1898,10 @@ bool MapRef::IsFixedCowArrayMap() const {
return equals(MapRef(broker(), fixed_cow_array_map));
}
bool MapRef::IsPrimitiveMap() const {
return instance_type() <= LAST_PRIMITIVE_TYPE;
}
MapRef MapRef::FindFieldOwner(int descriptor_index) const {
if (broker()->mode() == JSHeapBroker::kDisabled) {
AllowHandleAllocation handle_allocation;
......@@ -2086,6 +2095,12 @@ bool MapRef::IsInobjectSlackTrackingInProgress() const {
Map::kNoSlackTracking;
}
int MapRef::constructor_function_index() const {
IF_BROKER_DISABLED_ACCESS_HANDLE_C(Map, GetConstructorFunctionIndex);
CHECK(IsPrimitiveMap());
return data()->AsMap()->constructor_function_index();
}
bool MapRef::is_stable() const {
IF_BROKER_DISABLED_ACCESS_HANDLE_C(Map, is_stable);
return !Map::IsUnstableBit::decode(data()->AsMap()->bit_field3());
......@@ -2156,6 +2171,27 @@ MapRef NativeContextRef::GetInitialJSArrayMap(ElementsKind kind) const {
}
}
base::Optional<JSFunctionRef> NativeContextRef::GetConstructorFunction(
const MapRef& map) const {
CHECK(map.IsPrimitiveMap());
switch (map.constructor_function_index()) {
case Map::kNoConstructorFunctionIndex:
return base::nullopt;
case Context::BIGINT_FUNCTION_INDEX:
return bigint_function();
case Context::BOOLEAN_FUNCTION_INDEX:
return boolean_function();
case Context::NUMBER_FUNCTION_INDEX:
return number_function();
case Context::STRING_FUNCTION_INDEX:
return string_function();
case Context::SYMBOL_FUNCTION_INDEX:
return symbol_function();
default:
UNREACHABLE();
}
}
bool ObjectRef::BooleanValue() const {
if (broker()->mode() == JSHeapBroker::kDisabled) {
AllowHandleDereference allow_handle_dereference;
......
......@@ -240,8 +240,13 @@ class ContextRef : public HeapObjectRef {
#define BROKER_COMPULSORY_NATIVE_CONTEXT_FIELDS(V) \
V(JSFunction, array_function) \
V(JSFunction, boolean_function) \
V(JSFunction, bigint_function) \
V(JSFunction, number_function) \
V(JSFunction, object_function) \
V(JSFunction, promise_function) \
V(JSFunction, string_function) \
V(JSFunction, symbol_function) \
V(Map, fast_aliased_arguments_map) \
V(Map, initial_array_iterator_map) \
V(Map, initial_string_iterator_map) \
......@@ -282,6 +287,7 @@ class NativeContextRef : public ContextRef {
MapRef GetFunctionMapFromIndex(int index) const;
MapRef GetInitialJSArrayMap(ElementsKind kind) const;
base::Optional<JSFunctionRef> GetConstructorFunction(const MapRef& map) const;
};
class NameRef : public HeapObjectRef {
......@@ -347,6 +353,7 @@ class MapRef : public HeapObjectRef {
int GetInObjectPropertiesStartInWords() const;
int NumberOfOwnDescriptors() const;
int GetInObjectPropertyOffset(int index) const;
int constructor_function_index() const;
ElementsKind elements_kind() const;
bool is_stable() const;
bool is_constructor() const;
......@@ -357,6 +364,7 @@ class MapRef : public HeapObjectRef {
bool IsInobjectSlackTrackingInProgress() const;
bool is_dictionary_map() const;
bool IsFixedCowArrayMap() const;
bool IsPrimitiveMap() const;
bool is_undetectable() const;
bool is_callable() const;
......
......@@ -422,8 +422,8 @@ Reduction JSNativeContextSpecialization::ReduceJSInstanceOf(Node* node) {
Handle<JSObject> holder;
if (access_info.holder().ToHandle(&holder)) {
dependencies()->DependOnStablePrototypeChains(
broker(), native_context().object<Context>(),
access_info.receiver_maps(), holder);
broker(), access_info.receiver_maps(),
JSObjectRef(broker(), holder));
}
// Check that {constructor} is actually {receiver}.
......@@ -448,8 +448,7 @@ Reduction JSNativeContextSpecialization::ReduceJSInstanceOf(Node* node) {
Handle<JSObject> holder;
if (access_info.holder().ToHandle(&holder)) {
dependencies()->DependOnStablePrototypeChains(
broker(), native_context().object<Context>(),
access_info.receiver_maps(), holder);
broker(), access_info.receiver_maps(), JSObjectRef(broker(), holder));
} else {
holder = receiver;
}
......@@ -714,8 +713,7 @@ Reduction JSNativeContextSpecialization::ReduceJSResolvePromise(Node* node) {
Handle<JSObject> holder;
if (access_info.holder().ToHandle(&holder)) {
dependencies()->DependOnStablePrototypeChains(
broker(), native_context().object<Context>(),
access_info.receiver_maps(), holder);
broker(), access_info.receiver_maps(), JSObjectRef(broker(), holder));
}
// Simply fulfill the {promise} with the {resolution}.
......@@ -2031,8 +2029,7 @@ JSNativeContextSpecialization::BuildPropertyLoad(
PropertyAccessBuilder access_builder(jsgraph(), broker(), dependencies());
if (access_info.holder().ToHandle(&holder)) {
dependencies()->DependOnStablePrototypeChains(
broker(), native_context().object<Context>(),
access_info.receiver_maps(), holder);
broker(), access_info.receiver_maps(), JSObjectRef(broker(), holder));
}
// Generate the actual property access.
......@@ -2091,8 +2088,7 @@ JSNativeContextSpecialization::BuildPropertyStore(
if (access_info.holder().ToHandle(&holder)) {
DCHECK_NE(AccessMode::kStoreInLiteral, access_mode);
dependencies()->DependOnStablePrototypeChains(
broker(), native_context().object<Context>(),
access_info.receiver_maps(), holder);
broker(), access_info.receiver_maps(), JSObjectRef(broker(), holder));
}
DCHECK(!access_info.IsNotFound());
......@@ -3140,7 +3136,8 @@ bool JSNativeContextSpecialization::InferReceiverMaps(
// For untrusted receiver maps, we can still use the information
// if the maps are stable.
for (size_t i = 0; i < maps.size(); ++i) {
if (!maps[i]->is_stable()) return false;
MapRef map(broker(), maps[i]);
if (!map.is_stable()) return false;
}
for (size_t i = 0; i < maps.size(); ++i) {
receiver_maps->push_back(maps[i]);
......
......@@ -410,15 +410,15 @@ NodeProperties::InferReceiverMapsResult NodeProperties::InferReceiverMaps(
HeapObjectMatcher mtarget(GetValueInput(effect, 0));
HeapObjectMatcher mnewtarget(GetValueInput(effect, 1));
if (mtarget.HasValue() && mnewtarget.HasValue() &&
mnewtarget.Value()->IsJSFunction()) {
Handle<JSFunction> original_constructor =
Handle<JSFunction>::cast(mnewtarget.Value());
if (original_constructor->has_initial_map()) {
Handle<Map> initial_map(original_constructor->initial_map(),
broker->isolate());
if (initial_map->constructor_or_backpointer() ==
*mtarget.Value()) {
*maps_return = ZoneHandleSet<Map>(initial_map);
mnewtarget.Ref(broker).IsJSFunction()) {
JSFunctionRef original_constructor =
mnewtarget.Ref(broker).AsJSFunction();
if (original_constructor.has_initial_map()) {
original_constructor.Serialize();
MapRef initial_map = original_constructor.initial_map();
if (initial_map.constructor_or_backpointer().equals(
mtarget.Ref(broker))) {
*maps_return = ZoneHandleSet<Map>(initial_map.object<Map>());
return result;
}
}
......@@ -438,7 +438,7 @@ NodeProperties::InferReceiverMapsResult NodeProperties::InferReceiverMaps(
Node* const value = GetValueInput(effect, 1);
HeapObjectMatcher m(value);
if (m.HasValue()) {
*maps_return = ZoneHandleSet<Map>(Handle<Map>::cast(m.Value()));
*maps_return = ZoneHandleSet<Map>(m.Ref(broker).object<Map>());
return result;
}
}
......@@ -566,8 +566,9 @@ bool NodeProperties::CanBePrimitive(JSHeapBroker* broker, Node* receiver,
case IrOpcode::kJSToObject:
return false;
case IrOpcode::kHeapConstant: {
Handle<HeapObject> value = HeapObjectMatcher(receiver).Value();
return value->IsPrimitive();
HeapObjectRef value =
HeapObjectMatcher(receiver).Ref(broker).AsHeapObject();
return value.map().IsPrimitiveMap();
}
default: {
// We don't really care about the exact maps here,
......@@ -576,9 +577,10 @@ bool NodeProperties::CanBePrimitive(JSHeapBroker* broker, Node* receiver,
ZoneHandleSet<Map> maps;
if (InferReceiverMaps(broker, receiver, effect, &maps) !=
kNoReceiverMaps) {
// Check if all {maps} are actually JSReceiver maps.
// Check if one of the {maps} is not a JSReceiver map.
for (size_t i = 0; i < maps.size(); ++i) {
if (!maps[i]->IsJSReceiverMap()) return true;
MapRef map(broker, maps[i]);
if (!map.IsJSReceiverMap()) return true;
}
return false;
}
......@@ -606,8 +608,10 @@ bool NodeProperties::CanBeNullOrUndefined(JSHeapBroker* broker, Node* receiver,
case IrOpcode::kToBoolean:
return false;
case IrOpcode::kHeapConstant: {
Handle<HeapObject> value = HeapObjectMatcher(receiver).Value();
return value->IsNullOrUndefined(broker->isolate());
HeapObjectRef value =
HeapObjectMatcher(receiver).Ref(broker).AsHeapObject();
OddballType type = value.map().oddball_type();
return type == OddballType::kNull || type == OddballType::kUndefined;
}
default:
return true;
......
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