Commit 1737b2c7 authored by bmeurer's avatar bmeurer Committed by Commit bot

[turbofan] Introduce LoadFunctionPrototype simplified operator.

Add a LoadFunctionPrototype simplified operator, similar to what
Crankshaft has, that loads the prototype property of a constructor
function.

R=jarin@chromium.org
BUG=v8:5267

Review-Url: https://codereview.chromium.org/2517913002
Cr-Commit-Position: refs/heads/master@{#41127}
parent f31e8054
......@@ -94,6 +94,13 @@ PropertyAccessInfo PropertyAccessInfo::AccessorConstant(
return PropertyAccessInfo(kAccessorConstant, holder, constant, receiver_maps);
}
// static
PropertyAccessInfo PropertyAccessInfo::FunctionPrototype(
MapList const& receiver_maps) {
return PropertyAccessInfo(kFunctionPrototype, MaybeHandle<JSObject>(),
Handle<Object>(), receiver_maps);
}
// static
PropertyAccessInfo PropertyAccessInfo::Generic(MapList const& receiver_maps) {
return PropertyAccessInfo(kGeneric, MaybeHandle<JSObject>(), Handle<Object>(),
......@@ -144,9 +151,6 @@ bool PropertyAccessInfo::Merge(PropertyAccessInfo const* that) {
case kInvalid:
break;
case kNotFound:
return true;
case kDataField: {
// Check if we actually access the same field.
if (this->transition_map_.address() == that->transition_map_.address() &&
......@@ -173,6 +177,9 @@ bool PropertyAccessInfo::Merge(PropertyAccessInfo const* that) {
}
return false;
}
case kNotFound:
case kFunctionPrototype:
case kGeneric: {
this->receiver_maps_.insert(this->receiver_maps_.end(),
that->receiver_maps_.begin(),
......@@ -449,6 +456,13 @@ bool AccessInfoFactory::ComputePropertyAccessInfos(
bool AccessInfoFactory::LookupSpecialFieldAccessor(
Handle<Map> map, Handle<Name> name, PropertyAccessInfo* access_info) {
// Check for Function::prototype accessor.
if (map->IsJSFunctionMap() && map->is_constructor() &&
name.is_identical_to(factory()->prototype_string())) {
DCHECK(!map->has_non_instance_prototype());
*access_info = PropertyAccessInfo::FunctionPrototype(MapList{map});
return true;
}
// Check for special JSObject field accessors.
int offset;
if (Accessors::IsJSObjectFieldAccessor(map, name, &offset)) {
......
......@@ -62,6 +62,7 @@ class PropertyAccessInfo final {
kDataConstant,
kDataField,
kAccessorConstant,
kFunctionPrototype,
kGeneric
};
......@@ -79,6 +80,7 @@ class PropertyAccessInfo final {
static PropertyAccessInfo AccessorConstant(MapList const& receiver_maps,
Handle<Object> constant,
MaybeHandle<JSObject> holder);
static PropertyAccessInfo FunctionPrototype(MapList const& receiver_maps);
static PropertyAccessInfo Generic(MapList const& receiver_maps);
PropertyAccessInfo();
......@@ -89,6 +91,7 @@ class PropertyAccessInfo final {
bool IsDataConstant() const { return kind() == kDataConstant; }
bool IsDataField() const { return kind() == kDataField; }
bool IsAccessorConstant() const { return kind() == kAccessorConstant; }
bool IsFunctionPrototype() const { return kind() == kFunctionPrototype; }
bool IsGeneric() const { return kind() == kGeneric; }
bool HasTransitionMap() const { return !transition_map().is_null(); }
......
......@@ -784,6 +784,9 @@ bool EffectControlLinearizer::TryWireInStateEffect(Node* node,
case IrOpcode::kStoreTypedElement:
state = LowerStoreTypedElement(node, *effect, *control);
break;
case IrOpcode::kLoadFunctionPrototype:
state = LowerLoadFunctionPrototype(node, *effect, *control);
break;
case IrOpcode::kFloat64RoundUp:
state = LowerFloat64RoundUp(node, *effect, *control);
break;
......@@ -3273,6 +3276,50 @@ EffectControlLinearizer::LowerStoreTypedElement(Node* node, Node* effect,
return ValueEffectControl(nullptr, effect, control);
}
EffectControlLinearizer::ValueEffectControl
EffectControlLinearizer::LowerLoadFunctionPrototype(Node* node, Node* effect,
Node* control) {
Node* function = node->InputAt(0);
// Load the {JSFunction::prototype-or-initial-map} field.
Node* function_prototype_or_initial_map = effect =
graph()->NewNode(simplified()->LoadField(
AccessBuilder::ForJSFunctionPrototypeOrInitialMap()),
function, effect, control);
Node* function_prototype_or_initial_map_map = effect =
graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
function, effect, control);
// Check if the {function} has an initial map.
Node* check0 = graph()->NewNode(
machine()->WordEqual(), function_prototype_or_initial_map_map,
jsgraph()->HeapConstant(factory()->meta_map()));
Node* branch0 =
graph()->NewNode(common()->Branch(BranchHint::kTrue), check0, control);
Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
Node* etrue0 = effect;
Node* vtrue0;
{
// Load the "prototype" from the initial map.
vtrue0 = etrue0 = graph()->NewNode(
simplified()->LoadField(AccessBuilder::ForMapPrototype()),
function_prototype_or_initial_map, etrue0, if_true0);
}
Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
Node* efalse0 = effect;
Node* vfalse0 = function_prototype_or_initial_map;
control = graph()->NewNode(common()->Merge(2), if_true0, if_false0);
effect = graph()->NewNode(common()->EffectPhi(2), etrue0, efalse0, control);
Node* value =
graph()->NewNode(common()->Phi(MachineRepresentation::kTaggedPointer, 2),
vtrue0, vfalse0, control);
return ValueEffectControl(value, effect, control);
}
EffectControlLinearizer::ValueEffectControl
EffectControlLinearizer::LowerFloat64RoundUp(Node* node, Node* effect,
Node* control) {
......
......@@ -178,6 +178,8 @@ class V8_EXPORT_PRIVATE EffectControlLinearizer {
Node* control);
ValueEffectControl LowerStoreTypedElement(Node* node, Node* effect,
Node* control);
ValueEffectControl LowerLoadFunctionPrototype(Node* node, Node* effect,
Node* control);
// Lowering of optional operators.
ValueEffectControl LowerFloat64RoundUp(Node* node, Node* effect,
......
......@@ -1194,6 +1194,10 @@ JSNativeContextSpecialization::BuildPropertyAccess(
jsgraph()->UndefinedConstant(), effect);
}
}
} else if (access_info.IsFunctionPrototype()) {
DCHECK_EQ(AccessMode::kLoad, access_mode);
value = effect = graph()->NewNode(simplified()->LoadFunctionPrototype(),
receiver, effect, control);
} else {
DCHECK(access_info.IsGeneric());
DCHECK_EQ(AccessMode::kStore, access_mode);
......
......@@ -317,6 +317,7 @@
V(StoreBuffer) \
V(StoreElement) \
V(StoreTypedElement) \
V(LoadFunctionPrototype) \
V(ObjectIsCallable) \
V(ObjectIsNumber) \
V(ObjectIsReceiver) \
......
......@@ -2385,6 +2385,12 @@ class RepresentationSelector {
SetOutput(node, MachineRepresentation::kNone);
return;
}
case IrOpcode::kLoadFunctionPrototype: {
if (truncation.IsUnused()) return VisitUnused(node);
VisitUnop(node, UseInfo::AnyTagged(),
MachineRepresentation::kTaggedPointer);
return;
}
case IrOpcode::kPlainPrimitiveToNumber: {
if (InputIs(node, Type::Boolean())) {
VisitUnop(node, UseInfo::Bool(), MachineRepresentation::kWord32);
......
......@@ -495,6 +495,13 @@ struct SimplifiedOperatorGlobalCache final {
};
ArrayBufferWasNeuteredOperator kArrayBufferWasNeutered;
struct LoadFunctionPrototypeOperator final : public Operator {
LoadFunctionPrototypeOperator()
: Operator(IrOpcode::kLoadFunctionPrototype, Operator::kEliminatable,
"LoadFunctionPrototype", 1, 1, 1, 1, 1, 0) {}
};
LoadFunctionPrototypeOperator kLoadFunctionPrototype;
template <CheckForMinusZeroMode kMode>
struct CheckedInt32MulOperator final
: public Operator1<CheckForMinusZeroMode> {
......@@ -639,6 +646,7 @@ SimplifiedOperatorBuilder::SimplifiedOperatorBuilder(Zone* zone)
PURE_OP_LIST(GET_FROM_CACHE)
CHECKED_OP_LIST(GET_FROM_CACHE)
GET_FROM_CACHE(ArrayBufferWasNeutered)
GET_FROM_CACHE(LoadFunctionPrototype)
#undef GET_FROM_CACHE
const Operator* SimplifiedOperatorBuilder::CheckedInt32Mul(
......
......@@ -390,6 +390,9 @@ class V8_EXPORT_PRIVATE SimplifiedOperatorBuilder final
// store-typed-element buffer, [base + external + index], value
const Operator* StoreTypedElement(ExternalArrayType const&);
// load-function-prototype function
const Operator* LoadFunctionPrototype();
private:
Zone* zone() const { return zone_; }
......
......@@ -1730,6 +1730,10 @@ Type* Typer::Visitor::TypeStoreTypedElement(Node* node) {
return nullptr;
}
Type* Typer::Visitor::TypeLoadFunctionPrototype(Node* node) {
return Type::NonInternal();
}
Type* Typer::Visitor::TypeObjectIsCallable(Node* node) {
return TypeUnaryOp(node, ObjectIsCallable);
}
......
......@@ -1129,6 +1129,10 @@ void Verifier::Visitor::Check(Node* node) {
case IrOpcode::kStoreTypedElement:
CheckNotTyped(node);
break;
case IrOpcode::kLoadFunctionPrototype:
CheckValueInputIs(node, 0, Type::Any());
CheckTypeIs(node, Type::NonInternal());
break;
case IrOpcode::kNumberSilenceNaN:
CheckValueInputIs(node, 0, Type::Number());
CheckTypeIs(node, Type::Number());
......
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