#include <cmath> // For isfinite.
#include "builtins.h"
#include "code-stubs.h"
+#include "contexts.h"
#include "conversions.h"
#include "hashmap.h"
#include "parser.h"
}
-ObjectLiteral::Property::Property(Literal* key,
- Expression* value,
- Isolate* isolate) {
+ObjectLiteralProperty::ObjectLiteralProperty(Literal* key,
+ Expression* value,
+ Isolate* isolate) {
emit_store_ = true;
key_ = key;
value_ = value;
}
-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;
// ----------------------------------------------------------------------------
// 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.
oracle->CollectKeyedReceiverTypes(id, &receiver_types_);
}
store_mode_ = oracle->GetStoreMode(id);
+ type_ = oracle->IncrementType(this);
}
}
+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);
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);
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());
}
}
+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
#include "small-pointer-list.h"
#include "smart-pointers.h"
#include "token.h"
+#include "type-info.h"
#include "utils.h"
#include "variables.h"
#include "interface.h"
return STANDARD_STORE;
}
+ // TODO(rossberg): this should move to its own AST node eventually.
+ void RecordToBooleanTypeFeedback(TypeFeedbackOracle* oracle);
+ byte to_boolean_types() const { return to_boolean_types_; }
+
BailoutId id() const { return id_; }
TypeFeedbackId test_id() const { return test_id_; }
test_id_(GetNextId(isolate)) {}
private:
+ byte to_boolean_types_;
+
const BailoutId id_;
const TypeFeedbackId test_id_;
};
private:
Statement* body_;
Label continue_target_;
+
const BailoutId osr_entry_id_;
};
private:
Expression* cond_;
+
int condition_position_;
+
const BailoutId continue_id_;
const BailoutId back_edge_id_;
};
private:
Expression* cond_;
+
// True if there is a function literal subexpression in the condition.
bool may_have_function_literal_;
+
const BailoutId body_id_;
};
Statement* init_;
Expression* cond_;
Statement* next_;
+
// True if there is a function literal subexpression in the condition.
bool may_have_function_literal_;
Variable* loop_variable_;
+
const BailoutId continue_id_;
const BailoutId body_id_;
};
IterationStatement::Initialize(body);
each_ = each;
enumerable_ = enumerable;
+ for_in_type_ = SLOW_FOR_IN;
}
Expression* each() const { return each_; }
BailoutId PrepareId() const { return prepare_id_; }
TypeFeedbackId ForInFeedbackId() const { return reuse(PrepareId()); }
+ void RecordTypeFeedback(TypeFeedbackOracle* oracle);
+ enum ForInType { FAST_FOR_IN, SLOW_FOR_IN };
+ ForInType for_in_type() const { return for_in_type_; }
protected:
ForInStatement(Isolate* isolate, ZoneStringList* labels)
private:
Expression* each_;
Expression* enumerable_;
+
+ ForInType for_in_type_;
+
const BailoutId body_id_;
const BailoutId prepare_id_;
};
void Initialize(Expression* tag, ZoneList<CaseClause*>* cases) {
tag_ = tag;
cases_ = cases;
+ switch_type_ = UNKNOWN_SWITCH;
}
Expression* tag() const { return tag_; }
ZoneList<CaseClause*>* cases() const { return cases_; }
+ enum SwitchType { UNKNOWN_SWITCH, SMI_SWITCH, STRING_SWITCH, GENERIC_SWITCH };
+ SwitchType switch_type() const { return switch_type_; }
+ void set_switch_type(SwitchType switch_type) { switch_type_ = switch_type; }
+
protected:
SwitchStatement(Isolate* isolate, ZoneStringList* labels)
: BreakableStatement(isolate, labels, TARGET_FOR_ANONYMOUS),
private:
Expression* tag_;
ZoneList<CaseClause*>* cases_;
+ SwitchType switch_type_;
};
};
+// Property is used for passing information
+// about an object literal's properties from the parser
+// to the code generator.
+class ObjectLiteralProperty: public ZoneObject {
+ public:
+ enum Kind {
+ CONSTANT, // Property with constant value (compile time).
+ COMPUTED, // Property with computed value (execution time).
+ MATERIALIZED_LITERAL, // Property value is a materialized literal.
+ GETTER, SETTER, // Property is an accessor function.
+ PROTOTYPE // Property is __proto__.
+ };
+
+ ObjectLiteralProperty(Literal* key, Expression* value, Isolate* isolate);
+
+ Literal* key() { return key_; }
+ Expression* value() { return value_; }
+ Kind kind() { return kind_; }
+
+ // Type feedback information.
+ void RecordTypeFeedback(TypeFeedbackOracle* oracle);
+ bool IsMonomorphic() { return !receiver_type_.is_null(); }
+ Handle<Map> GetReceiverType() { return receiver_type_; }
+
+ bool IsCompileTimeValue();
+
+ void set_emit_store(bool emit_store);
+ bool emit_store();
+
+ protected:
+ template<class> friend class AstNodeFactory;
+
+ ObjectLiteralProperty(bool is_getter, FunctionLiteral* value);
+ void set_key(Literal* key) { key_ = key; }
+
+ private:
+ Literal* key_;
+ Expression* value_;
+ Kind kind_;
+ bool emit_store_;
+ Handle<Map> receiver_type_;
+};
+
+
// An object literal has a boilerplate object that is used
// for minimizing the work when constructing it at runtime.
class ObjectLiteral: public MaterializedLiteral {
public:
- // Property is used for passing information
- // about an object literal's properties from the parser
- // to the code generator.
- class Property: public ZoneObject {
- public:
- enum Kind {
- CONSTANT, // Property with constant value (compile time).
- COMPUTED, // Property with computed value (execution time).
- MATERIALIZED_LITERAL, // Property value is a materialized literal.
- GETTER, SETTER, // Property is an accessor function.
- PROTOTYPE // Property is __proto__.
- };
-
- Property(Literal* key, Expression* value, Isolate* isolate);
-
- Literal* key() { return key_; }
- Expression* value() { return value_; }
- Kind kind() { return kind_; }
-
- // Type feedback information.
- void RecordTypeFeedback(TypeFeedbackOracle* oracle);
- bool IsMonomorphic() { return !receiver_type_.is_null(); }
- Handle<Map> GetReceiverType() { return receiver_type_; }
-
- bool IsCompileTimeValue();
-
- void set_emit_store(bool emit_store);
- bool emit_store();
-
- protected:
- template<class> friend class AstNodeFactory;
-
- Property(bool is_getter, FunctionLiteral* value);
- void set_key(Literal* key) { key_ = key; }
-
- private:
- Literal* key_;
- Expression* value_;
- Kind kind_;
- bool emit_store_;
- Handle<Map> receiver_type_;
- };
+ typedef ObjectLiteralProperty Property;
DECLARE_NODE_TYPE(ObjectLiteral)
BailoutId ReturnId() const { return return_id_; }
+ // TODO(rossberg): this should really move somewhere else (and be merged with
+ // various similar methods in objets.cc), but for now...
+ static Handle<JSObject> GetPrototypeForPrimitiveCheck(
+ CheckType check, Isolate* isolate);
+
#ifdef DEBUG
// Used to assert that the FullCodeGenerator records the return site.
bool return_is_recorded_;
TypeFeedbackId CallNewFeedbackId() const { return reuse(id()); }
void RecordTypeFeedback(TypeFeedbackOracle* oracle);
virtual bool IsMonomorphic() { return is_monomorphic_; }
- Handle<JSFunction> target() { return target_; }
+ Handle<JSFunction> target() const { return target_; }
+ ElementsKind elements_kind() const { return elements_kind_; }
+ Handle<Smi> allocation_elements_kind() const { return alloc_elements_kind_; }
BailoutId ReturnId() const { return return_id_; }
- ElementsKind elements_kind() const { return elements_kind_; }
protected:
CallNew(Isolate* isolate,
arguments_(arguments),
pos_(pos),
is_monomorphic_(false),
- return_id_(GetNextId(isolate)),
- elements_kind_(GetInitialFastElementsKind()) { }
+ elements_kind_(GetInitialFastElementsKind()),
+ return_id_(GetNextId(isolate)) { }
private:
Expression* expression_;
bool is_monomorphic_;
Handle<JSFunction> target_;
+ ElementsKind elements_kind_;
+ Handle<Smi> alloc_elements_kind_;
const BailoutId return_id_;
- ElementsKind elements_kind_;
};
BailoutId MaterializeFalseId() { return materialize_false_id_; }
TypeFeedbackId UnaryOperationFeedbackId() const { return reuse(id()); }
+ void RecordTypeFeedback(TypeFeedbackOracle* oracle);
+ TypeInfo type() const { return type_; }
protected:
UnaryOperation(Isolate* isolate,
Expression* expression_;
int pos_;
+ TypeInfo type_;
+
// For unary not (Token::NOT), the AST ids where true and false will
// actually be materialized, respectively.
const BailoutId materialize_true_id_;
BailoutId RightId() const { return right_id_; }
TypeFeedbackId BinaryOperationFeedbackId() const { return reuse(id()); }
+ void RecordTypeFeedback(TypeFeedbackOracle* oracle);
+ TypeInfo left_type() const { return left_type_; }
+ TypeInfo right_type() const { return right_type_; }
+ TypeInfo result_type() const { return result_type_; }
protected:
BinaryOperation(Isolate* isolate,
Expression* left_;
Expression* right_;
int pos_;
+
+ TypeInfo left_type_;
+ TypeInfo right_type_;
+ TypeInfo result_type_;
+
// The short-circuit logical operations need an AST ID for their
// right-hand subexpression.
const BailoutId right_id_;
virtual KeyedAccessStoreMode GetStoreMode() {
return store_mode_;
}
+ TypeInfo type() const { return type_; }
BailoutId AssignmentId() const { return assignment_id_; }
bool is_monomorphic_ : 1;
KeyedAccessStoreMode store_mode_ : 5; // Windows treats as signed,
// must have extra bit.
+ TypeInfo type_;
+
Expression* expression_;
int pos_;
const BailoutId assignment_id_;
// Type feedback information.
TypeFeedbackId CompareOperationFeedbackId() const { return reuse(id()); }
+ void RecordTypeFeedback(TypeFeedbackOracle* oracle);
+ TypeInfo left_type() const { return left_type_; }
+ TypeInfo right_type() const { return right_type_; }
+ TypeInfo overall_type() const { return overall_type_; }
+ byte compare_nil_types() const { return compare_nil_types_; }
+ Handle<Map> map() const { return map_; }
// Match special cases.
bool IsLiteralCompareTypeof(Expression** expr, Handle<String>* check);
Expression* left_;
Expression* right_;
int pos_;
+
+ TypeInfo left_type_;
+ TypeInfo right_type_;
+ TypeInfo overall_type_;
+ byte compare_nil_types_;
+ Handle<Map> map_;
};
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) { }
#include "deoptimizer.h"
#include "full-codegen.h"
#include "gdb-jit.h"
+#include "typing.h"
#include "hydrogen.h"
#include "isolate-inl.h"
#include "lithium.h"
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();
public:
explicit OptimizingCompiler(CompilationInfo* info)
: info_(info),
- oracle_(NULL),
graph_builder_(NULL),
graph_(NULL),
chunk_(NULL),
private:
CompilationInfo* info_;
- TypeFeedbackOracle* oracle_;
HOptimizedGraphBuilder* graph_builder_;
HGraph* graph_;
LChunk* chunk_;
#include "scopeinfo.h"
#include "scopes.h"
#include "stub-cache.h"
+#include "typing.h"
#if V8_TARGET_ARCH_IA32
#include "ia32/lithium-codegen-ia32.h"
}
-HOptimizedGraphBuilder::HOptimizedGraphBuilder(CompilationInfo* info,
- TypeFeedbackOracle* oracle)
+HOptimizedGraphBuilder::HOptimizedGraphBuilder(CompilationInfo* info)
: HGraphBuilder(info),
function_state_(NULL),
- initial_function_state_(this, info, oracle, NORMAL_RETURN),
+ initial_function_state_(this, info, NORMAL_RETURN),
ast_context_(NULL),
break_scope_(NULL),
inlined_count_(0),
// a (possibly inlined) function.
FunctionState::FunctionState(HOptimizedGraphBuilder* owner,
CompilationInfo* info,
- TypeFeedbackOracle* oracle,
InliningKind inlining_kind)
: owner_(owner),
compilation_info_(info),
- oracle_(oracle),
call_context_(NULL),
inlining_kind_(inlining_kind),
function_return_(NULL),
if_false->MarkAsInlineReturnTarget();
TestContext* outer_test_context = TestContext::cast(owner->ast_context());
Expression* cond = outer_test_context->condition();
- TypeFeedbackOracle* outer_oracle = outer_test_context->oracle();
// The AstContext constructor pushed on the context stack. This newed
// instance is the reason that AstContext can't be BASE_EMBEDDED.
- test_context_ =
- new TestContext(owner, cond, outer_oracle, if_true, if_false);
+ test_context_ = new TestContext(owner, cond, if_true, if_false);
} else {
function_return_ = owner->graph()->CreateBasicBlock();
function_return()->MarkAsInlineReturnTarget();
}
HBasicBlock* empty_true = builder->graph()->CreateBasicBlock();
HBasicBlock* empty_false = builder->graph()->CreateBasicBlock();
- TypeFeedbackId test_id = condition()->test_id();
- ToBooleanStub::Types expected(oracle()->ToBooleanTypes(test_id));
+ ToBooleanStub::Types expected(condition()->to_boolean_types());
HBranch* test = new(zone()) HBranch(value, empty_true, empty_false, expected);
builder->current_block()->Finish(test);
void HOptimizedGraphBuilder::VisitForControl(Expression* expr,
HBasicBlock* true_block,
HBasicBlock* false_block) {
- TestContext for_test(this, expr, oracle(), true_block, false_block);
+ TestContext for_test(this, expr, true_block, false_block);
Visit(expr);
}
ASSERT(current_block() != NULL);
ASSERT(current_block()->HasPredecessor());
int drop_extra = 0;
- HBasicBlock* continue_block = break_scope()->Get(stmt->target(),
- CONTINUE,
- &drop_extra);
+ HBasicBlock* continue_block = break_scope()->Get(
+ stmt->target(), BreakAndContinueScope::CONTINUE, &drop_extra);
Drop(drop_extra);
current_block()->Goto(continue_block);
set_current_block(NULL);
ASSERT(current_block() != NULL);
ASSERT(current_block()->HasPredecessor());
int drop_extra = 0;
- HBasicBlock* break_block = break_scope()->Get(stmt->target(),
- BREAK,
- &drop_extra);
+ HBasicBlock* break_block = break_scope()->Get(
+ stmt->target(), BreakAndContinueScope::BREAK, &drop_extra);
Drop(drop_extra);
current_block()->Goto(break_block);
set_current_block(NULL);
ASSERT(!HasStackOverflow());
ASSERT(current_block() != NULL);
ASSERT(current_block()->HasPredecessor());
+
// We only optimize switch statements with smi-literal smi comparisons,
// with a bounded number of clauses.
const int kCaseClauseLimit = 128;
return Bailout("SwitchStatement: too many clauses");
}
+ ASSERT(stmt->switch_type() != SwitchStatement::UNKNOWN_SWITCH);
+ if (stmt->switch_type() == SwitchStatement::GENERIC_SWITCH) {
+ return Bailout("SwitchStatement: mixed or non-literal switch labels");
+ }
+
HValue* context = environment()->LookupContext();
CHECK_ALIVE(VisitForValue(stmt->tag()));
HValue* tag_value = Pop();
HBasicBlock* first_test_block = current_block();
- SwitchType switch_type = UNKNOWN_SWITCH;
-
- // 1. Extract clause type
- for (int i = 0; i < clause_count; ++i) {
- CaseClause* clause = clauses->at(i);
- if (clause->is_default()) continue;
-
- if (switch_type == UNKNOWN_SWITCH) {
- if (clause->label()->IsSmiLiteral()) {
- switch_type = SMI_SWITCH;
- } else if (clause->label()->IsStringLiteral()) {
- switch_type = STRING_SWITCH;
- } else {
- return Bailout("SwitchStatement: non-literal switch label");
- }
- } else if ((switch_type == STRING_SWITCH &&
- !clause->label()->IsStringLiteral()) ||
- (switch_type == SMI_SWITCH &&
- !clause->label()->IsSmiLiteral())) {
- return Bailout("SwitchStatement: mixed label types are not supported");
- }
- }
-
HUnaryControlInstruction* string_check = NULL;
HBasicBlock* not_string_block = NULL;
// Test switch's tag value if all clauses are string literals
- if (switch_type == STRING_SWITCH) {
+ if (stmt->switch_type() == SwitchStatement::STRING_SWITCH) {
string_check = new(zone()) HIsStringAndBranch(tag_value);
first_test_block = graph()->CreateBasicBlock();
not_string_block = graph()->CreateBasicBlock();
set_current_block(first_test_block);
}
- // 2. Build all the tests, with dangling true branches
+ // 1. Build all the tests, with dangling true branches
BailoutId default_id = BailoutId::None();
for (int i = 0; i < clause_count; ++i) {
CaseClause* clause = clauses->at(i);
default_id = clause->EntryId();
continue;
}
- if (switch_type == SMI_SWITCH) {
- clause->RecordTypeFeedback(oracle());
- }
// Generate a compare and branch.
CHECK_ALIVE(VisitForValue(clause->label()));
HControlInstruction* compare;
- if (switch_type == SMI_SWITCH) {
+ if (stmt->switch_type() == SwitchStatement::SMI_SWITCH) {
if (!clause->IsSmiCompare()) {
// Finish with deoptimize and add uses of enviroment values to
// account for invisible uses.
last_block = CreateJoin(last_block, not_string_block, join_id);
}
- // 3. Loop over the clauses and the linked list of tests in lockstep,
+ // 2. Loop over the clauses and the linked list of tests in lockstep,
// translating the clause bodies.
HBasicBlock* curr_test_block = first_test_block;
HBasicBlock* fall_through_block = NULL;
return Bailout("ForInStatement optimization is disabled");
}
- if (!oracle()->IsForInFastCase(stmt)) {
+ if (stmt->for_in_type() != ForInStatement::FAST_FOR_IN) {
return Bailout("ForInStatement is not fast case");
}
static Handle<SharedFunctionInfo> SearchSharedFunctionInfo(
Code* unoptimized_code, FunctionLiteral* expr) {
int start_position = expr->start_position();
- RelocIterator it(unoptimized_code);
- for (; !it.done(); it.next()) {
+ for (RelocIterator it(unoptimized_code); !it.done(); it.next()) {
RelocInfo* rinfo = it.rinfo();
if (rinfo->rmode() != RelocInfo::EMBEDDED_OBJECT) continue;
Object* obj = rinfo->target_object();
ASSERT(current_block() != NULL);
ASSERT(current_block()->HasPredecessor());
Handle<SharedFunctionInfo> shared_info =
- SearchSharedFunctionInfo(info()->shared_info()->code(),
- expr);
+ SearchSharedFunctionInfo(info()->shared_info()->code(), expr);
if (shared_info.is_null()) {
shared_info = Compiler::BuildFunctionInfo(expr, info()->script());
}
case ObjectLiteral::Property::COMPUTED:
if (key->handle()->IsInternalizedString()) {
if (property->emit_store()) {
- property->RecordTypeFeedback(oracle());
CHECK_ALIVE(VisitForValue(value));
HValue* value = Pop();
Handle<Map> map = property->GetReceiverType();
void HOptimizedGraphBuilder::HandlePropertyAssignment(Assignment* expr) {
Property* prop = expr->target()->AsProperty();
ASSERT(prop != NULL);
- expr->RecordTypeFeedback(oracle(), zone());
CHECK_ALIVE(VisitForValue(prop->obj()));
if (prop->key()->IsPropertyName()) {
return ast_context()->ReturnValue(Pop());
} else if (prop != NULL) {
- prop->RecordTypeFeedback(oracle(), zone());
-
if (prop->key()->IsPropertyName()) {
// Named property.
CHECK_ALIVE(VisitForValue(prop->obj()));
Push(load);
if (has_side_effects) AddSimulate(prop->LoadId(), REMOVABLE_SIMULATE);
-
CHECK_ALIVE(VisitForValue(expr->value()));
HValue* right = Pop();
HValue* left = Pop();
AddSimulate(operation->id(), REMOVABLE_SIMULATE);
}
- expr->RecordTypeFeedback(oracle(), zone());
HandleKeyedElementAccess(obj, key, instr, expr, expr->AssignmentId(),
RelocInfo::kNoPosition,
true, // is_store
ASSERT(!HasStackOverflow());
ASSERT(current_block() != NULL);
ASSERT(current_block()->HasPredecessor());
- expr->RecordTypeFeedback(oracle(), zone());
if (TryArgumentsAccess(expr)) return;
// After this point, we've made a decision to inline this function (so
// TryInline should always return true).
- // Save the pending call context and type feedback oracle. Set up new ones
- // for the inlined function.
+ // Type-check the inlined function.
ASSERT(target_shared->has_deoptimization_support());
- Handle<Code> unoptimized_code(target_shared->code());
- TypeFeedbackOracle target_oracle(
- unoptimized_code,
- Handle<Context>(target->context()->native_context()),
- isolate(),
- zone());
+ AstTyper::Type(&target_info);
+
+ // Save the pending call context. Set up new one for the inlined function.
// The function state is new-allocated because we need to delete it
// in two different places.
FunctionState* target_state = new FunctionState(
- this, &target_info, &target_oracle, inlining_kind);
+ this, &target_info, inlining_kind);
HConstant* undefined = graph()->GetConstantUndefined();
bool undefined_receiver = HEnvironment::UseUndefinedReceiver(
// Update inlined nodes count.
inlined_count_ += nodes_added;
+ Handle<Code> unoptimized_code(target_shared->code());
ASSERT(unoptimized_code->kind() == Code::FUNCTION);
Handle<TypeFeedbackInfo> type_info(
TypeFeedbackInfo::cast(unoptimized_code->type_feedback_info()));
HValue* context = environment()->LookupContext();
ASSERT(!expr->holder().is_null());
AddInstruction(new(zone()) HCheckPrototypeMaps(
- oracle()->GetPrototypeForPrimitiveCheck(STRING_CHECK),
+ Call::GetPrototypeForPrimitiveCheck(STRING_CHECK,
+ expr->holder()->GetIsolate()),
expr->holder(),
zone()));
HInstruction* char_code =
}
// Named function call.
- expr->RecordTypeFeedback(oracle(), CALL_AS_METHOD);
-
if (TryCallApply(expr)) return;
CHECK_ALIVE(VisitForValue(prop->obj()));
}
} else {
- expr->RecordTypeFeedback(oracle(), CALL_AS_FUNCTION);
VariableProxy* proxy = expr->expression()->AsVariableProxy();
bool global_call = proxy != NULL && proxy->var()->IsUnallocated();
ASSERT(!HasStackOverflow());
ASSERT(current_block() != NULL);
ASSERT(current_block()->HasPredecessor());
- expr->RecordTypeFeedback(oracle());
int argument_count = expr->arguments()->length() + 1; // Plus constructor.
HValue* context = environment()->LookupContext();
// information that happened after crankshaft won't be lost. The right
// way to do that is to begin passing the cell to the type feedback oracle
// instead of just the value in the cell. Do this in a follow-up checkin.
- Handle<Object> feedback = oracle()->GetInfo(expr->CallNewFeedbackId());
- ASSERT(feedback->IsSmi());
+ Handle<Smi> feedback = expr->allocation_elements_kind();
Handle<JSGlobalPropertyCell> cell =
isolate()->factory()->NewJSGlobalPropertyCell(feedback);
}
}
+
void HOptimizedGraphBuilder::VisitDelete(UnaryOperation* expr) {
Property* prop = expr->expression()->AsProperty();
VariableProxy* proxy = expr->expression()->AsVariableProxy();
HValue* context = environment()->LookupContext();
HInstruction* instr =
HMul::New(zone(), context, value, graph()->GetConstantMinus1());
- TypeInfo info = oracle()->UnaryType(expr);
+ TypeInfo info = expr->type();
Representation rep = ToRepresentation(info);
if (info.IsUninitialized()) {
AddSoftDeoptimize();
void HOptimizedGraphBuilder::VisitBitNot(UnaryOperation* expr) {
CHECK_ALIVE(VisitForValue(expr->expression()));
HValue* value = Pop();
- TypeInfo info = oracle()->UnaryType(expr);
+ TypeInfo info = expr->type();
if (info.IsUninitialized()) {
AddSoftDeoptimize();
}
bool returns_original_input,
CountOperation* expr) {
// The input to the count operation is on top of the expression stack.
- TypeInfo info = oracle()->IncrementType(expr);
+ TypeInfo info = expr->type();
Representation rep = ToRepresentation(info);
if (rep.IsTagged()) {
rep = Representation::Integer32();
} else {
// Argument of the count operation is a property.
ASSERT(prop != NULL);
- prop->RecordTypeFeedback(oracle(), zone());
if (prop->key()->IsPropertyName()) {
// Named property.
after = BuildIncrement(returns_original_input, expr);
input = environment()->ExpressionStackAt(0);
- expr->RecordTypeFeedback(oracle(), zone());
HandleKeyedElementAccess(obj, key, after, expr, expr->AssignmentId(),
RelocInfo::kNoPosition,
true, // is_store
HValue* left,
HValue* right) {
HValue* context = environment()->LookupContext();
- TypeInfo left_info, right_info, result_info, combined_info;
- oracle()->BinaryType(expr, &left_info, &right_info, &result_info);
+ TypeInfo left_info = expr->left_type();
+ TypeInfo right_info = expr->right_type();
+ TypeInfo result_info = expr->result_type();
+ TypeInfo combined_info;
Representation left_rep = ToRepresentation(left_info);
Representation right_rep = ToRepresentation(right_info);
Representation result_rep = ToRepresentation(result_info);
// We need an extra block to maintain edge-split form.
HBasicBlock* empty_block = graph()->CreateBasicBlock();
HBasicBlock* eval_right = graph()->CreateBasicBlock();
- TypeFeedbackId test_id = expr->left()->test_id();
- ToBooleanStub::Types expected(oracle()->ToBooleanTypes(test_id));
+ ToBooleanStub::Types expected(expr->left()->to_boolean_types());
HBranch* test = is_logical_and
? new(zone()) HBranch(left_value, eval_right, empty_block, expected)
: new(zone()) HBranch(left_value, empty_block, eval_right, expected);
return ast_context()->ReturnControl(instr, expr->id());
}
- TypeInfo left_type, right_type, overall_type_info;
- oracle()->CompareType(expr, &left_type, &right_type, &overall_type_info);
- Representation combined_rep = ToRepresentation(overall_type_info);
+ TypeInfo left_type = expr->left_type();
+ TypeInfo right_type = expr->right_type();
+ TypeInfo overall_type = expr->overall_type();
+ Representation combined_rep = ToRepresentation(overall_type);
Representation left_rep = ToRepresentation(left_type);
Representation right_rep = ToRepresentation(right_type);
// Check if this expression was ever executed according to type feedback.
// Note that for the special typeof/null/undefined cases we get unknown here.
- if (overall_type_info.IsUninitialized()) {
+ if (overall_type.IsUninitialized()) {
AddSoftDeoptimize();
- overall_type_info = left_type = right_type = TypeInfo::Unknown();
+ overall_type = left_type = right_type = TypeInfo::Unknown();
}
CHECK_ALIVE(VisitForValue(expr->left()));
HIn* result = new(zone()) HIn(context, left, right);
result->set_position(expr->position());
return ast_context()->ReturnInstruction(result, expr->id());
- } else if (overall_type_info.IsNonPrimitive()) {
+ } else if (overall_type.IsNonPrimitive()) {
switch (op) {
case Token::EQ:
case Token::EQ_STRICT: {
// Can we get away with map check and not instance type check?
- Handle<Map> map = oracle()->GetCompareMap(expr);
+ Handle<Map> map = expr->map();
if (!map.is_null()) {
AddCheckMapsWithTransitions(left, map);
AddCheckMapsWithTransitions(right, map);
default:
return Bailout("Unsupported non-primitive compare");
}
- } else if (overall_type_info.IsInternalizedString() &&
+ } else if (overall_type.IsInternalizedString() &&
Token::IsEqualityOp(op)) {
BuildCheckNonSmi(left);
AddInstruction(HCheckInstanceType::NewIsInternalizedString(left, zone()));
EqualityKind kind =
expr->op() == Token::EQ_STRICT ? kStrictEquality : kNonStrictEquality;
HIfContinuation continuation;
- TypeFeedbackId id = expr->CompareOperationFeedbackId();
CompareNilICStub::Types types;
if (kind == kStrictEquality) {
types.Add((nil == kNullValue) ? CompareNilICStub::NULL_TYPE :
CompareNilICStub::UNDEFINED);
} else {
- types = CompareNilICStub::Types(oracle()->CompareNilTypes(id));
- if (types.IsEmpty()) {
- types = CompareNilICStub::Types::FullCompare();
- }
+ types = CompareNilICStub::Types(expr->compare_nil_types());
+ if (types.IsEmpty()) types = CompareNilICStub::Types::FullCompare();
}
- Handle<Map> map_handle(oracle()->CompareNilMonomorphicReceiverType(id));
+ Handle<Map> map_handle = expr->map();
BuildCompareNil(value, kind, types, map_handle,
expr->position(), &continuation);
return ast_context()->ReturnContinuation(&continuation, expr->id());
#include "ast.h"
#include "compiler.h"
#include "hydrogen-instructions.h"
-#include "type-info.h"
#include "zone.h"
#include "scopes.h"
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) {
}
}
Expression* condition() const { return condition_; }
- TypeFeedbackOracle* oracle() const { return oracle_; }
HBasicBlock* if_true() const { return if_true_; }
HBasicBlock* if_false() const { return if_false_; }
void BuildBranch(HValue* value);
Expression* condition_;
- TypeFeedbackOracle* oracle_;
HBasicBlock* if_true_;
HBasicBlock* if_false_;
};
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_; }
HOptimizedGraphBuilder* owner_;
CompilationInfo* compilation_info_;
- TypeFeedbackOracle* oracle_;
// During function inlining, expression context of the call being
// inlined. NULL when not inlining.
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.
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:
BreakAndContinueScope* next_;
};
- HOptimizedGraphBuilder(CompilationInfo* info, TypeFeedbackOracle* oracle);
+ explicit HOptimizedGraphBuilder(CompilationInfo* info);
virtual bool BuildGraph();
HBasicBlock* second,
BailoutId join_id);
- TypeFeedbackOracle* oracle() const { return function_state()->oracle(); }
-
FunctionState* function_state() const { return function_state_; }
void VisitDeclarations(ZoneList<Declaration*>* declarations);
}
-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;
}
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>();
}
-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()));
}
}
-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();
#define V8_TYPE_INFO_H_
#include "allocation.h"
-#include "ast.h"
#include "globals.h"
#include "zone-inl.h"
class Property;
class SmallMapList;
class UnaryOperation;
+class ObjectLiteral;
+class ObjectLiteralProperty;
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);
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);
TypeInfo IncrementType(CountOperation* expr);
Zone* zone() const { return zone_; }
+ Isolate* isolate() const { return isolate_; }
private:
void CollectReceiverTypes(TypeFeedbackId ast_id,
--- /dev/null
+// 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.
+
+#include "typing.h"
+
+#include "v8.h"
+#include "parser.h" // for CompileTimeValue; TODO(rossberg): should move
+#include "scopes.h"
+
+namespace v8 {
+namespace internal {
+
+
+AstTyper::AstTyper(CompilationInfo* info)
+ : info_(info),
+ oracle_(
+ Handle<Code>(info->closure()->shared()->code()),
+ Handle<Context>(info->closure()->context()->native_context()),
+ info->isolate(),
+ info->zone()) {
+ InitializeAstVisitor();
+}
+
+
+#define CHECK_ALIVE(call) \
+ do { \
+ call; \
+ if (visitor->HasStackOverflow()) return; \
+ } while (false)
+
+
+void AstTyper::Type(CompilationInfo* info) {
+ AstTyper* visitor = new(info->zone()) AstTyper(info);
+ Scope* scope = info->scope();
+
+ // Handle implicit declaration of the function name in named function
+ // expressions before other declarations.
+ if (scope->is_function_scope() && scope->function() != NULL) {
+ CHECK_ALIVE(visitor->VisitVariableDeclaration(scope->function()));
+ }
+ CHECK_ALIVE(visitor->VisitDeclarations(scope->declarations()));
+ CHECK_ALIVE(visitor->VisitStatements(info->function()->body()));
+}
+
+
+#undef CHECK_ALIVE
+#define CHECK_ALIVE(call) \
+ do { \
+ call; \
+ if (HasStackOverflow()) return; \
+ } while (false)
+
+
+void AstTyper::VisitStatements(ZoneList<Statement*>* stmts) {
+ ASSERT(!HasStackOverflow());
+ for (int i = 0; i < stmts->length(); ++i) {
+ Statement* stmt = stmts->at(i);
+ CHECK_ALIVE(Visit(stmt));
+ }
+}
+
+
+void AstTyper::VisitBlock(Block* stmt) {
+ ASSERT(!HasStackOverflow());
+ CHECK_ALIVE(VisitStatements(stmt->statements()));
+}
+
+
+void AstTyper::VisitExpressionStatement(ExpressionStatement* stmt) {
+ ASSERT(!HasStackOverflow());
+ CHECK_ALIVE(Visit(stmt->expression()));
+}
+
+
+void AstTyper::VisitEmptyStatement(EmptyStatement* stmt) {
+ ASSERT(!HasStackOverflow());
+}
+
+
+void AstTyper::VisitIfStatement(IfStatement* stmt) {
+ ASSERT(!HasStackOverflow());
+ CHECK_ALIVE(Visit(stmt->condition()));
+ CHECK_ALIVE(Visit(stmt->then_statement()));
+ CHECK_ALIVE(Visit(stmt->else_statement()));
+
+ if (!stmt->condition()->ToBooleanIsTrue() &&
+ !stmt->condition()->ToBooleanIsFalse()) {
+ stmt->condition()->RecordToBooleanTypeFeedback(oracle());
+ }
+}
+
+
+void AstTyper::VisitContinueStatement(ContinueStatement* stmt) {
+ ASSERT(!HasStackOverflow());
+}
+
+
+void AstTyper::VisitBreakStatement(BreakStatement* stmt) {
+ ASSERT(!HasStackOverflow());
+}
+
+
+void AstTyper::VisitReturnStatement(ReturnStatement* stmt) {
+ ASSERT(!HasStackOverflow());
+ CHECK_ALIVE(Visit(stmt->expression()));
+
+ // TODO(rossberg): we only need this for inlining into test contexts...
+ stmt->expression()->RecordToBooleanTypeFeedback(oracle());
+}
+
+
+void AstTyper::VisitWithStatement(WithStatement* stmt) {
+ ASSERT(!HasStackOverflow());
+ CHECK_ALIVE(stmt->expression());
+ CHECK_ALIVE(stmt->statement());
+}
+
+
+void AstTyper::VisitSwitchStatement(SwitchStatement* stmt) {
+ ASSERT(!HasStackOverflow());
+ CHECK_ALIVE(Visit(stmt->tag()));
+ ZoneList<CaseClause*>* clauses = stmt->cases();
+ SwitchStatement::SwitchType switch_type = stmt->switch_type();
+ for (int i = 0; i < clauses->length(); ++i) {
+ CaseClause* clause = clauses->at(i);
+ if (!clause->is_default()) {
+ Expression* label = clause->label();
+ CHECK_ALIVE(Visit(label));
+
+ SwitchStatement::SwitchType label_switch_type =
+ label->IsSmiLiteral() ? SwitchStatement::SMI_SWITCH :
+ label->IsStringLiteral() ? SwitchStatement::STRING_SWITCH :
+ SwitchStatement::GENERIC_SWITCH;
+ if (switch_type == SwitchStatement::UNKNOWN_SWITCH)
+ switch_type = label_switch_type;
+ else if (switch_type != label_switch_type)
+ switch_type = SwitchStatement::GENERIC_SWITCH;
+ }
+ CHECK_ALIVE(VisitStatements(clause->statements()));
+ }
+ if (switch_type == SwitchStatement::UNKNOWN_SWITCH)
+ switch_type = SwitchStatement::GENERIC_SWITCH;
+ stmt->set_switch_type(switch_type);
+
+ // TODO(rossberg): can we eliminate this special case and extra loop?
+ if (switch_type == SwitchStatement::SMI_SWITCH) {
+ for (int i = 0; i < clauses->length(); ++i) {
+ CaseClause* clause = clauses->at(i);
+ if (!clause->is_default())
+ clause->RecordTypeFeedback(oracle());
+ }
+ }
+}
+
+
+void AstTyper::VisitDoWhileStatement(DoWhileStatement* stmt) {
+ ASSERT(!HasStackOverflow());
+ CHECK_ALIVE(Visit(stmt->body()));
+ CHECK_ALIVE(Visit(stmt->cond()));
+
+ if (!stmt->cond()->ToBooleanIsTrue()) {
+ stmt->cond()->RecordToBooleanTypeFeedback(oracle());
+ }
+}
+
+
+void AstTyper::VisitWhileStatement(WhileStatement* stmt) {
+ ASSERT(!HasStackOverflow());
+ CHECK_ALIVE(Visit(stmt->cond()));
+ CHECK_ALIVE(Visit(stmt->body()));
+
+ if (!stmt->cond()->ToBooleanIsTrue()) {
+ stmt->cond()->RecordToBooleanTypeFeedback(oracle());
+ }
+}
+
+
+void AstTyper::VisitForStatement(ForStatement* stmt) {
+ ASSERT(!HasStackOverflow());
+ if (stmt->init() != NULL) {
+ CHECK_ALIVE(Visit(stmt->init()));
+ }
+ if (stmt->cond() != NULL) {
+ CHECK_ALIVE(Visit(stmt->cond()));
+
+ stmt->cond()->RecordToBooleanTypeFeedback(oracle());
+ }
+ CHECK_ALIVE(Visit(stmt->body()));
+ if (stmt->next() != NULL) {
+ CHECK_ALIVE(Visit(stmt->next()));
+ }
+}
+
+
+void AstTyper::VisitForInStatement(ForInStatement* stmt) {
+ ASSERT(!HasStackOverflow());
+ CHECK_ALIVE(Visit(stmt->enumerable()));
+ CHECK_ALIVE(Visit(stmt->body()));
+
+ stmt->RecordTypeFeedback(oracle());
+}
+
+
+void AstTyper::VisitTryCatchStatement(TryCatchStatement* stmt) {
+ ASSERT(!HasStackOverflow());
+ CHECK_ALIVE(Visit(stmt->try_block()));
+ CHECK_ALIVE(Visit(stmt->catch_block()));
+}
+
+
+void AstTyper::VisitTryFinallyStatement(TryFinallyStatement* stmt) {
+ ASSERT(!HasStackOverflow());
+ CHECK_ALIVE(Visit(stmt->try_block()));
+ CHECK_ALIVE(Visit(stmt->finally_block()));
+}
+
+
+void AstTyper::VisitDebuggerStatement(DebuggerStatement* stmt) {
+ ASSERT(!HasStackOverflow());
+}
+
+
+void AstTyper::VisitFunctionLiteral(FunctionLiteral* expr) {
+ ASSERT(!HasStackOverflow());
+}
+
+
+void AstTyper::VisitSharedFunctionInfoLiteral(SharedFunctionInfoLiteral* expr) {
+ ASSERT(!HasStackOverflow());
+}
+
+
+void AstTyper::VisitConditional(Conditional* expr) {
+ ASSERT(!HasStackOverflow());
+ CHECK_ALIVE(Visit(expr->condition()));
+ CHECK_ALIVE(Visit(expr->then_expression()));
+ CHECK_ALIVE(Visit(expr->else_expression()));
+
+ expr->condition()->RecordToBooleanTypeFeedback(oracle());
+}
+
+
+void AstTyper::VisitVariableProxy(VariableProxy* expr) {
+ ASSERT(!HasStackOverflow());
+}
+
+
+void AstTyper::VisitLiteral(Literal* expr) {
+ ASSERT(!HasStackOverflow());
+}
+
+
+void AstTyper::VisitRegExpLiteral(RegExpLiteral* expr) {
+ ASSERT(!HasStackOverflow());
+}
+
+
+void AstTyper::VisitObjectLiteral(ObjectLiteral* expr) {
+ ASSERT(!HasStackOverflow());
+ ZoneList<ObjectLiteral::Property*>* properties = expr->properties();
+ for (int i = 0; i < properties->length(); ++i) {
+ ObjectLiteral::Property* prop = properties->at(i);
+ CHECK_ALIVE(Visit(prop->value()));
+
+ if ((prop->kind() == ObjectLiteral::Property::MATERIALIZED_LITERAL &&
+ !CompileTimeValue::IsCompileTimeValue(prop->value())) ||
+ prop->kind() == ObjectLiteral::Property::COMPUTED) {
+ if (prop->key()->handle()->IsInternalizedString() && prop->emit_store())
+ prop->RecordTypeFeedback(oracle());
+ }
+ }
+}
+
+
+void AstTyper::VisitArrayLiteral(ArrayLiteral* expr) {
+ ASSERT(!HasStackOverflow());
+ ZoneList<Expression*>* values = expr->values();
+ for (int i = 0; i < values->length(); ++i) {
+ Expression* value = values->at(i);
+ CHECK_ALIVE(Visit(value));
+ }
+}
+
+
+void AstTyper::VisitAssignment(Assignment* expr) {
+ ASSERT(!HasStackOverflow());
+ CHECK_ALIVE(Visit(expr->target()));
+ CHECK_ALIVE(Visit(expr->value()));
+
+ // TODO(rossberg): Can we clean this up?
+ if (expr->is_compound()) {
+ CHECK_ALIVE(Visit(expr->binary_operation()));
+
+ Expression* target = expr->target();
+ Property* prop = target->AsProperty();
+ if (prop != NULL) {
+ prop->RecordTypeFeedback(oracle(), zone());
+ if (!prop->key()->IsPropertyName()) // i.e., keyed
+ expr->RecordTypeFeedback(oracle(), zone());
+ }
+ return;
+ }
+ if (expr->target()->AsProperty())
+ expr->RecordTypeFeedback(oracle(), zone());
+}
+
+
+void AstTyper::VisitYield(Yield* expr) {
+ ASSERT(!HasStackOverflow());
+ CHECK_ALIVE(Visit(expr->generator_object()));
+ CHECK_ALIVE(Visit(expr->expression()));
+}
+
+
+void AstTyper::VisitThrow(Throw* expr) {
+ ASSERT(!HasStackOverflow());
+ CHECK_ALIVE(Visit(expr->exception()));
+}
+
+
+void AstTyper::VisitProperty(Property* expr) {
+ ASSERT(!HasStackOverflow());
+ CHECK_ALIVE(Visit(expr->obj()));
+ CHECK_ALIVE(Visit(expr->key()));
+
+ expr->RecordTypeFeedback(oracle(), zone());
+}
+
+
+void AstTyper::VisitCall(Call* expr) {
+ ASSERT(!HasStackOverflow());
+ CHECK_ALIVE(Visit(expr->expression()));
+ ZoneList<Expression*>* args = expr->arguments();
+ for (int i = 0; i < args->length(); ++i) {
+ Expression* arg = args->at(i);
+ CHECK_ALIVE(Visit(arg));
+ }
+
+ Expression* callee = expr->expression();
+ Property* prop = callee->AsProperty();
+ if (prop != NULL) {
+ if (prop->key()->IsPropertyName())
+ expr->RecordTypeFeedback(oracle(), CALL_AS_METHOD);
+ } else {
+ expr->RecordTypeFeedback(oracle(), CALL_AS_FUNCTION);
+ }
+}
+
+
+void AstTyper::VisitCallNew(CallNew* expr) {
+ ASSERT(!HasStackOverflow());
+ CHECK_ALIVE(Visit(expr->expression()));
+ ZoneList<Expression*>* args = expr->arguments();
+ for (int i = 0; i < args->length(); ++i) {
+ Expression* arg = args->at(i);
+ CHECK_ALIVE(Visit(arg));
+ }
+
+ expr->RecordTypeFeedback(oracle());
+}
+
+
+void AstTyper::VisitCallRuntime(CallRuntime* expr) {
+ ASSERT(!HasStackOverflow());
+ ZoneList<Expression*>* args = expr->arguments();
+ for (int i = 0; i < args->length(); ++i) {
+ Expression* arg = args->at(i);
+ CHECK_ALIVE(Visit(arg));
+ }
+}
+
+
+void AstTyper::VisitUnaryOperation(UnaryOperation* expr) {
+ ASSERT(!HasStackOverflow());
+ CHECK_ALIVE(Visit(expr->expression()));
+
+ expr->RecordTypeFeedback(oracle());
+ if (expr->op() == Token::NOT) {
+ // TODO(rossberg): only do in test or value context.
+ expr->expression()->RecordToBooleanTypeFeedback(oracle());
+ }
+}
+
+
+void AstTyper::VisitCountOperation(CountOperation* expr) {
+ ASSERT(!HasStackOverflow());
+ CHECK_ALIVE(Visit(expr->expression()));
+
+ expr->RecordTypeFeedback(oracle(), zone());
+ Property* prop = expr->expression()->AsProperty();
+ if (prop != NULL) {
+ prop->RecordTypeFeedback(oracle(), zone());
+ }
+}
+
+
+void AstTyper::VisitBinaryOperation(BinaryOperation* expr) {
+ ASSERT(!HasStackOverflow());
+ CHECK_ALIVE(Visit(expr->left()));
+ CHECK_ALIVE(Visit(expr->right()));
+
+ expr->RecordTypeFeedback(oracle());
+ if (expr->op() == Token::OR || expr->op() == Token::AND) {
+ expr->left()->RecordToBooleanTypeFeedback(oracle());
+ }
+}
+
+
+void AstTyper::VisitCompareOperation(CompareOperation* expr) {
+ ASSERT(!HasStackOverflow());
+ CHECK_ALIVE(Visit(expr->left()));
+ CHECK_ALIVE(Visit(expr->right()));
+
+ expr->RecordTypeFeedback(oracle());
+}
+
+
+void AstTyper::VisitThisFunction(ThisFunction* expr) {
+ ASSERT(!HasStackOverflow());
+}
+
+
+void AstTyper::VisitDeclarations(ZoneList<Declaration*>* decls) {
+ ASSERT(!HasStackOverflow());
+ for (int i = 0; i < decls->length(); ++i) {
+ Declaration* decl = decls->at(i);
+ CHECK_ALIVE(Visit(decl));
+ }
+}
+
+
+void AstTyper::VisitVariableDeclaration(VariableDeclaration* declaration) {
+ ASSERT(!HasStackOverflow());
+}
+
+
+void AstTyper::VisitFunctionDeclaration(FunctionDeclaration* declaration) {
+ ASSERT(!HasStackOverflow());
+ CHECK_ALIVE(Visit(declaration->fun()));
+}
+
+
+void AstTyper::VisitModuleDeclaration(ModuleDeclaration* declaration) {
+ ASSERT(!HasStackOverflow());
+ CHECK_ALIVE(Visit(declaration->module()));
+}
+
+
+void AstTyper::VisitImportDeclaration(ImportDeclaration* declaration) {
+ ASSERT(!HasStackOverflow());
+ CHECK_ALIVE(Visit(declaration->module()));
+}
+
+
+void AstTyper::VisitExportDeclaration(ExportDeclaration* declaration) {
+ ASSERT(!HasStackOverflow());
+}
+
+
+void AstTyper::VisitModuleLiteral(ModuleLiteral* module) {
+ ASSERT(!HasStackOverflow());
+ CHECK_ALIVE(Visit(module->body()));
+}
+
+
+void AstTyper::VisitModuleVariable(ModuleVariable* module) {
+ ASSERT(!HasStackOverflow());
+}
+
+
+void AstTyper::VisitModulePath(ModulePath* module) {
+ ASSERT(!HasStackOverflow());
+ CHECK_ALIVE(Visit(module->module()));
+}
+
+
+void AstTyper::VisitModuleUrl(ModuleUrl* module) {
+ ASSERT(!HasStackOverflow());
+}
+
+
+void AstTyper::VisitModuleStatement(ModuleStatement* stmt) {
+ ASSERT(!HasStackOverflow());
+ CHECK_ALIVE(Visit(stmt->body()));
+}
+
+
+} } // namespace v8::internal
--- /dev/null
+// 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_
'../../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',