Commit 1503d0e7 authored by Andy Wingo's avatar Andy Wingo

Move feedback slot allocation to post-pass

R=mvstanton@chromium.org, svenpanne@chromium.org

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

Cr-Commit-Position: refs/heads/master@{#25348}
parent 45ff9d53
......@@ -64,6 +64,21 @@ class AstNumberingVisitor FINAL : public AstVisitor {
properties_.flags()->Add(kDontCache);
}
template <typename Node>
void ReserveFeedbackSlots(Node* node) {
FeedbackVectorRequirements reqs = node->ComputeFeedbackRequirements();
if (reqs.slots() > 0) {
node->SetFirstFeedbackSlot(
FeedbackVectorSlot(properties_.feedback_slots()));
properties_.increase_feedback_slots(reqs.slots());
}
if (reqs.ic_slots() > 0) {
node->SetFirstFeedbackICSlot(
FeedbackVectorICSlot(properties_.ic_feedback_slots()));
properties_.increase_ic_feedback_slots(reqs.ic_slots());
}
}
BailoutReason dont_optimize_reason() const {
return (dont_turbofan_reason_ != kNoReason) ? dont_turbofan_reason_
: dont_crankshaft_reason_;
......@@ -145,6 +160,7 @@ void AstNumberingVisitor::VisitVariableProxy(VariableProxy* node) {
if (node->var()->IsLookupSlot()) {
DisableCrankshaft(kReferenceToAVariableWhichRequiresDynamicLookup);
}
ReserveFeedbackSlots(node);
node->set_base_id(ReserveIdRange(VariableProxy::num_ids()));
}
......@@ -158,6 +174,7 @@ void AstNumberingVisitor::VisitThisFunction(ThisFunction* node) {
void AstNumberingVisitor::VisitSuperReference(SuperReference* node) {
IncrementNodeCount();
DisableTurbofan(kSuperReference);
ReserveFeedbackSlots(node);
node->set_base_id(ReserveIdRange(SuperReference::num_ids()));
Visit(node->this_var());
}
......@@ -215,6 +232,7 @@ void AstNumberingVisitor::VisitReturnStatement(ReturnStatement* node) {
void AstNumberingVisitor::VisitYield(Yield* node) {
IncrementNodeCount();
DisableCrankshaft(kYield);
ReserveFeedbackSlots(node);
node->set_base_id(ReserveIdRange(Yield::num_ids()));
Visit(node->generator_object());
Visit(node->expression());
......@@ -319,6 +337,7 @@ void AstNumberingVisitor::VisitTryFinallyStatement(TryFinallyStatement* node) {
void AstNumberingVisitor::VisitProperty(Property* node) {
IncrementNodeCount();
ReserveFeedbackSlots(node);
node->set_base_id(ReserveIdRange(Property::num_ids()));
Visit(node->key());
Visit(node->obj());
......@@ -353,6 +372,7 @@ void AstNumberingVisitor::VisitCompareOperation(CompareOperation* node) {
void AstNumberingVisitor::VisitForInStatement(ForInStatement* node) {
IncrementNodeCount();
DisableSelfOptimization();
ReserveFeedbackSlots(node);
node->set_base_id(ReserveIdRange(ForInStatement::num_ids()));
Visit(node->each());
Visit(node->enumerable());
......@@ -461,6 +481,7 @@ void AstNumberingVisitor::VisitArrayLiteral(ArrayLiteral* node) {
void AstNumberingVisitor::VisitCall(Call* node) {
IncrementNodeCount();
ReserveFeedbackSlots(node);
node->set_base_id(ReserveIdRange(Call::num_ids()));
Visit(node->expression());
VisitArguments(node->arguments());
......@@ -469,6 +490,7 @@ void AstNumberingVisitor::VisitCall(Call* node) {
void AstNumberingVisitor::VisitCallNew(CallNew* node) {
IncrementNodeCount();
ReserveFeedbackSlots(node);
node->set_base_id(ReserveIdRange(CallNew::num_ids()));
Visit(node->expression());
VisitArguments(node->arguments());
......@@ -507,10 +529,6 @@ void AstNumberingVisitor::VisitFunctionLiteral(FunctionLiteral* node) {
void AstNumberingVisitor::Renumber(FunctionLiteral* node) {
properties_.flags()->Add(*node->flags());
properties_.increase_feedback_slots(node->slot_count());
properties_.increase_ic_feedback_slots(node->ic_slot_count());
if (node->scope()->HasIllegalRedeclaration()) {
node->scope()->VisitIllegalRedeclaration(this);
return;
......
......@@ -1006,28 +1006,24 @@ CaseClause::CaseClause(Zone* zone, Expression* label,
}
#define REGULAR_NODE_WITH_FEEDBACK_SLOTS(NodeType) \
void AstConstructionVisitor::Visit##NodeType(NodeType* node) { \
add_slot_node(node); \
}
#define DONT_OPTIMIZE_NODE(NodeType) \
void AstConstructionVisitor::Visit##NodeType(NodeType* node) { \
}
#define DONT_OPTIMIZE_NODE_WITH_FEEDBACK_SLOTS(NodeType) \
void AstConstructionVisitor::Visit##NodeType(NodeType* node) { \
add_slot_node(node); \
}
#define DONT_TURBOFAN_NODE(NodeType) \
void AstConstructionVisitor::Visit##NodeType(NodeType* node) { \
}
#define DONT_TURBOFAN_NODE_WITH_FEEDBACK_SLOTS(NodeType) \
void AstConstructionVisitor::Visit##NodeType(NodeType* node) { \
add_slot_node(node); \
}
#define DONT_SELFOPTIMIZE_NODE(NodeType) \
void AstConstructionVisitor::Visit##NodeType(NodeType* node) { \
}
#define DONT_SELFOPTIMIZE_NODE_WITH_FEEDBACK_SLOTS(NodeType) \
void AstConstructionVisitor::Visit##NodeType(NodeType* node) { \
add_slot_node(node); \
}
#define DONT_CACHE_NODE(NodeType) \
void AstConstructionVisitor::Visit##NodeType(NodeType* node) { \
......@@ -1101,7 +1097,6 @@ DONT_CACHE_NODE(ModuleLiteral)
void AstConstructionVisitor::VisitCallRuntime(CallRuntime* node) {
add_slot_node(node);
}
#undef REGULAR_NODE
......
......@@ -1705,6 +1705,7 @@ class VariableProxy FINAL : public Expression {
}
FeedbackVectorICSlot VariableFeedbackSlot() {
DCHECK(!FLAG_vector_ics || !variable_feedback_slot_.IsInvalid());
return variable_feedback_slot_;
}
......@@ -1790,6 +1791,7 @@ class Property FINAL : public Expression {
}
FeedbackVectorICSlot PropertyFeedbackSlot() const {
DCHECK(!FLAG_vector_ics || !property_feedback_slot_.IsInvalid());
return property_feedback_slot_;
}
......@@ -1834,7 +1836,10 @@ class Call FINAL : public Expression {
}
bool HasCallFeedbackSlot() const { return !call_feedback_slot_.IsInvalid(); }
FeedbackVectorICSlot CallFeedbackSlot() const { return call_feedback_slot_; }
FeedbackVectorICSlot CallFeedbackSlot() const {
DCHECK(!call_feedback_slot_.IsInvalid());
return call_feedback_slot_;
}
virtual SmallMapList* GetReceiverTypes() OVERRIDE {
if (expression()->IsProperty()) {
......@@ -1933,7 +1938,10 @@ class CallNew FINAL : public Expression {
callnew_feedback_slot_ = slot;
}
FeedbackVectorSlot CallNewFeedbackSlot() { return callnew_feedback_slot_; }
FeedbackVectorSlot CallNewFeedbackSlot() {
DCHECK(!callnew_feedback_slot_.IsInvalid());
return callnew_feedback_slot_;
}
FeedbackVectorSlot AllocationSiteFeedbackSlot() {
DCHECK(FLAG_pretenuring_call_new);
return CallNewFeedbackSlot().next();
......@@ -1997,6 +2005,8 @@ class CallRuntime FINAL : public Expression {
}
FeedbackVectorICSlot CallRuntimeFeedbackSlot() {
DCHECK(!(FLAG_vector_ics && is_jsruntime()) ||
!callruntime_feedback_slot_.IsInvalid());
return callruntime_feedback_slot_;
}
......@@ -2383,6 +2393,7 @@ class Yield FINAL : public Expression {
}
FeedbackVectorICSlot KeyedLoadFeedbackSlot() {
DCHECK(!FLAG_vector_ics || !yield_first_feedback_slot_.IsInvalid());
return yield_first_feedback_slot_;
}
......@@ -3159,8 +3170,6 @@ class AstConstructionVisitor BASE_EMBEDDED {
public:
AstConstructionVisitor() {}
AstProperties* ast_properties() { return &properties_; }
private:
template<class> friend class AstNodeFactory;
......@@ -3169,22 +3178,6 @@ class AstConstructionVisitor BASE_EMBEDDED {
void Visit##type(type* node);
AST_NODE_LIST(DEF_VISIT)
#undef DEF_VISIT
void add_slot_node(AstNode* slot_node) {
FeedbackVectorRequirements reqs = slot_node->ComputeFeedbackRequirements();
if (reqs.slots() > 0) {
slot_node->SetFirstFeedbackSlot(
FeedbackVectorSlot(properties_.feedback_slots()));
properties_.increase_feedback_slots(reqs.slots());
}
if (reqs.ic_slots() > 0) {
slot_node->SetFirstFeedbackICSlot(
FeedbackVectorICSlot(properties_.ic_feedback_slots()));
properties_.increase_ic_feedback_slots(reqs.ic_slots());
}
}
AstProperties properties_;
};
......
......@@ -291,9 +291,11 @@ bool CompilationInfo::ShouldSelfOptimize() {
void CompilationInfo::PrepareForCompilation(Scope* scope) {
DCHECK(scope_ == NULL);
scope_ = scope;
}
void CompilationInfo::EnsureFeedbackVector() {
if (feedback_vector_.is_null()) {
// Allocate the feedback vector too.
feedback_vector_ = isolate()->factory()->NewTypeFeedbackVector(
function()->slot_count(), function()->ic_slot_count());
}
......@@ -1326,8 +1328,18 @@ Handle<SharedFunctionInfo> Compiler::BuildFunctionInfo(
if (FLAG_lazy && allow_lazy && !literal->is_parenthesized()) {
Handle<Code> code = isolate->builtins()->CompileLazy();
info.SetCode(code);
// There's no need in theory for a lazy-compiled function to have a type
// feedback vector, but some parts of the system expect all
// SharedFunctionInfo instances to have one. The size of the vector depends
// on how many feedback-needing nodes are in the tree, and when lazily
// parsing we might not know that, if this function was never parsed before.
// In that case the vector will be replaced the next time MakeCode is
// called.
info.EnsureFeedbackVector();
scope_info = Handle<ScopeInfo>(ScopeInfo::Empty(isolate));
} else if (Renumber(&info) && FullCodeGenerator::MakeCode(&info)) {
// MakeCode will ensure that the feedback vector is present and
// appropriately sized.
DCHECK(!info.code().is_null());
scope_info = ScopeInfo::Create(info.scope(), info.zone());
} else {
......
......@@ -235,6 +235,7 @@ class CompilationInfo {
DCHECK(script_scope_ == NULL);
script_scope_ = script_scope;
}
void EnsureFeedbackVector();
Handle<TypeFeedbackVector> feedback_vector() const {
return feedback_vector_;
}
......
......@@ -306,6 +306,9 @@ bool FullCodeGenerator::MakeCode(CompilationInfo* info) {
TimerEventScope<TimerEventCompileFullCode> timer(info->isolate());
// Ensure that the feedback vector is large enough.
info->EnsureFeedbackVector();
Handle<Script> script = info->script();
if (!script->IsUndefined() && !script->source()->IsUndefined()) {
int len = String::cast(script->source())->length();
......
......@@ -605,17 +605,17 @@ static int GetArrayLength(Handle<JSArray> array) {
}
void FunctionInfoWrapper::SetInitialProperties(
Handle<String> name, int start_position, int end_position, int param_num,
int literal_count, int slot_count, int ic_slot_count, int parent_index) {
void FunctionInfoWrapper::SetInitialProperties(Handle<String> name,
int start_position,
int end_position, int param_num,
int literal_count,
int parent_index) {
HandleScope scope(isolate());
this->SetField(kFunctionNameOffset_, name);
this->SetSmiValueField(kStartPositionOffset_, start_position);
this->SetSmiValueField(kEndPositionOffset_, end_position);
this->SetSmiValueField(kParamNumOffset_, param_num);
this->SetSmiValueField(kLiteralNumOffset_, literal_count);
this->SetSmiValueField(kSlotNumOffset_, slot_count);
this->SetSmiValueField(kICSlotNumOffset_, ic_slot_count);
this->SetSmiValueField(kParentIndexOffset_, parent_index);
}
......@@ -646,26 +646,18 @@ Handle<Code> FunctionInfoWrapper::GetFunctionCode() {
}
Handle<TypeFeedbackVector> FunctionInfoWrapper::GetFeedbackVector() {
MaybeHandle<TypeFeedbackVector> FunctionInfoWrapper::GetFeedbackVector() {
Handle<Object> element = this->GetField(kSharedFunctionInfoOffset_);
Handle<TypeFeedbackVector> result;
if (element->IsJSValue()) {
Handle<JSValue> value_wrapper = Handle<JSValue>::cast(element);
Handle<Object> raw_result = UnwrapJSValue(value_wrapper);
Handle<SharedFunctionInfo> shared =
Handle<SharedFunctionInfo>::cast(raw_result);
result = Handle<TypeFeedbackVector>(shared->feedback_vector(), isolate());
CHECK_EQ(result->Slots(), GetSlotCount());
CHECK_EQ(result->ICSlots(), GetICSlotCount());
return Handle<TypeFeedbackVector>(shared->feedback_vector(), isolate());
} else {
// Scripts may never have a SharedFunctionInfo created, so
// create a type feedback vector here.
int slot_count = GetSlotCount();
int ic_slot_count = GetICSlotCount();
result =
isolate()->factory()->NewTypeFeedbackVector(slot_count, ic_slot_count);
// Scripts may never have a SharedFunctionInfo created.
return MaybeHandle<TypeFeedbackVector>();
}
return result;
}
......@@ -706,10 +698,10 @@ class FunctionInfoListener {
void FunctionStarted(FunctionLiteral* fun) {
HandleScope scope(isolate());
FunctionInfoWrapper info = FunctionInfoWrapper::Create(isolate());
info.SetInitialProperties(
fun->name(), fun->start_position(), fun->end_position(),
fun->parameter_count(), fun->materialized_literal_count(),
fun->slot_count(), fun->ic_slot_count(), current_parent_index_);
info.SetInitialProperties(fun->name(), fun->start_position(),
fun->end_position(), fun->parameter_count(),
fun->materialized_literal_count(),
current_parent_index_);
current_parent_index_ = len_;
SetElementSloppy(result_, len_, info.GetJSArray());
len_++;
......@@ -1201,10 +1193,12 @@ void LiveEdit::ReplaceFunctionCode(
shared_info->set_scope_info(ScopeInfo::cast(*code_scope_info));
}
shared_info->DisableOptimization(kLiveEdit);
// Update the type feedback vector
Handle<TypeFeedbackVector> feedback_vector =
// Update the type feedback vector, if needed.
MaybeHandle<TypeFeedbackVector> feedback_vector =
compile_info_wrapper.GetFeedbackVector();
shared_info->set_feedback_vector(*feedback_vector);
if (!feedback_vector.is_null()) {
shared_info->set_feedback_vector(*feedback_vector.ToHandleChecked());
}
}
if (shared_info->debug_info()->IsDebugInfo()) {
......
......@@ -282,7 +282,6 @@ class FunctionInfoWrapper : public JSArrayBasedStruct<FunctionInfoWrapper> {
void SetInitialProperties(Handle<String> name, int start_position,
int end_position, int param_num, int literal_count,
int slot_count, int ic_slot_count,
int parent_index);
void SetFunctionCode(Handle<Code> function_code,
......@@ -304,7 +303,7 @@ class FunctionInfoWrapper : public JSArrayBasedStruct<FunctionInfoWrapper> {
Handle<Code> GetFunctionCode();
Handle<TypeFeedbackVector> GetFeedbackVector();
MaybeHandle<TypeFeedbackVector> GetFeedbackVector();
Handle<Object> GetCodeScopeInfo();
......@@ -314,12 +313,6 @@ class FunctionInfoWrapper : public JSArrayBasedStruct<FunctionInfoWrapper> {
int GetEndPosition() { return this->GetSmiValueField(kEndPositionOffset_); }
int GetSlotCount() {
return this->GetSmiValueField(kSlotNumOffset_);
}
int GetICSlotCount() { return this->GetSmiValueField(kICSlotNumOffset_); }
private:
static const int kFunctionNameOffset_ = 0;
static const int kStartPositionOffset_ = 1;
......@@ -331,9 +324,7 @@ class FunctionInfoWrapper : public JSArrayBasedStruct<FunctionInfoWrapper> {
static const int kParentIndexOffset_ = 7;
static const int kSharedFunctionInfoOffset_ = 8;
static const int kLiteralNumOffset_ = 9;
static const int kSlotNumOffset_ = 10;
static const int kICSlotNumOffset_ = 11;
static const int kSize_ = 12;
static const int kSize_ = 10;
friend class JSArrayBasedStruct<FunctionInfoWrapper>;
};
......
......@@ -277,7 +277,6 @@ FunctionLiteral* Parser::DefaultConstructor(bool call_super, Scope* scope,
int expected_property_count = -1;
int handler_count = 0;
int parameter_count = 0;
AstProperties ast_properties;
const AstRawString* name = ast_value_factory()->empty_string();
Scope* function_scope = NewScope(scope, FUNCTION_SCOPE);
......@@ -308,8 +307,6 @@ FunctionLiteral* Parser::DefaultConstructor(bool call_super, Scope* scope,
materialized_literal_count = function_state.materialized_literal_count();
expected_property_count = function_state.expected_property_count();
handler_count = function_state.handler_count();
ast_properties = *factory()->visitor()->ast_properties();
}
FunctionLiteral* function_literal = factory()->NewFunctionLiteral(
......@@ -320,8 +317,6 @@ FunctionLiteral* Parser::DefaultConstructor(bool call_super, Scope* scope,
FunctionLiteral::kNotParenthesized, FunctionKind::kDefaultConstructor,
pos);
function_literal->set_ast_properties(&ast_properties);
return function_literal;
}
......@@ -968,7 +963,6 @@ FunctionLiteral* Parser::DoParseProgram(CompilationInfo* info, Scope** scope,
FunctionLiteral::kNoDuplicateParameters,
FunctionLiteral::ANONYMOUS_EXPRESSION, FunctionLiteral::kGlobalOrEval,
FunctionLiteral::kNotParenthesized, FunctionKind::kNormalFunction, 0);
result->set_ast_properties(factory()->visitor()->ast_properties());
}
}
......@@ -3553,7 +3547,6 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
FunctionLiteral::IsParenthesizedFlag parenthesized = parenthesized_function_
? FunctionLiteral::kIsParenthesized
: FunctionLiteral::kNotParenthesized;
AstProperties ast_properties;
// Parse function body.
{
AstNodeFactory<AstConstructionVisitor> function_factory(
......@@ -3721,8 +3714,6 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
scope->end_position(),
CHECK_OK);
}
ast_properties = *factory()->visitor()->ast_properties();
if (allow_harmony_scoping() && strict_mode() == STRICT) {
CheckConflictingVarDeclarations(scope, CHECK_OK);
}
......@@ -3734,7 +3725,6 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
num_parameters, duplicate_parameters, function_type,
FunctionLiteral::kIsFunction, parenthesized, kind, pos);
function_literal->set_function_token_position(function_token_pos);
function_literal->set_ast_properties(&ast_properties);
if (fni_ != NULL && should_infer_name) fni_->AddFunction(function_literal);
return function_literal;
......
......@@ -815,7 +815,6 @@ class PreParserExpression {
int position() const { return RelocInfo::kNoPosition; }
void set_function_token_position(int position) {}
void set_ast_properties(int* ast_properties) {}
private:
enum Type {
......@@ -1098,14 +1097,6 @@ class PreParserFactory {
int start_position, int end_position) {
return PreParserExpression::Default();
}
// Return the object itself as AstVisitor and implement the needed
// dummy method right in this class.
PreParserFactory* visitor() { return this; }
int* ast_properties() {
static int dummy = 42;
return &dummy;
}
};
......@@ -2632,7 +2623,6 @@ typename ParserBase<Traits>::ExpressionT ParserBase<
bool* ok) {
typename Traits::Type::ScopePtr scope = this->NewScope(scope_, ARROW_SCOPE);
typename Traits::Type::StatementList body;
typename Traits::Type::AstProperties ast_properties;
int num_parameters = -1;
int materialized_literal_count = -1;
int expected_property_count = -1;
......@@ -2714,8 +2704,6 @@ typename ParserBase<Traits>::ExpressionT ParserBase<
if (allow_harmony_scoping() && strict_mode() == STRICT)
this->CheckConflictingVarDeclarations(scope, CHECK_OK);
ast_properties = *factory()->visitor()->ast_properties();
}
FunctionLiteralT function_literal = factory()->NewFunctionLiteral(
......@@ -2727,7 +2715,6 @@ typename ParserBase<Traits>::ExpressionT ParserBase<
start_pos);
function_literal->set_function_token_position(start_pos);
function_literal->set_ast_properties(&ast_properties);
if (fni_ != NULL) this->InferFunctionName(fni_, function_literal);
......
......@@ -348,20 +348,19 @@ TEST(FeedbackVectorUnaffectedByScopeChanges) {
*v8::Handle<v8::Function>::Cast(
CcTest::global()->Get(v8_str("morphing_call"))));
int expected_slots = 0;
int expected_ic_slots = FLAG_vector_ics ? 2 : 1;
CHECK_EQ(expected_slots, f->shared()->feedback_vector()->Slots());
CHECK_EQ(expected_ic_slots, f->shared()->feedback_vector()->ICSlots());
// And yet it's not compiled.
// Not compiled, and so no feedback vector allocated yet.
CHECK(!f->shared()->is_compiled());
CHECK_EQ(0, f->shared()->feedback_vector()->Slots());
CHECK_EQ(0, f->shared()->feedback_vector()->ICSlots());
CompileRun("morphing_call();");
// The vector should have the same size despite the new scoping.
// Now a feedback vector is allocated.
CHECK(f->shared()->is_compiled());
int expected_slots = 0;
int expected_ic_slots = FLAG_vector_ics ? 2 : 1;
CHECK_EQ(expected_slots, f->shared()->feedback_vector()->Slots());
CHECK_EQ(expected_ic_slots, f->shared()->feedback_vector()->ICSlots());
CHECK(f->shared()->is_compiled());
}
......
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