Commit d9221717 authored by Georg Neis's avatar Georg Neis Committed by Commit Bot

[turbofan] Unify code that determines a JSCreate's map

There were four places where we did essentially the same steps in
order to extract the initial map for inlining a JSCreate operation.
This CL creates a function on NodeProperties for this task.

As a side effect, this fixes a bug in ReduceJSCreateArray, where
has_initial_map could get called when it wasn't permissible to do so.

Notes: For simplicity, in one or two places where we used to get the
target/newtarget constants from the types we now get them from
HeapConstant nodes.

Cosmetic change: rename "receiver_map" to the more accurate
"root_map" in JSNativeContextSpecialization::ExtractReceiverMaps.

Bug: chromium:939316
Change-Id: I8fd9eb50993be3d839ab9b18eeea28184c53eabf
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1528435
Commit-Queue: Georg Neis <neis@chromium.org>
Reviewed-by: 's avatarBenedikt Meurer <bmeurer@chromium.org>
Reviewed-by: 's avatarJaroslav Sevcik <jarin@chromium.org>
Cr-Commit-Position: refs/heads/master@{#60301}
parent 6f2b87b8
This diff is collapsed.
......@@ -3360,15 +3360,15 @@ bool JSNativeContextSpecialization::ExtractReceiverMaps(
// Try to extract some maps from the {nexus}.
if (nexus.ExtractMaps(receiver_maps) != 0) {
// Try to filter impossible candidates based on inferred root map.
Handle<Map> receiver_map;
if (InferReceiverRootMap(receiver).ToHandle(&receiver_map)) {
DCHECK(!receiver_map->is_abandoned_prototype_map());
Handle<Map> root_map;
if (InferReceiverRootMap(receiver).ToHandle(&root_map)) {
DCHECK(!root_map->is_abandoned_prototype_map());
Isolate* isolate = this->isolate();
receiver_maps->erase(
std::remove_if(receiver_maps->begin(), receiver_maps->end(),
[receiver_map, isolate](const Handle<Map>& map) {
[root_map, isolate](Handle<Map> map) {
return map->is_abandoned_prototype_map() ||
map->FindRootMap(isolate) != *receiver_map;
map->FindRootMap(isolate) != *root_map;
}),
receiver_maps->end());
}
......@@ -3410,18 +3410,12 @@ MaybeHandle<Map> JSNativeContextSpecialization::InferReceiverRootMap(
if (m.HasValue()) {
return handle(m.Value()->map()->FindRootMap(isolate()), isolate());
} else if (m.IsJSCreate()) {
HeapObjectMatcher mtarget(m.InputAt(0));
HeapObjectMatcher mnewtarget(m.InputAt(1));
if (mtarget.HasValue() && mnewtarget.HasValue()) {
Handle<JSFunction> constructor =
Handle<JSFunction>::cast(mtarget.Value());
if (constructor->has_initial_map()) {
Handle<Map> initial_map(constructor->initial_map(), isolate());
if (initial_map->constructor_or_backpointer() == *mnewtarget.Value()) {
DCHECK_EQ(*initial_map, initial_map->FindRootMap(isolate()));
return initial_map;
}
}
base::Optional<MapRef> initial_map =
NodeProperties::GetJSCreateMap(broker(), receiver);
if (initial_map.has_value()) {
DCHECK_EQ(*initial_map->object(),
initial_map->object()->FindRootMap(isolate()));
return initial_map->object();
}
}
return MaybeHandle<Map>();
......
......@@ -361,6 +361,30 @@ bool NodeProperties::IsSame(Node* a, Node* b) {
}
}
// static
base::Optional<MapRef> NodeProperties::GetJSCreateMap(JSHeapBroker* broker,
Node* receiver) {
DCHECK(receiver->opcode() == IrOpcode::kJSCreate ||
receiver->opcode() == IrOpcode::kJSCreateArray);
HeapObjectMatcher mtarget(GetValueInput(receiver, 0));
HeapObjectMatcher mnewtarget(GetValueInput(receiver, 1));
if (mtarget.HasValue() && mnewtarget.HasValue() &&
mnewtarget.Ref(broker).IsJSFunction()) {
ObjectRef target = mtarget.Ref(broker);
JSFunctionRef newtarget = mnewtarget.Ref(broker).AsJSFunction();
if (newtarget.map().has_prototype_slot() && newtarget.has_initial_map()) {
if (broker->mode() == JSHeapBroker::kSerializing) newtarget.Serialize();
MapRef initial_map = newtarget.initial_map();
if (initial_map.GetConstructor().equals(target)) {
DCHECK(target.AsJSFunction().map().is_constructor());
DCHECK(newtarget.map().is_constructor());
return initial_map;
}
}
}
return base::nullopt;
}
// static
NodeProperties::InferReceiverMapsResult NodeProperties::InferReceiverMaps(
JSHeapBroker* broker, Node* receiver, Node* effect,
......@@ -406,21 +430,10 @@ NodeProperties::InferReceiverMapsResult NodeProperties::InferReceiverMaps(
}
case IrOpcode::kJSCreate: {
if (IsSame(receiver, effect)) {
HeapObjectMatcher mtarget(GetValueInput(effect, 0));
HeapObjectMatcher mnewtarget(GetValueInput(effect, 1));
if (mtarget.HasValue() && mnewtarget.HasValue() &&
mnewtarget.Ref(broker).IsJSFunction()) {
JSFunctionRef original_constructor =
mnewtarget.Ref(broker).AsJSFunction();
if (original_constructor.map().has_prototype_slot() &&
original_constructor.has_initial_map()) {
original_constructor.Serialize();
MapRef initial_map = original_constructor.initial_map();
if (initial_map.GetConstructor().equals(mtarget.Ref(broker))) {
*maps_return = ZoneHandleSet<Map>(initial_map.object());
return result;
}
}
base::Optional<MapRef> initial_map = GetJSCreateMap(broker, receiver);
if (initial_map.has_value()) {
*maps_return = ZoneHandleSet<Map>(initial_map->object());
return result;
}
// We reached the allocation of the {receiver}.
return kNoReceiverMaps;
......
......@@ -155,6 +155,10 @@ class V8_EXPORT_PRIVATE NodeProperties final {
JSHeapBroker* broker, Node* receiver, Node* effect,
ZoneHandleSet<Map>* maps_return);
// Return the initial map of the new-target if the allocation can be inlined.
static base::Optional<MapRef> GetJSCreateMap(JSHeapBroker* broker,
Node* receiver);
static bool HasInstanceTypeWitness(JSHeapBroker* broker, Node* receiver,
Node* effect, InstanceType instance_type);
......
......@@ -4,16 +4,36 @@
// Flags: --allow-natives-syntax
function f(arg) {
const o = Reflect.construct(Object, arguments, Proxy);
o.foo = arg;
}
function g(i) {
f(i);
}
g(0);
g(1);
%OptimizeFunctionOnNextCall(g);
g(2);
(function JSCreate() {
function f(arg) {
const o = Reflect.construct(Object, arguments, Proxy);
o.foo = arg;
}
function g(i) {
f(i);
}
g(0);
g(1);
%OptimizeFunctionOnNextCall(g);
g(2);
})();
(function JSCreateArray() {
function f() {
try {
const o = Reflect.construct(Array, arguments, parseInt);
} catch(e) { }
}
function g() {
f();
}
g();
g();
%OptimizeFunctionOnNextCall(g);
g();
})();
......@@ -74,8 +74,7 @@ class JSCreateLoweringTest : public TypedGraphTest {
TEST_F(JSCreateLoweringTest, JSCreate) {
Handle<JSFunction> function = isolate()->object_function();
Node* const target =
Parameter(Type::HeapConstant(broker(), function, graph()->zone()));
Node* const target = graph()->NewNode(common()->HeapConstant(function));
Node* const context = Parameter(Type::Any());
Node* const effect = graph()->start();
Node* const control = graph()->start();
......
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