Commit 86c2db5e authored by franzih's avatar franzih Committed by Commit bot

[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}
parent d82aca19
......@@ -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();
......
// 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";
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";
^
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