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_;
if (node->var()->IsLookupSlot()) {
DisableCrankshaft(kReferenceToAVariableWhichRequiresDynamicLookup);
}
+ ReserveFeedbackSlots(node);
node->set_base_id(ReserveIdRange(VariableProxy::num_ids()));
}
void AstNumberingVisitor::VisitSuperReference(SuperReference* node) {
IncrementNodeCount();
DisableTurbofan(kSuperReference);
+ ReserveFeedbackSlots(node);
node->set_base_id(ReserveIdRange(SuperReference::num_ids()));
Visit(node->this_var());
}
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());
void AstNumberingVisitor::VisitProperty(Property* node) {
IncrementNodeCount();
+ ReserveFeedbackSlots(node);
node->set_base_id(ReserveIdRange(Property::num_ids()));
Visit(node->key());
Visit(node->obj());
void AstNumberingVisitor::VisitForInStatement(ForInStatement* node) {
IncrementNodeCount();
DisableSelfOptimization();
+ ReserveFeedbackSlots(node);
node->set_base_id(ReserveIdRange(ForInStatement::num_ids()));
Visit(node->each());
Visit(node->enumerable());
void AstNumberingVisitor::VisitCall(Call* node) {
IncrementNodeCount();
+ ReserveFeedbackSlots(node);
node->set_base_id(ReserveIdRange(Call::num_ids()));
Visit(node->expression());
VisitArguments(node->arguments());
void AstNumberingVisitor::VisitCallNew(CallNew* node) {
IncrementNodeCount();
+ ReserveFeedbackSlots(node);
node->set_base_id(ReserveIdRange(CallNew::num_ids()));
Visit(node->expression());
VisitArguments(node->arguments());
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;
}
#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) { \
void AstConstructionVisitor::VisitCallRuntime(CallRuntime* node) {
- add_slot_node(node);
}
#undef REGULAR_NODE
}
FeedbackVectorICSlot VariableFeedbackSlot() {
+ DCHECK(!FLAG_vector_ics || !variable_feedback_slot_.IsInvalid());
return variable_feedback_slot_;
}
}
FeedbackVectorICSlot PropertyFeedbackSlot() const {
+ DCHECK(!FLAG_vector_ics || !property_feedback_slot_.IsInvalid());
return property_feedback_slot_;
}
}
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()) {
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();
}
FeedbackVectorICSlot CallRuntimeFeedbackSlot() {
+ DCHECK(!(FLAG_vector_ics && is_jsruntime()) ||
+ !callruntime_feedback_slot_.IsInvalid());
return callruntime_feedback_slot_;
}
}
FeedbackVectorICSlot KeyedLoadFeedbackSlot() {
+ DCHECK(!FLAG_vector_ics || !yield_first_feedback_slot_.IsInvalid());
return yield_first_feedback_slot_;
}
public:
AstConstructionVisitor() {}
- AstProperties* ast_properties() { return &properties_; }
-
private:
template<class> friend class AstNodeFactory;
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_;
};
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());
}
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 {
DCHECK(script_scope_ == NULL);
script_scope_ = script_scope;
}
+ void EnsureFeedbackVector();
Handle<TypeFeedbackVector> feedback_vector() const {
return feedback_vector_;
}
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();
}
-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);
}
}
-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;
}
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_++;
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()) {
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,
Handle<Code> GetFunctionCode();
- Handle<TypeFeedbackVector> GetFeedbackVector();
+ MaybeHandle<TypeFeedbackVector> GetFeedbackVector();
Handle<Object> GetCodeScopeInfo();
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;
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>;
};
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);
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(
FunctionLiteral::kNotParenthesized, FunctionKind::kDefaultConstructor,
pos);
- function_literal->set_ast_properties(&ast_properties);
-
return function_literal;
}
FunctionLiteral::kNoDuplicateParameters,
FunctionLiteral::ANONYMOUS_EXPRESSION, FunctionLiteral::kGlobalOrEval,
FunctionLiteral::kNotParenthesized, FunctionKind::kNormalFunction, 0);
- result->set_ast_properties(factory()->visitor()->ast_properties());
}
}
FunctionLiteral::IsParenthesizedFlag parenthesized = parenthesized_function_
? FunctionLiteral::kIsParenthesized
: FunctionLiteral::kNotParenthesized;
- AstProperties ast_properties;
// Parse function body.
{
AstNodeFactory<AstConstructionVisitor> function_factory(
scope->end_position(),
CHECK_OK);
}
- ast_properties = *factory()->visitor()->ast_properties();
-
if (allow_harmony_scoping() && strict_mode() == STRICT) {
CheckConflictingVarDeclarations(scope, CHECK_OK);
}
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;
int position() const { return RelocInfo::kNoPosition; }
void set_function_token_position(int position) {}
- void set_ast_properties(int* ast_properties) {}
private:
enum Type {
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;
- }
};
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;
if (allow_harmony_scoping() && strict_mode() == STRICT)
this->CheckConflictingVarDeclarations(scope, CHECK_OK);
-
- ast_properties = *factory()->visitor()->ast_properties();
}
FunctionLiteralT function_literal = factory()->NewFunctionLiteral(
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);
*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());
}