Commit 5450fc07 authored by mvstanton's avatar mvstanton Committed by Commit bot

VectorICs: allocating slots for store ics in ast nodes.

Also adapt code generation to pass the slot to the
store/keyed-store ic. AST nodes ObjectLiteral, Assignment,
ForEach, Call and CountOperation now include one or more
feedback vector ic slot ids.

BUG=

Review URL: https://codereview.chromium.org/1161623002

Cr-Commit-Position: refs/heads/master@{#28659}
parent 42fc4310
This diff is collapsed.
This diff is collapsed.
......@@ -313,6 +313,7 @@ void AstNumberingVisitor::VisitAssignment(Assignment* node) {
if (node->is_compound()) VisitBinaryOperation(node->binary_operation());
Visit(node->target());
Visit(node->value());
ReserveFeedbackSlots(node);
}
......@@ -342,11 +343,11 @@ void AstNumberingVisitor::VisitSpread(Spread* node) {
void AstNumberingVisitor::VisitForInStatement(ForInStatement* node) {
IncrementNodeCount();
DisableSelfOptimization();
ReserveFeedbackSlots(node);
node->set_base_id(ReserveIdRange(ForInStatement::num_ids()));
Visit(node->each());
Visit(node->enumerable());
Visit(node->body());
ReserveFeedbackSlots(node);
}
......@@ -359,6 +360,7 @@ void AstNumberingVisitor::VisitForOfStatement(ForOfStatement* node) {
Visit(node->result_done());
Visit(node->assign_each());
Visit(node->body());
ReserveFeedbackSlots(node);
}
......@@ -437,6 +439,7 @@ void AstNumberingVisitor::VisitObjectLiteral(ObjectLiteral* node) {
// is shadowed by a later occurrence of the same key. For the
// marked expressions, no store code will be is emitted.
node->CalculateEmitStore(zone());
ReserveFeedbackSlots(node);
}
......
......@@ -121,16 +121,73 @@ FeedbackVectorRequirements VariableProxy::ComputeFeedbackRequirements(
}
static int GetStoreICSlots(Expression* expr) {
int ic_slots = 0;
if (FLAG_vector_stores) {
Property* property = expr->AsProperty();
LhsKind assign_type = Property::GetAssignType(property);
if ((assign_type == VARIABLE &&
expr->AsVariableProxy()->var()->IsUnallocated()) ||
assign_type == NAMED_PROPERTY || assign_type == KEYED_PROPERTY) {
ic_slots++;
}
}
return ic_slots;
}
static Code::Kind GetStoreICKind(Expression* expr) {
LhsKind assign_type = Property::GetAssignType(expr->AsProperty());
return assign_type == KEYED_PROPERTY ? Code::KEYED_STORE_IC : Code::STORE_IC;
}
FeedbackVectorRequirements ForEachStatement::ComputeFeedbackRequirements(
Isolate* isolate, const ICSlotCache* cache) {
int ic_slots = GetStoreICSlots(each());
return FeedbackVectorRequirements(0, ic_slots);
}
Code::Kind ForEachStatement::FeedbackICSlotKind(int index) {
return GetStoreICKind(each());
}
Assignment::Assignment(Zone* zone, Token::Value op, Expression* target,
Expression* value, int pos)
: Expression(zone, pos),
bit_field_(IsUninitializedField::encode(false) |
KeyTypeField::encode(ELEMENT) |
StoreModeField::encode(STANDARD_STORE) |
TokenField::encode(op)),
bit_field_(
IsUninitializedField::encode(false) | KeyTypeField::encode(ELEMENT) |
StoreModeField::encode(STANDARD_STORE) | TokenField::encode(op)),
target_(target),
value_(value),
binary_operation_(NULL) {}
binary_operation_(NULL),
slot_(FeedbackVectorICSlot::Invalid()) {}
FeedbackVectorRequirements Assignment::ComputeFeedbackRequirements(
Isolate* isolate, const ICSlotCache* cache) {
int ic_slots = GetStoreICSlots(target());
return FeedbackVectorRequirements(0, ic_slots);
}
Code::Kind Assignment::FeedbackICSlotKind(int index) {
return GetStoreICKind(target());
}
FeedbackVectorRequirements CountOperation::ComputeFeedbackRequirements(
Isolate* isolate, const ICSlotCache* cache) {
int ic_slots = GetStoreICSlots(expression());
return FeedbackVectorRequirements(0, ic_slots);
}
Code::Kind CountOperation::FeedbackICSlotKind(int index) {
return GetStoreICKind(expression());
}
Token::Value Assignment::binary_op() const {
......@@ -253,6 +310,56 @@ bool ObjectLiteral::Property::emit_store() {
}
FeedbackVectorRequirements ObjectLiteral::ComputeFeedbackRequirements(
Isolate* isolate, const ICSlotCache* cache) {
if (!FLAG_vector_stores) return FeedbackVectorRequirements(0, 0);
// This logic that computes the number of slots needed for vector store
// ics must mirror FullCodeGenerator::VisitObjectLiteral.
int ic_slots = 0;
for (int i = 0; i < properties()->length(); i++) {
ObjectLiteral::Property* property = properties()->at(i);
if (property->IsCompileTimeValue()) continue;
Expression* value = property->value();
if (property->is_computed_name() &&
property->kind() != ObjectLiteral::Property::PROTOTYPE) {
if (FunctionLiteral::NeedsHomeObject(value)) ic_slots++;
} else if (property->emit_store()) {
if (property->kind() == ObjectLiteral::Property::MATERIALIZED_LITERAL ||
property->kind() == ObjectLiteral::Property::COMPUTED) {
Literal* key = property->key()->AsLiteral();
if (key->value()->IsInternalizedString()) ic_slots++;
if (FunctionLiteral::NeedsHomeObject(value)) ic_slots++;
} else if (property->kind() == ObjectLiteral::Property::GETTER ||
property->kind() == ObjectLiteral::Property::SETTER) {
// We might need a slot for the home object.
if (FunctionLiteral::NeedsHomeObject(value)) ic_slots++;
}
}
}
#ifdef DEBUG
// FullCodeGenerator::VisitObjectLiteral verifies that it consumes slot_count_
// slots.
slot_count_ = ic_slots;
#endif
return FeedbackVectorRequirements(0, ic_slots);
}
FeedbackVectorICSlot ObjectLiteral::SlotForHomeObject(Expression* value,
int* slot_index) const {
if (FLAG_vector_stores && FunctionLiteral::NeedsHomeObject(value)) {
DCHECK(slot_index != NULL && *slot_index >= 0 && *slot_index < slot_count_);
FeedbackVectorICSlot slot = GetNthSlot(*slot_index);
*slot_index += 1;
return slot;
}
return FeedbackVectorICSlot::Invalid();
}
void ObjectLiteral::CalculateEmitStore(Zone* zone) {
const auto GETTER = ObjectLiteral::Property::GETTER;
const auto SETTER = ObjectLiteral::Property::SETTER;
......@@ -590,7 +697,10 @@ void Expression::RecordToBooleanTypeFeedback(TypeFeedbackOracle* oracle) {
bool Call::IsUsingCallFeedbackICSlot(Isolate* isolate) const {
CallType call_type = GetCallType(isolate);
if (IsUsingCallFeedbackSlot(isolate) || call_type == POSSIBLY_EVAL_CALL) {
if (call_type == POSSIBLY_EVAL_CALL) {
return false;
}
if (call_type == SUPER_CALL && !FLAG_vector_stores) {
return false;
}
return true;
......@@ -599,7 +709,7 @@ bool Call::IsUsingCallFeedbackICSlot(Isolate* isolate) const {
bool Call::IsUsingCallFeedbackSlot(Isolate* isolate) const {
// SuperConstructorCall uses a CallConstructStub, which wants
// a Slot, not an IC slot.
// a Slot, in addition to any IC slots requested elsewhere.
return GetCallType(isolate) == SUPER_CALL;
}
......@@ -608,8 +718,6 @@ FeedbackVectorRequirements Call::ComputeFeedbackRequirements(
Isolate* isolate, const ICSlotCache* cache) {
int ic_slots = IsUsingCallFeedbackICSlot(isolate) ? 1 : 0;
int slots = IsUsingCallFeedbackSlot(isolate) ? 1 : 0;
// A Call uses either a slot or an IC slot.
DCHECK((ic_slots & slots) == 0);
return FeedbackVectorRequirements(slots, ic_slots);
}
......
......@@ -796,13 +796,26 @@ class ForEachStatement : public IterationStatement {
Expression* each() const { return each_; }
Expression* subject() const { return subject_; }
FeedbackVectorRequirements ComputeFeedbackRequirements(
Isolate* isolate, const ICSlotCache* cache) override;
void SetFirstFeedbackICSlot(FeedbackVectorICSlot slot,
ICSlotCache* cache) override {
each_slot_ = slot;
}
Code::Kind FeedbackICSlotKind(int index) override;
FeedbackVectorICSlot EachFeedbackSlot() const { return each_slot_; }
protected:
ForEachStatement(Zone* zone, ZoneList<const AstRawString*>* labels, int pos)
: IterationStatement(zone, labels, pos), each_(NULL), subject_(NULL) {}
: IterationStatement(zone, labels, pos),
each_(NULL),
subject_(NULL),
each_slot_(FeedbackVectorICSlot::Invalid()) {}
private:
Expression* each_;
Expression* subject_;
FeedbackVectorICSlot each_slot_;
};
......@@ -815,9 +828,12 @@ class ForInStatement final : public ForEachStatement {
}
// Type feedback information.
virtual FeedbackVectorRequirements ComputeFeedbackRequirements(
FeedbackVectorRequirements ComputeFeedbackRequirements(
Isolate* isolate, const ICSlotCache* cache) override {
return FeedbackVectorRequirements(1, 0);
FeedbackVectorRequirements base =
ForEachStatement::ComputeFeedbackRequirements(isolate, cache);
DCHECK(base.slots() == 0 && base.ic_slots() <= 1);
return FeedbackVectorRequirements(1, base.ic_slots());
}
void SetFirstFeedbackSlot(FeedbackVectorSlot slot) override {
for_in_feedback_slot_ = slot;
......@@ -1457,17 +1473,44 @@ class ObjectLiteral final : public MaterializedLiteral {
// ObjectLiteral can vary, so num_ids() is not a static method.
int num_ids() const { return parent_num_ids() + 1 + properties()->length(); }
// Object literals need one feedback slot for each non-trivial value, as well
// as some slots for home objects.
FeedbackVectorRequirements ComputeFeedbackRequirements(
Isolate* isolate, const ICSlotCache* cache) override;
void SetFirstFeedbackICSlot(FeedbackVectorICSlot slot,
ICSlotCache* cache) override {
slot_ = slot;
}
Code::Kind FeedbackICSlotKind(int index) override { return Code::STORE_IC; }
FeedbackVectorICSlot GetNthSlot(int n) const {
return FeedbackVectorICSlot(slot_.ToInt() + n);
}
// If value needs a home object, returns a valid feedback vector ic slot
// given by slot_index, and increments slot_index.
FeedbackVectorICSlot SlotForHomeObject(Expression* value,
int* slot_index) const;
#ifdef DEBUG
int slot_count() const { return slot_count_; }
#endif
protected:
ObjectLiteral(Zone* zone, ZoneList<Property*>* properties, int literal_index,
int boilerplate_properties, bool has_function,
bool is_strong, int pos)
int boilerplate_properties, bool has_function, bool is_strong,
int pos)
: MaterializedLiteral(zone, literal_index, is_strong, pos),
properties_(properties),
boilerplate_properties_(boilerplate_properties),
fast_elements_(false),
has_elements_(false),
may_store_doubles_(false),
has_function_(has_function) {}
has_function_(has_function),
#ifdef DEBUG
slot_count_(0),
#endif
slot_(FeedbackVectorICSlot::Invalid()) {
}
static int parent_num_ids() { return MaterializedLiteral::num_ids(); }
private:
......@@ -1479,6 +1522,12 @@ class ObjectLiteral final : public MaterializedLiteral {
bool has_elements_;
bool may_store_doubles_;
bool has_function_;
#ifdef DEBUG
// slot_count_ helps validate that the logic to allocate ic slots and the
// logic to use them are in sync.
int slot_count_;
#endif
FeedbackVectorICSlot slot_;
};
......@@ -1654,6 +1703,17 @@ class VariableProxy final : public Expression {
};
// Left-hand side can only be a property, a global or a (parameter or local)
// slot.
enum LhsKind {
VARIABLE,
NAMED_PROPERTY,
KEYED_PROPERTY,
NAMED_SUPER_PROPERTY,
KEYED_SUPER_PROPERTY
};
class Property final : public Expression {
public:
DECLARE_NODE_TYPE(Property)
......@@ -1721,6 +1781,14 @@ class Property final : public Expression {
return property_feedback_slot_;
}
static LhsKind GetAssignType(Property* property) {
if (property == NULL) return VARIABLE;
bool super_access = property->IsSuperAccess();
return (property->key()->IsPropertyName())
? (super_access ? NAMED_SUPER_PROPERTY : NAMED_PROPERTY)
: (super_access ? KEYED_SUPER_PROPERTY : KEYED_PROPERTY);
}
protected:
Property(Zone* zone, Expression* obj, Expression* key, int pos)
: Expression(zone, pos),
......@@ -1759,22 +1827,14 @@ class Call final : public Expression {
Isolate* isolate, const ICSlotCache* cache) override;
void SetFirstFeedbackICSlot(FeedbackVectorICSlot slot,
ICSlotCache* cache) override {
ic_slot_or_slot_ = slot.ToInt();
}
void SetFirstFeedbackSlot(FeedbackVectorSlot slot) override {
ic_slot_or_slot_ = slot.ToInt();
ic_slot_ = slot;
}
void SetFirstFeedbackSlot(FeedbackVectorSlot slot) override { slot_ = slot; }
Code::Kind FeedbackICSlotKind(int index) override { return Code::CALL_IC; }
FeedbackVectorSlot CallFeedbackSlot() const {
DCHECK(ic_slot_or_slot_ != FeedbackVectorSlot::Invalid().ToInt());
return FeedbackVectorSlot(ic_slot_or_slot_);
}
FeedbackVectorSlot CallFeedbackSlot() const { return slot_; }
FeedbackVectorICSlot CallFeedbackICSlot() const {
DCHECK(ic_slot_or_slot_ != FeedbackVectorICSlot::Invalid().ToInt());
return FeedbackVectorICSlot(ic_slot_or_slot_);
}
FeedbackVectorICSlot CallFeedbackICSlot() const { return ic_slot_; }
SmallMapList* GetReceiverTypes() override {
if (expression()->IsProperty()) {
......@@ -1846,7 +1906,8 @@ class Call final : public Expression {
Call(Zone* zone, Expression* expression, ZoneList<Expression*>* arguments,
int pos)
: Expression(zone, pos),
ic_slot_or_slot_(FeedbackVectorICSlot::Invalid().ToInt()),
ic_slot_(FeedbackVectorICSlot::Invalid()),
slot_(FeedbackVectorSlot::Invalid()),
expression_(expression),
arguments_(arguments),
bit_field_(IsUninitializedField::encode(false)) {
......@@ -1859,9 +1920,8 @@ class Call final : public Expression {
private:
int local_id(int n) const { return base_id() + parent_num_ids() + n; }
// We store this as an integer because we don't know if we have a slot or
// an ic slot until scoping time.
int ic_slot_or_slot_;
FeedbackVectorICSlot ic_slot_;
FeedbackVectorSlot slot_;
Expression* expression_;
ZoneList<Expression*>* arguments_;
Handle<JSFunction> target_;
......@@ -2120,16 +2180,25 @@ class CountOperation final : public Expression {
return TypeFeedbackId(local_id(3));
}
FeedbackVectorRequirements ComputeFeedbackRequirements(
Isolate* isolate, const ICSlotCache* cache) override;
void SetFirstFeedbackICSlot(FeedbackVectorICSlot slot,
ICSlotCache* cache) override {
slot_ = slot;
}
Code::Kind FeedbackICSlotKind(int index) override;
FeedbackVectorICSlot CountSlot() const { return slot_; }
protected:
CountOperation(Zone* zone, Token::Value op, bool is_prefix, Expression* expr,
int pos)
: Expression(zone, pos),
bit_field_(IsPrefixField::encode(is_prefix) |
KeyTypeField::encode(ELEMENT) |
StoreModeField::encode(STANDARD_STORE) |
TokenField::encode(op)),
bit_field_(
IsPrefixField::encode(is_prefix) | KeyTypeField::encode(ELEMENT) |
StoreModeField::encode(STANDARD_STORE) | TokenField::encode(op)),
type_(NULL),
expression_(expr) {}
expression_(expr),
slot_(FeedbackVectorICSlot::Invalid()) {}
static int parent_num_ids() { return Expression::num_ids(); }
private:
......@@ -2146,6 +2215,7 @@ class CountOperation final : public Expression {
Type* type_;
Expression* expression_;
SmallMapList receiver_types_;
FeedbackVectorICSlot slot_;
};
......@@ -2288,6 +2358,15 @@ class Assignment final : public Expression {
bit_field_ = StoreModeField::update(bit_field_, mode);
}
FeedbackVectorRequirements ComputeFeedbackRequirements(
Isolate* isolate, const ICSlotCache* cache) override;
void SetFirstFeedbackICSlot(FeedbackVectorICSlot slot,
ICSlotCache* cache) override {
slot_ = slot;
}
Code::Kind FeedbackICSlotKind(int index) override;
FeedbackVectorICSlot AssignmentSlot() const { return slot_; }
protected:
Assignment(Zone* zone, Token::Value op, Expression* target, Expression* value,
int pos);
......@@ -2308,6 +2387,7 @@ class Assignment final : public Expression {
Expression* value_;
BinaryOperation* binary_operation_;
SmallMapList receiver_types_;
FeedbackVectorICSlot slot_;
};
......
......@@ -591,26 +591,6 @@ class FullCodeGenerator: public AstVisitor {
void EmitLoadJSRuntimeFunction(CallRuntime* expr);
void EmitCallJSRuntimeFunction(CallRuntime* expr);
// Platform-specific support for compiling assignments.
// Left-hand side can only be a property, a global or a (parameter or local)
// slot.
enum LhsKind {
VARIABLE,
NAMED_PROPERTY,
KEYED_PROPERTY,
NAMED_SUPER_PROPERTY,
KEYED_SUPER_PROPERTY
};
static LhsKind GetAssignType(Property* property) {
if (property == NULL) return VARIABLE;
bool super_access = property->IsSuperAccess();
return (property->key()->IsPropertyName())
? (super_access ? NAMED_SUPER_PROPERTY : NAMED_PROPERTY)
: (super_access ? KEYED_SUPER_PROPERTY : KEYED_PROPERTY);
}
// Load a value from a named property.
// The receiver is left on the stack by the IC.
void EmitNamedPropertyLoad(Property* expr);
......@@ -647,13 +627,16 @@ class FullCodeGenerator: public AstVisitor {
Expression* right);
// Assign to the given expression as if via '='. The right-hand-side value
// is expected in the accumulator.
void EmitAssignment(Expression* expr);
// is expected in the accumulator. slot is only used if FLAG_vector_stores
// is true.
void EmitAssignment(Expression* expr, FeedbackVectorICSlot slot =
FeedbackVectorICSlot::Invalid());
// Complete a variable assignment. The right-hand-side value is expected
// in the accumulator.
void EmitVariableAssignment(Variable* var,
Token::Value op);
void EmitVariableAssignment(
Variable* var, Token::Value op,
FeedbackVectorICSlot slot = FeedbackVectorICSlot::Invalid());
// Helper functions to EmitVariableAssignment
void EmitStoreToStackLocalOrContextSlot(Variable* var,
......@@ -683,10 +666,14 @@ class FullCodeGenerator: public AstVisitor {
// Adds the [[HomeObject]] to |initializer| if it is a FunctionLiteral.
// The value of the initializer is expected to be at the top of the stack.
// |offset| is the offset in the stack where the home object can be found.
void EmitSetHomeObjectIfNeeded(Expression* initializer, int offset);
void EmitSetHomeObjectIfNeeded(
Expression* initializer, int offset,
FeedbackVectorICSlot slot = FeedbackVectorICSlot::Invalid());
void EmitLoadSuperConstructor();
void EmitInitializeThisAfterSuper(SuperReference* super_ref);
void EmitInitializeThisAfterSuper(
SuperReference* super_ref,
FeedbackVectorICSlot slot = FeedbackVectorICSlot::Invalid());
void CallIC(Handle<Code> code,
TypeFeedbackId id = TypeFeedbackId::None());
......@@ -764,6 +751,8 @@ class FullCodeGenerator: public AstVisitor {
bool MustCreateObjectLiteralWithRuntime(ObjectLiteral* expr) const;
bool MustCreateArrayLiteralWithRuntime(ArrayLiteral* expr) const;
void EmitLoadStoreICSlot(FeedbackVectorICSlot slot);
Handle<HandlerTable> handler_table() { return handler_table_; }
struct BailoutEntry {
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -23,6 +23,12 @@ TypeFeedbackVector::VectorICKind TypeFeedbackVector::FromCodeKind(
return KindLoadIC;
case Code::KEYED_LOAD_IC:
return KindKeyedLoadIC;
case Code::STORE_IC:
DCHECK(FLAG_vector_stores);
return KindStoreIC;
case Code::KEYED_STORE_IC:
DCHECK(FLAG_vector_stores);
return KindKeyedStoreIC;
default:
// Shouldn't get here.
UNREACHABLE();
......@@ -41,6 +47,12 @@ Code::Kind TypeFeedbackVector::FromVectorICKind(VectorICKind kind) {
return Code::LOAD_IC;
case KindKeyedLoadIC:
return Code::KEYED_LOAD_IC;
case KindStoreIC:
DCHECK(FLAG_vector_stores);
return Code::STORE_IC;
case KindKeyedStoreIC:
DCHECK(FLAG_vector_stores);
return Code::KEYED_STORE_IC;
case KindUnused:
break;
}
......@@ -200,6 +212,8 @@ void TypeFeedbackVector::ClearICSlotsImpl(SharedFunctionInfo* shared,
KeyedLoadICNexus nexus(this, slot);
nexus.Clear(host);
}
// TODO(mvstanton): Handle clearing of store ics when FLAG_vector_stores
// is true.
}
}
}
......
......@@ -228,10 +228,12 @@ class TypeFeedbackVector : public FixedArray {
KindUnused = 0x0,
KindCallIC = 0x1,
KindLoadIC = 0x2,
KindKeyedLoadIC = 0x3
KindKeyedLoadIC = 0x3,
KindStoreIC = 0x4,
KindKeyedStoreIC = 0x5,
};
static const int kVectorICKindBits = 2;
static const int kVectorICKindBits = 3;
static VectorICKind FromCodeKind(Code::Kind kind);
static Code::Kind FromVectorICKind(VectorICKind kind);
void SetKind(FeedbackVectorICSlot slot, Code::Kind kind);
......
This diff is collapsed.
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