Commit 6fda4e4c authored by rossberg@chromium.org's avatar rossberg@chromium.org

Collect type feedback in separate pass and store it in AST

Notes:

- For now, just adds the missing type info fields to the AST nodes directly.
  I'd like to factor that out more nicely in a follow-up CL.

- All type feedback now is uniformly collected through AST nodes'
  RecordTypeFeedback functions. At some point, this logic should be moved
  out of ast.cc.

- The typing pass currently simulates the exact same conditions under
  which feedback was collected in Hydrogen before. That also should be
  made more generic in the future.

- Type information itself is unchanged. Making it more regular is
  yet more future work.

Some additional cleanups:

- Lifted out nested class ObjectLiteral::Property, to enable forward declaration.
- Moved around some auxiliary enums.

R=svenpanne@chromium.org
BUG=

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

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@14825 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 0a428961
......@@ -30,6 +30,7 @@
#include <cmath> // For isfinite.
#include "builtins.h"
#include "code-stubs.h"
#include "contexts.h"
#include "conversions.h"
#include "hashmap.h"
#include "parser.h"
......@@ -181,9 +182,9 @@ LanguageMode FunctionLiteral::language_mode() const {
}
ObjectLiteral::Property::Property(Literal* key,
Expression* value,
Isolate* isolate) {
ObjectLiteralProperty::ObjectLiteralProperty(Literal* key,
Expression* value,
Isolate* isolate) {
emit_store_ = true;
key_ = key;
value_ = value;
......@@ -201,7 +202,8 @@ ObjectLiteral::Property::Property(Literal* key,
}
ObjectLiteral::Property::Property(bool is_getter, FunctionLiteral* value) {
ObjectLiteralProperty::ObjectLiteralProperty(bool is_getter,
FunctionLiteral* value) {
emit_store_ = true;
value_ = value;
kind_ = is_getter ? GETTER : SETTER;
......@@ -415,6 +417,16 @@ bool FunctionDeclaration::IsInlineable() const {
// ----------------------------------------------------------------------------
// Recording of type feedback
void ForInStatement::RecordTypeFeedback(TypeFeedbackOracle* oracle) {
for_in_type_ = static_cast<ForInType>(oracle->ForInType(this));
}
void Expression::RecordToBooleanTypeFeedback(TypeFeedbackOracle* oracle) {
to_boolean_types_ = oracle->ToBooleanTypes(test_id());
}
void Property::RecordTypeFeedback(TypeFeedbackOracle* oracle,
Zone* zone) {
// Record type feedback from the oracle in the AST.
......@@ -486,6 +498,7 @@ void CountOperation::RecordTypeFeedback(TypeFeedbackOracle* oracle,
oracle->CollectKeyedReceiverTypes(id, &receiver_types_);
}
store_mode_ = oracle->GetStoreMode(id);
type_ = oracle->IncrementType(this);
}
......@@ -575,6 +588,32 @@ bool Call::ComputeGlobalTarget(Handle<GlobalObject> global,
}
Handle<JSObject> Call::GetPrototypeForPrimitiveCheck(
CheckType check, Isolate* isolate) {
v8::internal::Context* native_context = isolate->context()->native_context();
JSFunction* function = NULL;
switch (check) {
case RECEIVER_MAP_CHECK:
UNREACHABLE();
break;
case STRING_CHECK:
function = native_context->string_function();
break;
case SYMBOL_CHECK:
function = native_context->symbol_function();
break;
case NUMBER_CHECK:
function = native_context->number_function();
break;
case BOOLEAN_CHECK:
function = native_context->boolean_function();
break;
}
ASSERT(function != NULL);
return Handle<JSObject>(JSObject::cast(function->instance_prototype()));
}
void Call::RecordTypeFeedback(TypeFeedbackOracle* oracle,
CallKind call_kind) {
is_monomorphic_ = oracle->CallIsMonomorphic(this);
......@@ -606,8 +645,7 @@ void Call::RecordTypeFeedback(TypeFeedbackOracle* oracle,
map = receiver_types_.at(0);
} else {
ASSERT(check_type_ != RECEIVER_MAP_CHECK);
holder_ = Handle<JSObject>(
oracle->GetPrototypeForPrimitiveCheck(check_type_));
holder_ = GetPrototypeForPrimitiveCheck(check_type_, oracle->isolate());
map = Handle<Map>(holder_->map());
}
is_monomorphic_ = ComputeTarget(map, name);
......@@ -622,6 +660,12 @@ void CallNew::RecordTypeFeedback(TypeFeedbackOracle* oracle) {
target_ = oracle->GetCallNewTarget(this);
elements_kind_ = oracle->GetCallNewElementsKind(this);
}
Handle<Object> alloc_elements_kind = oracle->GetInfo(CallNewFeedbackId());
// if (alloc_elements_kind->IsSmi())
// alloc_elements_kind_ = Handle<Smi>::cast(alloc_elements_kind);
alloc_elements_kind_ = alloc_elements_kind->IsSmi()
? Handle<Smi>::cast(alloc_elements_kind)
: handle(Smi::FromInt(GetInitialFastElementsKind()), oracle->isolate());
}
......@@ -632,6 +676,30 @@ void ObjectLiteral::Property::RecordTypeFeedback(TypeFeedbackOracle* oracle) {
}
void UnaryOperation::RecordTypeFeedback(TypeFeedbackOracle* oracle) {
type_ = oracle->UnaryType(this);
}
void BinaryOperation::RecordTypeFeedback(TypeFeedbackOracle* oracle) {
oracle->BinaryType(this, &left_type_, &right_type_, &result_type_);
}
void CompareOperation::RecordTypeFeedback(TypeFeedbackOracle* oracle) {
oracle->CompareType(this, &left_type_, &right_type_, &overall_type_);
if (!overall_type_.IsUninitialized() && overall_type_.IsNonPrimitive() &&
(op_ == Token::EQ || op_ == Token::EQ_STRICT)) {
map_ = oracle->GetCompareMap(this);
} else {
// May be a compare to nil.
map_ = oracle->CompareNilMonomorphicReceiverType(this);
if (op_ != Token::EQ_STRICT)
compare_nil_types_ = oracle->CompareNilTypes(this);
}
}
// ----------------------------------------------------------------------------
// Implementation of AstVisitor
......
This diff is collapsed.
......@@ -672,7 +672,7 @@ class ArrayConstructorStub: public PlatformCodeStub {
class MathPowStub: public PlatformCodeStub {
public:
enum ExponentType { INTEGER, DOUBLE, TAGGED, ON_STACK};
enum ExponentType { INTEGER, DOUBLE, TAGGED, ON_STACK };
explicit MathPowStub(ExponentType exponent_type)
: exponent_type_(exponent_type) { }
......
......@@ -36,6 +36,7 @@
#include "deoptimizer.h"
#include "full-codegen.h"
#include "gdb-jit.h"
#include "typing.h"
#include "hydrogen.h"
#include "isolate-inl.h"
#include "lithium.h"
......@@ -361,11 +362,11 @@ OptimizingCompiler::Status OptimizingCompiler::CreateGraph() {
PrintF("Compiling method %s using hydrogen\n", *name->ToCString());
isolate()->GetHTracer()->TraceCompilation(info());
}
Handle<Context> native_context(
info()->closure()->context()->native_context());
oracle_ = new(info()->zone()) TypeFeedbackOracle(
code, native_context, isolate(), info()->zone());
graph_builder_ = new(info()->zone()) HOptimizedGraphBuilder(info(), oracle_);
// Type-check the function.
AstTyper::Type(info());
graph_builder_ = new(info()->zone()) HOptimizedGraphBuilder(info());
Timer t(this, &time_taken_to_create_graph_);
graph_ = graph_builder_->CreateGraph();
......
......@@ -449,7 +449,6 @@ class OptimizingCompiler: public ZoneObject {
public:
explicit OptimizingCompiler(CompilationInfo* info)
: info_(info),
oracle_(NULL),
graph_builder_(NULL),
graph_(NULL),
chunk_(NULL),
......@@ -478,7 +477,6 @@ class OptimizingCompiler: public ZoneObject {
private:
CompilationInfo* info_;
TypeFeedbackOracle* oracle_;
HOptimizedGraphBuilder* graph_builder_;
HGraph* graph_;
LChunk* chunk_;
......
This diff is collapsed.
......@@ -34,7 +34,6 @@
#include "ast.h"
#include "compiler.h"
#include "hydrogen-instructions.h"
#include "type-info.h"
#include "zone.h"
#include "scopes.h"
......@@ -792,12 +791,10 @@ class TestContext: public AstContext {
public:
TestContext(HOptimizedGraphBuilder* owner,
Expression* condition,
TypeFeedbackOracle* oracle,
HBasicBlock* if_true,
HBasicBlock* if_false)
: AstContext(owner, Expression::kTest),
condition_(condition),
oracle_(oracle),
if_true_(if_true),
if_false_(if_false) {
}
......@@ -814,7 +811,6 @@ class TestContext: public AstContext {
}
Expression* condition() const { return condition_; }
TypeFeedbackOracle* oracle() const { return oracle_; }
HBasicBlock* if_true() const { return if_true_; }
HBasicBlock* if_false() const { return if_false_; }
......@@ -824,7 +820,6 @@ class TestContext: public AstContext {
void BuildBranch(HValue* value);
Expression* condition_;
TypeFeedbackOracle* oracle_;
HBasicBlock* if_true_;
HBasicBlock* if_false_;
};
......@@ -834,12 +829,10 @@ class FunctionState {
public:
FunctionState(HOptimizedGraphBuilder* owner,
CompilationInfo* info,
TypeFeedbackOracle* oracle,
InliningKind inlining_kind);
~FunctionState();
CompilationInfo* compilation_info() { return compilation_info_; }
TypeFeedbackOracle* oracle() { return oracle_; }
AstContext* call_context() { return call_context_; }
InliningKind inlining_kind() const { return inlining_kind_; }
HBasicBlock* function_return() { return function_return_; }
......@@ -865,7 +858,6 @@ class FunctionState {
HOptimizedGraphBuilder* owner_;
CompilationInfo* compilation_info_;
TypeFeedbackOracle* oracle_;
// During function inlining, expression context of the call being
// inlined. NULL when not inlining.
......@@ -1353,9 +1345,6 @@ class HGraphBuilder {
class HOptimizedGraphBuilder: public HGraphBuilder, public AstVisitor {
public:
enum BreakType { BREAK, CONTINUE };
enum SwitchType { UNKNOWN_SWITCH, SMI_SWITCH, STRING_SWITCH };
// A class encapsulating (lazily-allocated) break and continue blocks for
// a breakable statement. Separated from BreakAndContinueScope so that it
// can have a separate lifetime.
......@@ -1400,6 +1389,7 @@ class HOptimizedGraphBuilder: public HGraphBuilder, public AstVisitor {
BreakAndContinueScope* next() { return next_; }
// Search the break stack for a break or continue target.
enum BreakType { BREAK, CONTINUE };
HBasicBlock* Get(BreakableStatement* stmt, BreakType type, int* drop_extra);
private:
......@@ -1408,7 +1398,7 @@ class HOptimizedGraphBuilder: public HGraphBuilder, public AstVisitor {
BreakAndContinueScope* next_;
};
HOptimizedGraphBuilder(CompilationInfo* info, TypeFeedbackOracle* oracle);
explicit HOptimizedGraphBuilder(CompilationInfo* info);
virtual bool BuildGraph();
......@@ -1426,8 +1416,6 @@ class HOptimizedGraphBuilder: public HGraphBuilder, public AstVisitor {
HBasicBlock* second,
BailoutId join_id);
TypeFeedbackOracle* oracle() const { return function_state()->oracle(); }
FunctionState* function_state() const { return function_state_; }
void VisitDeclarations(ZoneList<Declaration*>* declarations);
......
......@@ -184,10 +184,11 @@ bool TypeFeedbackOracle::ObjectLiteralStoreIsMonomorphic(
}
bool TypeFeedbackOracle::IsForInFastCase(ForInStatement* stmt) {
byte TypeFeedbackOracle::ForInType(ForInStatement* stmt) {
Handle<Object> value = GetInfo(stmt->ForInFeedbackId());
return value->IsSmi() &&
Smi::cast(*value)->value() == TypeFeedbackCells::kForInFastCaseMarker;
Smi::cast(*value)->value() == TypeFeedbackCells::kForInFastCaseMarker
? ForInStatement::FAST_FOR_IN : ForInStatement::SLOW_FOR_IN;
}
......@@ -221,8 +222,8 @@ Handle<Map> TypeFeedbackOracle::StoreMonomorphicReceiverType(
Handle<Map> TypeFeedbackOracle::CompareNilMonomorphicReceiverType(
TypeFeedbackId id) {
Handle<Object> maybe_code = GetInfo(id);
CompareOperation* expr) {
Handle<Object> maybe_code = GetInfo(expr->CompareOperationFeedbackId());
if (maybe_code->IsCode()) {
Map* map = Handle<Code>::cast(maybe_code)->FindFirstMap();
if (map == NULL) return Handle<Map>();
......@@ -296,31 +297,6 @@ CheckType TypeFeedbackOracle::GetCallCheckType(Call* expr) {
}
Handle<JSObject> TypeFeedbackOracle::GetPrototypeForPrimitiveCheck(
CheckType check) {
JSFunction* function = NULL;
switch (check) {
case RECEIVER_MAP_CHECK:
UNREACHABLE();
break;
case STRING_CHECK:
function = native_context_->string_function();
break;
case SYMBOL_CHECK:
function = native_context_->symbol_function();
break;
case NUMBER_CHECK:
function = native_context_->number_function();
break;
case BOOLEAN_CHECK:
function = native_context_->boolean_function();
break;
}
ASSERT(function != NULL);
return Handle<JSObject>(JSObject::cast(function->instance_prototype()));
}
Handle<JSFunction> TypeFeedbackOracle::GetCallTarget(Call* expr) {
return Handle<JSFunction>::cast(GetInfo(expr->CallFeedbackId()));
}
......@@ -641,8 +617,8 @@ byte TypeFeedbackOracle::ToBooleanTypes(TypeFeedbackId id) {
}
byte TypeFeedbackOracle::CompareNilTypes(TypeFeedbackId id) {
Handle<Object> object = GetInfo(id);
byte TypeFeedbackOracle::CompareNilTypes(CompareOperation* expr) {
Handle<Object> object = GetInfo(expr->CompareOperationFeedbackId());
if (object->IsCode() &&
Handle<Code>::cast(object)->is_compare_nil_ic_stub()) {
return Handle<Code>::cast(object)->compare_nil_types();
......
......@@ -29,7 +29,6 @@
#define V8_TYPE_INFO_H_
#include "allocation.h"
#include "ast.h"
#include "globals.h"
#include "zone-inl.h"
......@@ -232,6 +231,8 @@ class ICStub;
class Property;
class SmallMapList;
class UnaryOperation;
class ObjectLiteral;
class ObjectLiteralProperty;
class TypeFeedbackOracle: public ZoneObject {
......@@ -248,13 +249,15 @@ class TypeFeedbackOracle: public ZoneObject {
bool StoreIsPolymorphic(TypeFeedbackId ast_id);
bool CallIsMonomorphic(Call* expr);
bool CallNewIsMonomorphic(CallNew* expr);
bool ObjectLiteralStoreIsMonomorphic(ObjectLiteral::Property* prop);
bool ObjectLiteralStoreIsMonomorphic(ObjectLiteralProperty* prop);
bool IsForInFastCase(ForInStatement* expr);
// TODO(1571) We can't use ForInStatement::ForInType as the return value due
// to various cycles in our headers.
byte ForInType(ForInStatement* expr);
Handle<Map> LoadMonomorphicReceiverType(Property* expr);
Handle<Map> StoreMonomorphicReceiverType(TypeFeedbackId id);
Handle<Map> CompareNilMonomorphicReceiverType(TypeFeedbackId id);
Handle<Map> CompareNilMonomorphicReceiverType(CompareOperation* expr);
KeyedAccessStoreMode GetStoreMode(TypeFeedbackId ast_id);
......@@ -278,26 +281,24 @@ class TypeFeedbackOracle: public ZoneObject {
void CollectPolymorphicMaps(Handle<Code> code, SmallMapList* types);
CheckType GetCallCheckType(Call* expr);
Handle<JSObject> GetPrototypeForPrimitiveCheck(CheckType check);
Handle<JSFunction> GetCallTarget(Call* expr);
Handle<JSFunction> GetCallNewTarget(CallNew* expr);
ElementsKind GetCallNewElementsKind(CallNew* expr);
Handle<Map> GetObjectLiteralStoreMap(ObjectLiteral::Property* prop);
Handle<Map> GetObjectLiteralStoreMap(ObjectLiteralProperty* prop);
bool LoadIsBuiltin(Property* expr, Builtins::Name id);
bool LoadIsStub(Property* expr, ICStub* stub);
// TODO(1571) We can't use ToBooleanStub::Types as the return value because
// of various cylces in our headers. Death to tons of implementations in
// of various cycles in our headers. Death to tons of implementations in
// headers!! :-P
byte ToBooleanTypes(TypeFeedbackId ast_id);
// TODO(1571) We can't use CompareNilICStub::Types as the return value because
// of various cylces in our headers. Death to tons of implementations in
// headers!! :-P
byte CompareNilTypes(TypeFeedbackId ast_id);
byte CompareNilTypes(CompareOperation* expr);
// Get type information for arithmetic operations and compares.
TypeInfo UnaryType(UnaryOperation* expr);
......@@ -314,6 +315,7 @@ class TypeFeedbackOracle: public ZoneObject {
TypeInfo IncrementType(CountOperation* expr);
Zone* zone() const { return zone_; }
Isolate* isolate() const { return isolate_; }
private:
void CollectReceiverTypes(TypeFeedbackId ast_id,
......
This diff is collapsed.
// Copyright 2013 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef V8_TYPING_H_
#define V8_TYPING_H_
#include "v8.h"
#include "allocation.h"
#include "ast.h"
#include "compiler.h"
#include "type-info.h"
#include "zone.h"
#include "scopes.h"
namespace v8 {
namespace internal {
class AstTyper: public AstVisitor {
public:
static void Type(CompilationInfo* info);
void* operator new(size_t size, Zone* zone) {
return zone->New(static_cast<int>(size));
}
void operator delete(void* pointer, Zone* zone) { }
void operator delete(void* pointer) { }
DEFINE_AST_VISITOR_SUBCLASS_MEMBERS();
private:
explicit AstTyper(CompilationInfo* info);
CompilationInfo* info_;
TypeFeedbackOracle oracle_;
TypeFeedbackOracle* oracle() { return &oracle_; }
Zone* zone() const { return info_->zone(); }
void VisitDeclarations(ZoneList<Declaration*>* declarations);
void VisitStatements(ZoneList<Statement*>* statements);
#define DECLARE_VISIT(type) virtual void Visit##type(type* node);
AST_NODE_LIST(DECLARE_VISIT)
#undef DECLARE_VISIT
DISALLOW_COPY_AND_ASSIGN(AstTyper);
};
} } // namespace v8::internal
#endif // V8_TYPING_H_
......@@ -453,6 +453,8 @@
'../../src/transitions.h',
'../../src/type-info.cc',
'../../src/type-info.h',
'../../src/typing.cc',
'../../src/typing.h',
'../../src/unbound-queue-inl.h',
'../../src/unbound-queue.h',
'../../src/unicode-inl.h',
......
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