[type-profile] Handle returns correctly.
Handle fall-off returns and returns inside try blocks. Store the type-profile feedback slot on the FunctionLiteral rather than on every return statement. Next steps: * Store entries in nexus that can be identified as 'return' (rather than parameter or assignment) * Collect types for parameters and assignments * Distinguish multiple parameters and assignments correctly R=mstarzinger@chromium.org BUG=v8:5935 Review-Url: https://codereview.chromium.org/2764113002 Cr-Commit-Position: refs/heads/master@{#44014}
This commit is contained in:
parent
d82aca1928
commit
86c2db5e33
@ -33,13 +33,6 @@ class AstNumberingVisitor final : public AstVisitor<AstNumberingVisitor> {
|
||||
|
||||
bool Renumber(FunctionLiteral* node);
|
||||
|
||||
FeedbackSlot TypeProfileSlotForReturnValue() const {
|
||||
if (collect_type_profile_) {
|
||||
DCHECK(!type_profile_for_return_value_.IsInvalid());
|
||||
}
|
||||
return type_profile_for_return_value_;
|
||||
}
|
||||
|
||||
private:
|
||||
// AST node visitor interface.
|
||||
#define DEFINE_VISIT(type) void Visit##type(type* node);
|
||||
@ -111,7 +104,6 @@ class AstNumberingVisitor final : public AstVisitor<AstNumberingVisitor> {
|
||||
BailoutReason dont_optimize_reason_;
|
||||
HandlerTable::CatchPrediction catch_prediction_;
|
||||
bool collect_type_profile_;
|
||||
FeedbackSlot type_profile_for_return_value_;
|
||||
|
||||
DEFINE_AST_VISITOR_SUBCLASS_MEMBERS();
|
||||
DISALLOW_COPY_AND_ASSIGN(AstNumberingVisitor);
|
||||
@ -245,8 +237,6 @@ void AstNumberingVisitor::VisitReturnStatement(ReturnStatement* node) {
|
||||
IncrementNodeCount();
|
||||
Visit(node->expression());
|
||||
|
||||
node->SetTypeProfileSlot(TypeProfileSlotForReturnValue());
|
||||
|
||||
DCHECK(!node->is_async_return() ||
|
||||
properties_.flags() & AstProperties::kMustUseIgnitionTurbo);
|
||||
}
|
||||
@ -435,8 +425,7 @@ void AstNumberingVisitor::VisitAssignment(Assignment* node) {
|
||||
if (node->is_compound()) VisitBinaryOperation(node->binary_operation());
|
||||
VisitReference(node->target());
|
||||
Visit(node->value());
|
||||
node->AssignFeedbackSlots(properties_.get_spec(), language_mode_,
|
||||
&slot_cache_, collect_type_profile_);
|
||||
ReserveFeedbackSlots(node);
|
||||
}
|
||||
|
||||
|
||||
@ -702,8 +691,7 @@ bool AstNumberingVisitor::Renumber(FunctionLiteral* node) {
|
||||
LanguageModeScope language_mode_scope(this, node->language_mode());
|
||||
|
||||
if (collect_type_profile_) {
|
||||
type_profile_for_return_value_ =
|
||||
properties_.get_spec()->AddTypeProfileSlot();
|
||||
node->SetTypeProfileSlot(properties_.get_spec()->AddTypeProfileSlot());
|
||||
}
|
||||
|
||||
VisitDeclarations(scope->declarations());
|
||||
|
@ -283,13 +283,8 @@ Assignment::Assignment(Token::Value op, Expression* target, Expression* value,
|
||||
|
||||
void Assignment::AssignFeedbackSlots(FeedbackVectorSpec* spec,
|
||||
LanguageMode language_mode,
|
||||
FeedbackSlotCache* cache,
|
||||
bool collect_type_profile) {
|
||||
FeedbackSlotCache* cache) {
|
||||
AssignVectorSlots(target(), spec, language_mode, &slot_);
|
||||
|
||||
if (collect_type_profile) {
|
||||
type_profile_slot_ = spec->AddTypeProfileSlot();
|
||||
}
|
||||
}
|
||||
|
||||
void CountOperation::AssignFeedbackSlots(FeedbackVectorSpec* spec,
|
||||
|
@ -904,15 +904,6 @@ class ReturnStatement final : public JumpStatement {
|
||||
Type type() const { return TypeField::decode(bit_field_); }
|
||||
bool is_async_return() const { return type() == kAsyncReturn; }
|
||||
|
||||
FeedbackSlot TypeProfileSlot() const {
|
||||
DCHECK(HasTypeProfileSlot());
|
||||
return type_profile_slot_;
|
||||
}
|
||||
|
||||
void SetTypeProfileSlot(FeedbackSlot slot) { type_profile_slot_ = slot; }
|
||||
|
||||
bool HasTypeProfileSlot() const { return !type_profile_slot_.IsInvalid(); }
|
||||
|
||||
private:
|
||||
friend class AstNodeFactory;
|
||||
|
||||
@ -921,8 +912,6 @@ class ReturnStatement final : public JumpStatement {
|
||||
bit_field_ |= TypeField::encode(type);
|
||||
}
|
||||
|
||||
FeedbackSlot type_profile_slot_;
|
||||
|
||||
Expression* expression_;
|
||||
|
||||
class TypeField
|
||||
@ -2425,17 +2414,9 @@ class Assignment final : public Expression {
|
||||
}
|
||||
|
||||
void AssignFeedbackSlots(FeedbackVectorSpec* spec, LanguageMode language_mode,
|
||||
FeedbackSlotCache* cache,
|
||||
bool collect_type_profile = false);
|
||||
FeedbackSlotCache* cache);
|
||||
FeedbackSlot AssignmentSlot() const { return slot_; }
|
||||
|
||||
FeedbackSlot TypeProfileSlot() const {
|
||||
DCHECK(HasTypeProfileSlot());
|
||||
return type_profile_slot_;
|
||||
}
|
||||
|
||||
bool HasTypeProfileSlot() const { return !type_profile_slot_.IsInvalid(); }
|
||||
|
||||
private:
|
||||
friend class AstNodeFactory;
|
||||
|
||||
@ -2457,8 +2438,6 @@ class Assignment final : public Expression {
|
||||
Expression* value_;
|
||||
BinaryOperation* binary_operation_;
|
||||
SmallMapList receiver_types_;
|
||||
|
||||
FeedbackSlot type_profile_slot_;
|
||||
};
|
||||
|
||||
|
||||
@ -2606,7 +2585,10 @@ class FunctionLiteral final : public Expression {
|
||||
literal_feedback_slot_ = spec->AddCreateClosureSlot();
|
||||
}
|
||||
|
||||
void SetTypeProfileSlot(FeedbackSlot slot) { type_profile_slot_ = slot; }
|
||||
|
||||
FeedbackSlot LiteralFeedbackSlot() const { return literal_feedback_slot_; }
|
||||
FeedbackSlot TypeProfileSlot() const { return type_profile_slot_; }
|
||||
|
||||
static bool NeedsHomeObject(Expression* expr);
|
||||
|
||||
@ -2769,6 +2751,7 @@ class FunctionLiteral final : public Expression {
|
||||
AstProperties ast_properties_;
|
||||
int function_literal_id_;
|
||||
FeedbackSlot literal_feedback_slot_;
|
||||
FeedbackSlot type_profile_slot_;
|
||||
};
|
||||
|
||||
// Property is used for passing information
|
||||
|
@ -177,6 +177,17 @@ FeedbackSlotKind FeedbackVector::GetKind(FeedbackSlot slot) const {
|
||||
return metadata()->GetKind(slot);
|
||||
}
|
||||
|
||||
FeedbackSlot FeedbackVector::GetTypeProfileSlot() const {
|
||||
FeedbackMetadataIterator iter(metadata());
|
||||
while (iter.HasNext()) {
|
||||
FeedbackSlot slot = iter.Next();
|
||||
if (IsTypeProfile(slot)) {
|
||||
return slot;
|
||||
}
|
||||
}
|
||||
return FeedbackSlot();
|
||||
}
|
||||
|
||||
// static
|
||||
Handle<FeedbackVector> FeedbackVector::New(Isolate* isolate,
|
||||
Handle<SharedFunctionInfo> shared) {
|
||||
|
@ -76,6 +76,10 @@ inline bool IsKeyedStoreICKind(FeedbackSlotKind kind) {
|
||||
kind == FeedbackSlotKind::kStoreKeyedStrict;
|
||||
}
|
||||
|
||||
inline bool IsTypeProfileKind(FeedbackSlotKind kind) {
|
||||
return kind == FeedbackSlotKind::kTypeProfile;
|
||||
}
|
||||
|
||||
inline TypeofMode GetTypeofModeFromSlotKind(FeedbackSlotKind kind) {
|
||||
DCHECK(IsLoadGlobalICKind(kind));
|
||||
return (kind == FeedbackSlotKind::kLoadGlobalInsideTypeof)
|
||||
@ -315,6 +319,8 @@ class FeedbackVector : public FixedArray {
|
||||
// Returns slot kind for given slot.
|
||||
FeedbackSlotKind GetKind(FeedbackSlot slot) const;
|
||||
|
||||
FeedbackSlot GetTypeProfileSlot() const;
|
||||
|
||||
static Handle<FeedbackVector> New(Isolate* isolate,
|
||||
Handle<SharedFunctionInfo> shared);
|
||||
|
||||
@ -331,6 +337,7 @@ class FeedbackVector : public FixedArray {
|
||||
DEFINE_SLOT_KIND_PREDICATE(IsStoreIC)
|
||||
DEFINE_SLOT_KIND_PREDICATE(IsStoreOwnIC)
|
||||
DEFINE_SLOT_KIND_PREDICATE(IsKeyedStoreIC)
|
||||
DEFINE_SLOT_KIND_PREDICATE(IsTypeProfile)
|
||||
#undef DEFINE_SLOT_KIND_PREDICATE
|
||||
|
||||
// Returns typeof mode encoded into kind of given slot.
|
||||
|
@ -1092,13 +1092,6 @@ void BytecodeGenerator::VisitBreakStatement(BreakStatement* stmt) {
|
||||
void BytecodeGenerator::VisitReturnStatement(ReturnStatement* stmt) {
|
||||
builder()->SetStatementPosition(stmt);
|
||||
VisitForAccumulatorValue(stmt->expression());
|
||||
|
||||
if (stmt->HasTypeProfileSlot()) {
|
||||
FeedbackSlot collect_type_feedback_slot = stmt->TypeProfileSlot();
|
||||
builder()->CollectTypeProfile(stmt->position(),
|
||||
feedback_index(collect_type_feedback_slot));
|
||||
}
|
||||
|
||||
if (stmt->is_async_return()) {
|
||||
execution_control()->AsyncReturnAccumulator();
|
||||
} else {
|
||||
@ -2030,6 +2023,11 @@ void BytecodeGenerator::BuildReturn() {
|
||||
builder()->StoreAccumulatorInRegister(result).CallRuntime(
|
||||
Runtime::kTraceExit, result);
|
||||
}
|
||||
if (!info()->literal()->TypeProfileSlot().IsInvalid()) {
|
||||
builder()->CollectTypeProfile(
|
||||
info()->literal()->position(),
|
||||
feedback_index(info()->literal()->TypeProfileSlot()));
|
||||
}
|
||||
builder()->Return();
|
||||
}
|
||||
|
||||
@ -2339,16 +2337,6 @@ void BytecodeGenerator::VisitAssignment(Assignment* expr) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Value is in accumulator.
|
||||
// TODO(franzih): Collect type profile once we can handle more than just
|
||||
// return statements.
|
||||
if (false && expr->HasTypeProfileSlot()) {
|
||||
FeedbackSlot collect_type_feedback_slot = expr->TypeProfileSlot();
|
||||
|
||||
builder()->CollectTypeProfile(expr->position(),
|
||||
feedback_index(collect_type_feedback_slot));
|
||||
}
|
||||
}
|
||||
|
||||
void BytecodeGenerator::VisitYield(Yield* expr) {
|
||||
|
@ -707,6 +707,7 @@ RUNTIME_FUNCTION(Runtime_CollectTypeProfile) {
|
||||
type = JSReceiver::GetConstructorName(object);
|
||||
}
|
||||
|
||||
DCHECK(!vector->ToSlot(index).IsInvalid());
|
||||
CollectTypeProfileNexus nexus(vector, vector->ToSlot(index));
|
||||
nexus.Collect(type, position->value());
|
||||
|
||||
|
@ -171,16 +171,11 @@ RUNTIME_FUNCTION(Runtime_PrintTypeProfile) {
|
||||
Object* function_name = vector->shared_function_info()->name();
|
||||
PrintF("Function: %s\n", String::cast(function_name)->ToCString().get());
|
||||
|
||||
FeedbackMetadataIterator iter(vector->metadata());
|
||||
while (iter.HasNext()) {
|
||||
FeedbackSlot slot = iter.Next();
|
||||
FeedbackSlotKind kind = iter.kind();
|
||||
if (kind == FeedbackSlotKind::kTypeProfile) {
|
||||
CollectTypeProfileNexus nexus(vector, slot);
|
||||
nexus.Print();
|
||||
PrintF("\n");
|
||||
return isolate->heap()->undefined_value();
|
||||
}
|
||||
FeedbackSlot slot = vector->GetTypeProfileSlot();
|
||||
if (!slot.IsInvalid()) {
|
||||
CollectTypeProfileNexus nexus(vector, slot);
|
||||
nexus.Print();
|
||||
PrintF("\n");
|
||||
}
|
||||
}
|
||||
return isolate->heap()->undefined_value();
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright 2016 the V8 project authors. All rights reserved.
|
||||
// Copyright 2017 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
@ -39,7 +39,6 @@ function testReturnOfNonVariable() {
|
||||
}
|
||||
|
||||
// Return statement is reached but its expression is never really returned.
|
||||
// TODO(franzih): The only return type should be 'string'.
|
||||
function try_finally() {
|
||||
try {
|
||||
return 23;
|
||||
@ -50,16 +49,12 @@ function try_finally() {
|
||||
try_finally();
|
||||
%PrintTypeProfile(try_finally);
|
||||
|
||||
// TODO(franzih): 'undefined' should be the return type.
|
||||
function fall_off() {
|
||||
//nothing
|
||||
}
|
||||
fall_off();
|
||||
%PrintTypeProfile(fall_off);
|
||||
|
||||
|
||||
|
||||
|
||||
testReturnOfNonVariable();
|
||||
|
||||
throw "throw otherwise test fails with --stress-opt";
|
||||
|
@ -1,26 +1,26 @@
|
||||
Function: testFunction
|
||||
424: Object
|
||||
374: number
|
||||
424: string
|
||||
424: number
|
||||
246: Object
|
||||
246: number
|
||||
246: string
|
||||
246: number
|
||||
|
||||
Function: testFunction
|
||||
424: Object
|
||||
374: number
|
||||
424: string
|
||||
424: number
|
||||
424: undefined
|
||||
374: string
|
||||
374: Object
|
||||
424: Object
|
||||
424: MyClass
|
||||
246: Object
|
||||
246: number
|
||||
246: string
|
||||
246: number
|
||||
246: undefined
|
||||
246: string
|
||||
246: Object
|
||||
246: Object
|
||||
246: MyClass
|
||||
|
||||
Function: try_finally
|
||||
1032: number
|
||||
1061: string
|
||||
956: string
|
||||
|
||||
Function: fall_off
|
||||
1105: undefined
|
||||
|
||||
*%(basename)s:65: throw otherwise test fails with --stress-opt
|
||||
*%(basename)s:60: throw otherwise test fails with --stress-opt
|
||||
throw "throw otherwise test fails with --stress-opt";
|
||||
^
|
||||
|
Loading…
Reference in New Issue
Block a user