Commit e97b29a4 authored by jarin's avatar jarin Committed by Commit bot

[turbofan] Add type to the allocation operator.

This gives us more precise type information, so we can avoid some type
guards to refine the type information back.

The motivation for this is to help escape analysis by not introducing
redundant type guards (which escape analysis cannot handle yet even
though it could and should do).

Motivating example:

In the example below, the out-of-object property array for properties
fld5 and fld6 gets type Any when it is created by "o.fld5 = 5" (for
object literals, we store 4 properties in-objeca, the rest goes out
of object).

When we run load elimination for the load the out-of-object property
array (to store 6 into o.fld6), load elimination inserts TypeGuard to
enforce the Type::Internal() type. This makes escape analysis bail out
on this object, and we do not eliminate the object creation.

function f() {
  var o = {};
  o.fld1 = 1;
  o.fld2 = 2;
  o.fld3 = 3;
  o.fld4 = 4;
  o.fld5 = 5;
  o.fld6 = 6;
}

f();
f();
%OptimizeFunctionOnNextCall(f);
f();

Review-Url: https://codereview.chromium.org/2797993006
Cr-Commit-Position: refs/heads/master@{#44470}
parent fae3f6bf
......@@ -99,8 +99,8 @@ Node* GraphAssembler::Projection(int index, Node* value) {
Node* GraphAssembler::Allocate(PretenureFlag pretenure, Node* size) {
return current_effect_ =
graph()->NewNode(simplified()->Allocate(NOT_TENURED), size,
current_effect_, current_control_);
graph()->NewNode(simplified()->Allocate(Type::Any(), NOT_TENURED),
size, current_effect_, current_control_);
}
Node* GraphAssembler::LoadField(FieldAccess const& access, Node* object) {
......
......@@ -295,9 +295,8 @@ Reduction JSBuiltinReducer::ReduceArrayIterator(Handle<Map> receiver_map,
effect = graph()->NewNode(
common()->BeginRegion(RegionObservability::kNotObservable), effect);
Node* value = effect = graph()->NewNode(
simplified()->Allocate(NOT_TENURED),
simplified()->Allocate(Type::OtherObject(), NOT_TENURED),
jsgraph()->Constant(JSArrayIterator::kSize), effect, control);
NodeProperties::SetType(value, Type::OtherObject());
effect = graph()->NewNode(simplified()->StoreField(AccessBuilder::ForMap()),
value, jsgraph()->Constant(map), effect, control);
effect = graph()->NewNode(
......@@ -1582,7 +1581,7 @@ Reduction JSBuiltinReducer::ReduceObjectCreate(Node* node) {
common()->BeginRegion(RegionObservability::kNotObservable), effect);
Node* value = effect =
graph()->NewNode(simplified()->Allocate(NOT_TENURED),
graph()->NewNode(simplified()->Allocate(Type::Any(), NOT_TENURED),
jsgraph()->Constant(size), effect, control);
effect =
graph()->NewNode(simplified()->StoreField(AccessBuilder::ForMap()),
......@@ -1635,7 +1634,7 @@ Reduction JSBuiltinReducer::ReduceObjectCreate(Node* node) {
effect = graph()->NewNode(
common()->BeginRegion(RegionObservability::kNotObservable), effect);
Node* value = effect =
graph()->NewNode(simplified()->Allocate(NOT_TENURED),
graph()->NewNode(simplified()->Allocate(Type::Any(), NOT_TENURED),
jsgraph()->Constant(instance_size), effect, control);
effect =
graph()->NewNode(simplified()->StoreField(AccessBuilder::ForMap()), value,
......@@ -1878,9 +1877,8 @@ Reduction JSBuiltinReducer::ReduceStringIterator(Node* node) {
effect = graph()->NewNode(
common()->BeginRegion(RegionObservability::kNotObservable), effect);
Node* value = effect = graph()->NewNode(
simplified()->Allocate(NOT_TENURED),
simplified()->Allocate(Type::OtherObject(), NOT_TENURED),
jsgraph()->Constant(JSStringIterator::kSize), effect, control);
NodeProperties::SetType(value, Type::OtherObject());
effect = graph()->NewNode(simplified()->StoreField(AccessBuilder::ForMap()),
value, map, effect, control);
effect = graph()->NewNode(
......
......@@ -43,11 +43,8 @@ class AllocationBuilder final {
effect_ = graph()->NewNode(
common()->BeginRegion(RegionObservability::kNotObservable), effect_);
allocation_ =
graph()->NewNode(simplified()->Allocate(pretenure),
graph()->NewNode(simplified()->Allocate(type, pretenure),
jsgraph()->Constant(size), effect_, control_);
// TODO(turbofan): Maybe we should put the Type* onto the Allocate operator
// at some point, or maybe we should have a completely differnt story.
NodeProperties::SetType(allocation_, type);
effect_ = allocation_;
}
......
......@@ -1520,7 +1520,7 @@ JSNativeContextSpecialization::BuildPropertyAccess(
common()->BeginRegion(RegionObservability::kNotObservable),
effect);
Node* box = effect = graph()->NewNode(
simplified()->Allocate(NOT_TENURED),
simplified()->Allocate(Type::OtherInternal(), NOT_TENURED),
jsgraph()->Constant(HeapNumber::kSize), effect, control);
effect = graph()->NewNode(
simplified()->StoreField(AccessBuilder::ForMap()), box,
......@@ -2209,7 +2209,7 @@ Node* JSNativeContextSpecialization::BuildExtendPropertiesBackingStore(
effect = graph()->NewNode(
common()->BeginRegion(RegionObservability::kNotObservable), effect);
Node* new_properties = effect = graph()->NewNode(
simplified()->Allocate(NOT_TENURED),
simplified()->Allocate(Type::OtherInternal(), NOT_TENURED),
jsgraph()->Constant(FixedArray::SizeFor(new_length)), effect, control);
effect = graph()->NewNode(simplified()->StoreField(AccessBuilder::ForMap()),
new_properties, jsgraph()->FixedArrayMapConstant(),
......
......@@ -712,9 +712,8 @@ Reduction JSTypedLowering::ReduceCreateConsString(Node* node) {
effect = graph()->NewNode(
common()->BeginRegion(RegionObservability::kNotObservable), effect);
Node* value = effect =
graph()->NewNode(simplified()->Allocate(NOT_TENURED),
graph()->NewNode(simplified()->Allocate(Type::OtherString(), NOT_TENURED),
jsgraph()->Constant(ConsString::kSize), effect, control);
NodeProperties::SetType(value, Type::OtherString());
effect = graph()->NewNode(simplified()->StoreField(AccessBuilder::ForMap()),
value, value_map, effect, control);
effect = graph()->NewNode(
......
......@@ -388,9 +388,32 @@ NumberOperationHint NumberOperationHintOf(const Operator* op) {
return OpParameter<NumberOperationHint>(op);
}
size_t hash_value(AllocateParameters info) {
return base::hash_combine(info.type(), info.pretenure());
}
V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os,
AllocateParameters info) {
info.type()->PrintTo(os);
return os << ", " << info.pretenure();
}
bool operator==(AllocateParameters const& lhs, AllocateParameters const& rhs) {
return lhs.pretenure() == rhs.pretenure() && lhs.type() == rhs.type();
}
bool operator!=(AllocateParameters const& lhs, AllocateParameters const& rhs) {
return !(lhs == rhs);
}
PretenureFlag PretenureFlagOf(const Operator* op) {
DCHECK_EQ(IrOpcode::kAllocate, op->opcode());
return OpParameter<PretenureFlag>(op);
return OpParameter<AllocateParameters>(op).pretenure();
}
Type* AllocateTypeOf(const Operator* op) {
DCHECK_EQ(IrOpcode::kAllocate, op->opcode());
return OpParameter<AllocateParameters>(op).type();
}
UnicodeEncoding UnicodeEncodingOf(const Operator* op) {
......@@ -646,17 +669,6 @@ struct SimplifiedOperatorGlobalCache final {
CheckFloat64HoleNaNOperator<CheckFloat64HoleMode::kNeverReturnHole>
kCheckFloat64HoleNeverReturnHoleOperator;
template <PretenureFlag kPretenure>
struct AllocateOperator final : public Operator1<PretenureFlag> {
AllocateOperator()
: Operator1<PretenureFlag>(
IrOpcode::kAllocate,
Operator::kNoDeopt | Operator::kNoThrow | Operator::kNoWrite,
"Allocate", 1, 1, 1, 1, 1, 0, kPretenure) {}
};
AllocateOperator<NOT_TENURED> kAllocateNotTenuredOperator;
AllocateOperator<TENURED> kAllocateTenuredOperator;
struct EnsureWritableFastElementsOperator final : public Operator {
EnsureWritableFastElementsOperator()
: Operator( // --
......@@ -864,15 +876,12 @@ bool IsRestLengthOf(const Operator* op) {
return OpParameter<ArgumentsLengthParameters>(op).is_rest_length;
}
const Operator* SimplifiedOperatorBuilder::Allocate(PretenureFlag pretenure) {
switch (pretenure) {
case NOT_TENURED:
return &cache_.kAllocateNotTenuredOperator;
case TENURED:
return &cache_.kAllocateTenuredOperator;
}
UNREACHABLE();
return nullptr;
const Operator* SimplifiedOperatorBuilder::Allocate(Type* type,
PretenureFlag pretenure) {
return new (zone()) Operator1<AllocateParameters>(
IrOpcode::kAllocate,
Operator::kNoDeopt | Operator::kNoThrow | Operator::kNoWrite, "Allocate",
1, 1, 1, 1, 1, 0, AllocateParameters(type, pretenure));
}
......
......@@ -245,8 +245,30 @@ NumberOperationHint NumberOperationHintOf(const Operator* op)
int FormalParameterCountOf(const Operator* op) WARN_UNUSED_RESULT;
bool IsRestLengthOf(const Operator* op) WARN_UNUSED_RESULT;
class AllocateParameters {
public:
AllocateParameters(Type* type, PretenureFlag pretenure)
: type_(type), pretenure_(pretenure) {}
Type* type() const { return type_; }
PretenureFlag pretenure() const { return pretenure_; }
private:
Type* type_;
PretenureFlag pretenure_;
};
size_t hash_value(AllocateParameters);
V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream&, AllocateParameters);
bool operator==(AllocateParameters const&, AllocateParameters const&);
bool operator!=(AllocateParameters const&, AllocateParameters const&);
PretenureFlag PretenureFlagOf(const Operator* op) WARN_UNUSED_RESULT;
Type* AllocateTypeOf(const Operator* op) WARN_UNUSED_RESULT;
UnicodeEncoding UnicodeEncodingOf(const Operator*) WARN_UNUSED_RESULT;
// Interface for building simplified operators, which represent the
......@@ -442,7 +464,7 @@ class V8_EXPORT_PRIVATE SimplifiedOperatorBuilder final
// transition-elements-kind object, from-map, to-map
const Operator* TransitionElementsKind(ElementsTransition transition);
const Operator* Allocate(PretenureFlag pretenure = NOT_TENURED);
const Operator* Allocate(Type* type, PretenureFlag pretenure = NOT_TENURED);
const Operator* LoadField(FieldAccess const&);
const Operator* StoreField(FieldAccess const&);
......
......@@ -1876,7 +1876,9 @@ Type* Typer::Visitor::TypeConvertTaggedHoleToUndefined(Node* node) {
return type;
}
Type* Typer::Visitor::TypeAllocate(Node* node) { return Type::Any(); }
Type* Typer::Visitor::TypeAllocate(Node* node) {
return AllocateTypeOf(node->op());
}
Type* Typer::Visitor::TypeLoadField(Node* node) {
return FieldAccessOf(node->op()).type;
......
......@@ -66,8 +66,8 @@ class EscapeAnalysisTest : public TypedGraphTest {
if (!control) {
control = control_;
}
return effect_ = graph()->NewNode(simplified()->Allocate(), size, effect,
control);
return effect_ = graph()->NewNode(simplified()->Allocate(Type::Any()), size,
effect, control);
}
Node* Constant(int num) {
......
......@@ -465,7 +465,7 @@ TEST_F(LoadEliminationTest, AliasAnalysisForFinishRegion) {
load_elimination.Reduce(effect);
Node* object0 = effect =
graph()->NewNode(simplified()->Allocate(NOT_TENURED),
graph()->NewNode(simplified()->Allocate(Type::Any(), NOT_TENURED),
jsgraph()->Constant(16), effect, control);
load_elimination.Reduce(effect);
......@@ -478,7 +478,7 @@ TEST_F(LoadEliminationTest, AliasAnalysisForFinishRegion) {
load_elimination.Reduce(effect);
Node* object1 = effect =
graph()->NewNode(simplified()->Allocate(NOT_TENURED),
graph()->NewNode(simplified()->Allocate(Type::Any(), NOT_TENURED),
jsgraph()->Constant(16), effect, control);
load_elimination.Reduce(effect);
......
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