| Index: src/typing.cc
|
| diff --git a/src/typing.cc b/src/typing.cc
|
| deleted file mode 100644
|
| index 3193f7ad8e76af2b3646c5021657274620d8b07c..0000000000000000000000000000000000000000
|
| --- a/src/typing.cc
|
| +++ /dev/null
|
| @@ -1,815 +0,0 @@
|
| -// Copyright 2013 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.
|
| -
|
| -#include "src/typing.h"
|
| -
|
| -#include "src/frames.h"
|
| -#include "src/frames-inl.h"
|
| -#include "src/ostreams.h"
|
| -#include "src/parser.h" // for CompileTimeValue; TODO(rossberg): should move
|
| -#include "src/scopes.h"
|
| -#include "src/splay-tree-inl.h"
|
| -
|
| -namespace v8 {
|
| -namespace internal {
|
| -
|
| -
|
| -AstTyper::AstTyper(Isolate* isolate, Zone* zone, Handle<JSFunction> closure,
|
| - Scope* scope, BailoutId osr_ast_id, FunctionLiteral* root)
|
| - : isolate_(isolate),
|
| - zone_(zone),
|
| - closure_(closure),
|
| - scope_(scope),
|
| - osr_ast_id_(osr_ast_id),
|
| - root_(root),
|
| - oracle_(isolate, zone, handle(closure->shared()->code()),
|
| - handle(closure->shared()->feedback_vector()),
|
| - handle(closure->context()->native_context())),
|
| - store_(zone) {
|
| - InitializeAstVisitor(isolate);
|
| -}
|
| -
|
| -
|
| -#ifdef OBJECT_PRINT
|
| - static void PrintObserved(Variable* var, Object* value, Type* type) {
|
| - OFStream os(stdout);
|
| - os << " observed " << (var->IsParameter() ? "param" : "local") << " ";
|
| - var->name()->Print(os);
|
| - os << " : " << Brief(value) << " -> ";
|
| - type->PrintTo(os);
|
| - os << std::endl;
|
| - }
|
| -#endif // OBJECT_PRINT
|
| -
|
| -
|
| -Effect AstTyper::ObservedOnStack(Object* value) {
|
| - Type* lower = Type::NowOf(value, zone());
|
| - return Effect(Bounds(lower, Type::Any(zone())));
|
| -}
|
| -
|
| -
|
| -void AstTyper::ObserveTypesAtOsrEntry(IterationStatement* stmt) {
|
| - if (stmt->OsrEntryId() != osr_ast_id_) return;
|
| -
|
| - DisallowHeapAllocation no_gc;
|
| - JavaScriptFrameIterator it(isolate_);
|
| - JavaScriptFrame* frame = it.frame();
|
| -
|
| - // Assert that the frame on the stack belongs to the function we want to OSR.
|
| - DCHECK_EQ(*closure_, frame->function());
|
| -
|
| - int params = scope_->num_parameters();
|
| - int locals = scope_->StackLocalCount();
|
| -
|
| - // Use sequential composition to achieve desired narrowing.
|
| - // The receiver is a parameter with index -1.
|
| - store_.Seq(parameter_index(-1), ObservedOnStack(frame->receiver()));
|
| - for (int i = 0; i < params; i++) {
|
| - store_.Seq(parameter_index(i), ObservedOnStack(frame->GetParameter(i)));
|
| - }
|
| -
|
| - for (int i = 0; i < locals; i++) {
|
| - store_.Seq(stack_local_index(i), ObservedOnStack(frame->GetExpression(i)));
|
| - }
|
| -
|
| -#ifdef OBJECT_PRINT
|
| - if (FLAG_trace_osr && FLAG_print_scopes) {
|
| - PrintObserved(scope_->receiver(), frame->receiver(),
|
| - store_.LookupBounds(parameter_index(-1)).lower);
|
| -
|
| - for (int i = 0; i < params; i++) {
|
| - PrintObserved(scope_->parameter(i), frame->GetParameter(i),
|
| - store_.LookupBounds(parameter_index(i)).lower);
|
| - }
|
| -
|
| - ZoneList<Variable*> local_vars(locals, zone());
|
| - ZoneList<Variable*> context_vars(scope_->ContextLocalCount(), zone());
|
| - ZoneList<Variable*> global_vars(scope_->ContextGlobalCount(), zone());
|
| - scope_->CollectStackAndContextLocals(&local_vars, &context_vars,
|
| - &global_vars);
|
| - for (int i = 0; i < locals; i++) {
|
| - PrintObserved(local_vars.at(i),
|
| - frame->GetExpression(i),
|
| - store_.LookupBounds(stack_local_index(i)).lower);
|
| - }
|
| - }
|
| -#endif // OBJECT_PRINT
|
| -}
|
| -
|
| -
|
| -#define RECURSE(call) \
|
| - do { \
|
| - DCHECK(!HasStackOverflow()); \
|
| - call; \
|
| - if (HasStackOverflow()) return; \
|
| - } while (false)
|
| -
|
| -
|
| -void AstTyper::Run() {
|
| - RECURSE(VisitDeclarations(scope_->declarations()));
|
| - RECURSE(VisitStatements(root_->body()));
|
| -}
|
| -
|
| -
|
| -void AstTyper::VisitStatements(ZoneList<Statement*>* stmts) {
|
| - for (int i = 0; i < stmts->length(); ++i) {
|
| - Statement* stmt = stmts->at(i);
|
| - RECURSE(Visit(stmt));
|
| - if (stmt->IsJump()) break;
|
| - }
|
| -}
|
| -
|
| -
|
| -void AstTyper::VisitBlock(Block* stmt) {
|
| - RECURSE(VisitStatements(stmt->statements()));
|
| - if (stmt->labels() != NULL) {
|
| - store_.Forget(); // Control may transfer here via 'break l'.
|
| - }
|
| -}
|
| -
|
| -
|
| -void AstTyper::VisitExpressionStatement(ExpressionStatement* stmt) {
|
| - RECURSE(Visit(stmt->expression()));
|
| -}
|
| -
|
| -
|
| -void AstTyper::VisitEmptyStatement(EmptyStatement* stmt) {
|
| -}
|
| -
|
| -
|
| -void AstTyper::VisitSloppyBlockFunctionStatement(
|
| - SloppyBlockFunctionStatement* stmt) {
|
| - Visit(stmt->statement());
|
| -}
|
| -
|
| -
|
| -void AstTyper::VisitIfStatement(IfStatement* stmt) {
|
| - // Collect type feedback.
|
| - if (!stmt->condition()->ToBooleanIsTrue() &&
|
| - !stmt->condition()->ToBooleanIsFalse()) {
|
| - stmt->condition()->RecordToBooleanTypeFeedback(oracle());
|
| - }
|
| -
|
| - RECURSE(Visit(stmt->condition()));
|
| - Effects then_effects = EnterEffects();
|
| - RECURSE(Visit(stmt->then_statement()));
|
| - ExitEffects();
|
| - Effects else_effects = EnterEffects();
|
| - RECURSE(Visit(stmt->else_statement()));
|
| - ExitEffects();
|
| - then_effects.Alt(else_effects);
|
| - store_.Seq(then_effects);
|
| -}
|
| -
|
| -
|
| -void AstTyper::VisitContinueStatement(ContinueStatement* stmt) {
|
| - // TODO(rossberg): is it worth having a non-termination effect?
|
| -}
|
| -
|
| -
|
| -void AstTyper::VisitBreakStatement(BreakStatement* stmt) {
|
| - // TODO(rossberg): is it worth having a non-termination effect?
|
| -}
|
| -
|
| -
|
| -void AstTyper::VisitReturnStatement(ReturnStatement* stmt) {
|
| - // Collect type feedback.
|
| - // TODO(rossberg): we only need this for inlining into test contexts...
|
| - stmt->expression()->RecordToBooleanTypeFeedback(oracle());
|
| -
|
| - RECURSE(Visit(stmt->expression()));
|
| - // TODO(rossberg): is it worth having a non-termination effect?
|
| -}
|
| -
|
| -
|
| -void AstTyper::VisitWithStatement(WithStatement* stmt) {
|
| - RECURSE(stmt->expression());
|
| - RECURSE(stmt->statement());
|
| -}
|
| -
|
| -
|
| -void AstTyper::VisitSwitchStatement(SwitchStatement* stmt) {
|
| - RECURSE(Visit(stmt->tag()));
|
| -
|
| - ZoneList<CaseClause*>* clauses = stmt->cases();
|
| - Effects local_effects(zone());
|
| - bool complex_effects = false; // True for label effects or fall-through.
|
| -
|
| - for (int i = 0; i < clauses->length(); ++i) {
|
| - CaseClause* clause = clauses->at(i);
|
| -
|
| - Effects clause_effects = EnterEffects();
|
| -
|
| - if (!clause->is_default()) {
|
| - Expression* label = clause->label();
|
| - // Collect type feedback.
|
| - Type* tag_type;
|
| - Type* label_type;
|
| - Type* combined_type;
|
| - oracle()->CompareType(clause->CompareId(),
|
| - &tag_type, &label_type, &combined_type);
|
| - NarrowLowerType(stmt->tag(), tag_type);
|
| - NarrowLowerType(label, label_type);
|
| - clause->set_compare_type(combined_type);
|
| -
|
| - RECURSE(Visit(label));
|
| - if (!clause_effects.IsEmpty()) complex_effects = true;
|
| - }
|
| -
|
| - ZoneList<Statement*>* stmts = clause->statements();
|
| - RECURSE(VisitStatements(stmts));
|
| - ExitEffects();
|
| - if (stmts->is_empty() || stmts->last()->IsJump()) {
|
| - local_effects.Alt(clause_effects);
|
| - } else {
|
| - complex_effects = true;
|
| - }
|
| - }
|
| -
|
| - if (complex_effects) {
|
| - store_.Forget(); // Reached this in unknown state.
|
| - } else {
|
| - store_.Seq(local_effects);
|
| - }
|
| -}
|
| -
|
| -
|
| -void AstTyper::VisitCaseClause(CaseClause* clause) {
|
| - UNREACHABLE();
|
| -}
|
| -
|
| -
|
| -void AstTyper::VisitDoWhileStatement(DoWhileStatement* stmt) {
|
| - // Collect type feedback.
|
| - if (!stmt->cond()->ToBooleanIsTrue()) {
|
| - stmt->cond()->RecordToBooleanTypeFeedback(oracle());
|
| - }
|
| -
|
| - // TODO(rossberg): refine the unconditional Forget (here and elsewhere) by
|
| - // computing the set of variables assigned in only some of the origins of the
|
| - // control transfer (such as the loop body here).
|
| - store_.Forget(); // Control may transfer here via looping or 'continue'.
|
| - ObserveTypesAtOsrEntry(stmt);
|
| - RECURSE(Visit(stmt->body()));
|
| - RECURSE(Visit(stmt->cond()));
|
| - store_.Forget(); // Control may transfer here via 'break'.
|
| -}
|
| -
|
| -
|
| -void AstTyper::VisitWhileStatement(WhileStatement* stmt) {
|
| - // Collect type feedback.
|
| - if (!stmt->cond()->ToBooleanIsTrue()) {
|
| - stmt->cond()->RecordToBooleanTypeFeedback(oracle());
|
| - }
|
| -
|
| - store_.Forget(); // Control may transfer here via looping or 'continue'.
|
| - RECURSE(Visit(stmt->cond()));
|
| - ObserveTypesAtOsrEntry(stmt);
|
| - RECURSE(Visit(stmt->body()));
|
| - store_.Forget(); // Control may transfer here via termination or 'break'.
|
| -}
|
| -
|
| -
|
| -void AstTyper::VisitForStatement(ForStatement* stmt) {
|
| - if (stmt->init() != NULL) {
|
| - RECURSE(Visit(stmt->init()));
|
| - }
|
| - store_.Forget(); // Control may transfer here via looping.
|
| - if (stmt->cond() != NULL) {
|
| - // Collect type feedback.
|
| - stmt->cond()->RecordToBooleanTypeFeedback(oracle());
|
| -
|
| - RECURSE(Visit(stmt->cond()));
|
| - }
|
| - ObserveTypesAtOsrEntry(stmt);
|
| - RECURSE(Visit(stmt->body()));
|
| - if (stmt->next() != NULL) {
|
| - store_.Forget(); // Control may transfer here via 'continue'.
|
| - RECURSE(Visit(stmt->next()));
|
| - }
|
| - store_.Forget(); // Control may transfer here via termination or 'break'.
|
| -}
|
| -
|
| -
|
| -void AstTyper::VisitForInStatement(ForInStatement* stmt) {
|
| - // Collect type feedback.
|
| - stmt->set_for_in_type(static_cast<ForInStatement::ForInType>(
|
| - oracle()->ForInType(stmt->ForInFeedbackSlot())));
|
| -
|
| - RECURSE(Visit(stmt->enumerable()));
|
| - store_.Forget(); // Control may transfer here via looping or 'continue'.
|
| - ObserveTypesAtOsrEntry(stmt);
|
| - RECURSE(Visit(stmt->body()));
|
| - store_.Forget(); // Control may transfer here via 'break'.
|
| -}
|
| -
|
| -
|
| -void AstTyper::VisitForOfStatement(ForOfStatement* stmt) {
|
| - RECURSE(Visit(stmt->iterable()));
|
| - store_.Forget(); // Control may transfer here via looping or 'continue'.
|
| - RECURSE(Visit(stmt->body()));
|
| - store_.Forget(); // Control may transfer here via 'break'.
|
| -}
|
| -
|
| -
|
| -void AstTyper::VisitTryCatchStatement(TryCatchStatement* stmt) {
|
| - Effects try_effects = EnterEffects();
|
| - RECURSE(Visit(stmt->try_block()));
|
| - ExitEffects();
|
| - Effects catch_effects = EnterEffects();
|
| - store_.Forget(); // Control may transfer here via 'throw'.
|
| - RECURSE(Visit(stmt->catch_block()));
|
| - ExitEffects();
|
| - try_effects.Alt(catch_effects);
|
| - store_.Seq(try_effects);
|
| - // At this point, only variables that were reassigned in the catch block are
|
| - // still remembered.
|
| -}
|
| -
|
| -
|
| -void AstTyper::VisitTryFinallyStatement(TryFinallyStatement* stmt) {
|
| - RECURSE(Visit(stmt->try_block()));
|
| - store_.Forget(); // Control may transfer here via 'throw'.
|
| - RECURSE(Visit(stmt->finally_block()));
|
| -}
|
| -
|
| -
|
| -void AstTyper::VisitDebuggerStatement(DebuggerStatement* stmt) {
|
| - store_.Forget(); // May do whatever.
|
| -}
|
| -
|
| -
|
| -void AstTyper::VisitFunctionLiteral(FunctionLiteral* expr) {}
|
| -
|
| -
|
| -void AstTyper::VisitClassLiteral(ClassLiteral* expr) {}
|
| -
|
| -
|
| -void AstTyper::VisitNativeFunctionLiteral(NativeFunctionLiteral* expr) {
|
| -}
|
| -
|
| -
|
| -void AstTyper::VisitConditional(Conditional* expr) {
|
| - // Collect type feedback.
|
| - expr->condition()->RecordToBooleanTypeFeedback(oracle());
|
| -
|
| - RECURSE(Visit(expr->condition()));
|
| - Effects then_effects = EnterEffects();
|
| - RECURSE(Visit(expr->then_expression()));
|
| - ExitEffects();
|
| - Effects else_effects = EnterEffects();
|
| - RECURSE(Visit(expr->else_expression()));
|
| - ExitEffects();
|
| - then_effects.Alt(else_effects);
|
| - store_.Seq(then_effects);
|
| -
|
| - NarrowType(expr, Bounds::Either(
|
| - expr->then_expression()->bounds(),
|
| - expr->else_expression()->bounds(), zone()));
|
| -}
|
| -
|
| -
|
| -void AstTyper::VisitVariableProxy(VariableProxy* expr) {
|
| - Variable* var = expr->var();
|
| - if (var->IsStackAllocated()) {
|
| - NarrowType(expr, store_.LookupBounds(variable_index(var)));
|
| - }
|
| -}
|
| -
|
| -
|
| -void AstTyper::VisitLiteral(Literal* expr) {
|
| - Type* type = Type::Constant(expr->value(), zone());
|
| - NarrowType(expr, Bounds(type));
|
| -}
|
| -
|
| -
|
| -void AstTyper::VisitRegExpLiteral(RegExpLiteral* expr) {
|
| - // TODO(rossberg): Reintroduce RegExp type.
|
| - NarrowType(expr, Bounds(Type::Object(zone())));
|
| -}
|
| -
|
| -
|
| -void AstTyper::VisitObjectLiteral(ObjectLiteral* expr) {
|
| - ZoneList<ObjectLiteral::Property*>* properties = expr->properties();
|
| - for (int i = 0; i < properties->length(); ++i) {
|
| - ObjectLiteral::Property* prop = properties->at(i);
|
| -
|
| - // Collect type feedback.
|
| - if ((prop->kind() == ObjectLiteral::Property::MATERIALIZED_LITERAL &&
|
| - !CompileTimeValue::IsCompileTimeValue(prop->value())) ||
|
| - prop->kind() == ObjectLiteral::Property::COMPUTED) {
|
| - if (!prop->is_computed_name() &&
|
| - prop->key()->AsLiteral()->value()->IsInternalizedString() &&
|
| - prop->emit_store()) {
|
| - // Record type feed back for the property.
|
| - TypeFeedbackId id = prop->key()->AsLiteral()->LiteralFeedbackId();
|
| - FeedbackVectorSlot slot = prop->GetSlot();
|
| - SmallMapList maps;
|
| - if (FLAG_vector_stores) {
|
| - oracle()->CollectReceiverTypes(slot, &maps);
|
| - } else {
|
| - oracle()->CollectReceiverTypes(id, &maps);
|
| - }
|
| - prop->set_receiver_type(maps.length() == 1 ? maps.at(0)
|
| - : Handle<Map>::null());
|
| - }
|
| - }
|
| -
|
| - RECURSE(Visit(prop->value()));
|
| - }
|
| -
|
| - NarrowType(expr, Bounds(Type::Object(zone())));
|
| -}
|
| -
|
| -
|
| -void AstTyper::VisitArrayLiteral(ArrayLiteral* expr) {
|
| - ZoneList<Expression*>* values = expr->values();
|
| - for (int i = 0; i < values->length(); ++i) {
|
| - Expression* value = values->at(i);
|
| - RECURSE(Visit(value));
|
| - }
|
| -
|
| - NarrowType(expr, Bounds(Type::Object(zone())));
|
| -}
|
| -
|
| -
|
| -void AstTyper::VisitAssignment(Assignment* expr) {
|
| - // Collect type feedback.
|
| - Property* prop = expr->target()->AsProperty();
|
| - if (prop != NULL) {
|
| - TypeFeedbackId id = expr->AssignmentFeedbackId();
|
| - FeedbackVectorSlot slot = expr->AssignmentSlot();
|
| - expr->set_is_uninitialized(FLAG_vector_stores
|
| - ? oracle()->StoreIsUninitialized(slot)
|
| - : oracle()->StoreIsUninitialized(id));
|
| - if (!expr->IsUninitialized()) {
|
| - SmallMapList* receiver_types = expr->GetReceiverTypes();
|
| - if (prop->key()->IsPropertyName()) {
|
| - Literal* lit_key = prop->key()->AsLiteral();
|
| - DCHECK(lit_key != NULL && lit_key->value()->IsString());
|
| - Handle<String> name = Handle<String>::cast(lit_key->value());
|
| - if (FLAG_vector_stores) {
|
| - oracle()->AssignmentReceiverTypes(slot, name, receiver_types);
|
| - } else {
|
| - oracle()->AssignmentReceiverTypes(id, name, receiver_types);
|
| - }
|
| - } else {
|
| - KeyedAccessStoreMode store_mode;
|
| - IcCheckType key_type;
|
| - if (FLAG_vector_stores) {
|
| - oracle()->KeyedAssignmentReceiverTypes(slot, receiver_types,
|
| - &store_mode, &key_type);
|
| - } else {
|
| - oracle()->KeyedAssignmentReceiverTypes(id, receiver_types,
|
| - &store_mode, &key_type);
|
| - }
|
| - expr->set_store_mode(store_mode);
|
| - expr->set_key_type(key_type);
|
| - }
|
| - }
|
| - }
|
| -
|
| - Expression* rhs =
|
| - expr->is_compound() ? expr->binary_operation() : expr->value();
|
| - RECURSE(Visit(expr->target()));
|
| - RECURSE(Visit(rhs));
|
| - NarrowType(expr, rhs->bounds());
|
| -
|
| - VariableProxy* proxy = expr->target()->AsVariableProxy();
|
| - if (proxy != NULL && proxy->var()->IsStackAllocated()) {
|
| - store_.Seq(variable_index(proxy->var()), Effect(expr->bounds()));
|
| - }
|
| -}
|
| -
|
| -
|
| -void AstTyper::VisitYield(Yield* expr) {
|
| - RECURSE(Visit(expr->generator_object()));
|
| - RECURSE(Visit(expr->expression()));
|
| -
|
| - // We don't know anything about the result type.
|
| -}
|
| -
|
| -
|
| -void AstTyper::VisitThrow(Throw* expr) {
|
| - RECURSE(Visit(expr->exception()));
|
| - // TODO(rossberg): is it worth having a non-termination effect?
|
| -
|
| - NarrowType(expr, Bounds(Type::None(zone())));
|
| -}
|
| -
|
| -
|
| -void AstTyper::VisitProperty(Property* expr) {
|
| - // Collect type feedback.
|
| - FeedbackVectorSlot slot = expr->PropertyFeedbackSlot();
|
| - expr->set_inline_cache_state(oracle()->LoadInlineCacheState(slot));
|
| -
|
| - if (!expr->IsUninitialized()) {
|
| - if (expr->key()->IsPropertyName()) {
|
| - Literal* lit_key = expr->key()->AsLiteral();
|
| - DCHECK(lit_key != NULL && lit_key->value()->IsString());
|
| - Handle<String> name = Handle<String>::cast(lit_key->value());
|
| - oracle()->PropertyReceiverTypes(slot, name, expr->GetReceiverTypes());
|
| - } else {
|
| - bool is_string;
|
| - IcCheckType key_type;
|
| - oracle()->KeyedPropertyReceiverTypes(slot, expr->GetReceiverTypes(),
|
| - &is_string, &key_type);
|
| - expr->set_is_string_access(is_string);
|
| - expr->set_key_type(key_type);
|
| - }
|
| - }
|
| -
|
| - RECURSE(Visit(expr->obj()));
|
| - RECURSE(Visit(expr->key()));
|
| -
|
| - // We don't know anything about the result type.
|
| -}
|
| -
|
| -
|
| -void AstTyper::VisitCall(Call* expr) {
|
| - // Collect type feedback.
|
| - RECURSE(Visit(expr->expression()));
|
| - bool is_uninitialized = true;
|
| - if (expr->IsUsingCallFeedbackICSlot(isolate_)) {
|
| - FeedbackVectorSlot slot = expr->CallFeedbackICSlot();
|
| - is_uninitialized = oracle()->CallIsUninitialized(slot);
|
| - if (!expr->expression()->IsProperty() &&
|
| - oracle()->CallIsMonomorphic(slot)) {
|
| - expr->set_target(oracle()->GetCallTarget(slot));
|
| - Handle<AllocationSite> site = oracle()->GetCallAllocationSite(slot);
|
| - expr->set_allocation_site(site);
|
| - }
|
| - }
|
| -
|
| - expr->set_is_uninitialized(is_uninitialized);
|
| -
|
| - ZoneList<Expression*>* args = expr->arguments();
|
| - for (int i = 0; i < args->length(); ++i) {
|
| - Expression* arg = args->at(i);
|
| - RECURSE(Visit(arg));
|
| - }
|
| -
|
| - VariableProxy* proxy = expr->expression()->AsVariableProxy();
|
| - if (proxy != NULL && proxy->var()->is_possibly_eval(isolate_)) {
|
| - store_.Forget(); // Eval could do whatever to local variables.
|
| - }
|
| -
|
| - // We don't know anything about the result type.
|
| -}
|
| -
|
| -
|
| -void AstTyper::VisitCallNew(CallNew* expr) {
|
| - // Collect type feedback.
|
| - FeedbackVectorSlot allocation_site_feedback_slot =
|
| - expr->CallNewFeedbackSlot();
|
| - expr->set_allocation_site(
|
| - oracle()->GetCallNewAllocationSite(allocation_site_feedback_slot));
|
| - bool monomorphic =
|
| - oracle()->CallNewIsMonomorphic(expr->CallNewFeedbackSlot());
|
| - expr->set_is_monomorphic(monomorphic);
|
| - if (monomorphic) {
|
| - expr->set_target(oracle()->GetCallNewTarget(expr->CallNewFeedbackSlot()));
|
| - }
|
| -
|
| - RECURSE(Visit(expr->expression()));
|
| - ZoneList<Expression*>* args = expr->arguments();
|
| - for (int i = 0; i < args->length(); ++i) {
|
| - Expression* arg = args->at(i);
|
| - RECURSE(Visit(arg));
|
| - }
|
| -
|
| - NarrowType(expr, Bounds(Type::None(zone()), Type::Receiver(zone())));
|
| -}
|
| -
|
| -
|
| -void AstTyper::VisitCallRuntime(CallRuntime* expr) {
|
| - ZoneList<Expression*>* args = expr->arguments();
|
| - for (int i = 0; i < args->length(); ++i) {
|
| - Expression* arg = args->at(i);
|
| - RECURSE(Visit(arg));
|
| - }
|
| -
|
| - // We don't know anything about the result type.
|
| -}
|
| -
|
| -
|
| -void AstTyper::VisitUnaryOperation(UnaryOperation* expr) {
|
| - // Collect type feedback.
|
| - if (expr->op() == Token::NOT) {
|
| - // TODO(rossberg): only do in test or value context.
|
| - expr->expression()->RecordToBooleanTypeFeedback(oracle());
|
| - }
|
| -
|
| - RECURSE(Visit(expr->expression()));
|
| -
|
| - switch (expr->op()) {
|
| - case Token::NOT:
|
| - case Token::DELETE:
|
| - NarrowType(expr, Bounds(Type::Boolean(zone())));
|
| - break;
|
| - case Token::VOID:
|
| - NarrowType(expr, Bounds(Type::Undefined(zone())));
|
| - break;
|
| - case Token::TYPEOF:
|
| - NarrowType(expr, Bounds(Type::InternalizedString(zone())));
|
| - break;
|
| - default:
|
| - UNREACHABLE();
|
| - }
|
| -}
|
| -
|
| -
|
| -void AstTyper::VisitCountOperation(CountOperation* expr) {
|
| - // Collect type feedback.
|
| - TypeFeedbackId store_id = expr->CountStoreFeedbackId();
|
| - FeedbackVectorSlot slot = expr->CountSlot();
|
| - KeyedAccessStoreMode store_mode;
|
| - IcCheckType key_type;
|
| - if (FLAG_vector_stores) {
|
| - oracle()->GetStoreModeAndKeyType(slot, &store_mode, &key_type);
|
| - oracle()->CountReceiverTypes(slot, expr->GetReceiverTypes());
|
| - } else {
|
| - oracle()->GetStoreModeAndKeyType(store_id, &store_mode, &key_type);
|
| - oracle()->CountReceiverTypes(store_id, expr->GetReceiverTypes());
|
| - }
|
| - expr->set_store_mode(store_mode);
|
| - expr->set_key_type(key_type);
|
| - expr->set_type(oracle()->CountType(expr->CountBinOpFeedbackId()));
|
| - // TODO(rossberg): merge the count type with the generic expression type.
|
| -
|
| - RECURSE(Visit(expr->expression()));
|
| -
|
| - NarrowType(expr, Bounds(Type::SignedSmall(zone()), Type::Number(zone())));
|
| -
|
| - VariableProxy* proxy = expr->expression()->AsVariableProxy();
|
| - if (proxy != NULL && proxy->var()->IsStackAllocated()) {
|
| - store_.Seq(variable_index(proxy->var()), Effect(expr->bounds()));
|
| - }
|
| -}
|
| -
|
| -
|
| -void AstTyper::VisitBinaryOperation(BinaryOperation* expr) {
|
| - // Collect type feedback.
|
| - Type* type;
|
| - Type* left_type;
|
| - Type* right_type;
|
| - Maybe<int> fixed_right_arg = Nothing<int>();
|
| - Handle<AllocationSite> allocation_site;
|
| - oracle()->BinaryType(expr->BinaryOperationFeedbackId(),
|
| - &left_type, &right_type, &type, &fixed_right_arg,
|
| - &allocation_site, expr->op());
|
| - NarrowLowerType(expr, type);
|
| - NarrowLowerType(expr->left(), left_type);
|
| - NarrowLowerType(expr->right(), right_type);
|
| - expr->set_allocation_site(allocation_site);
|
| - expr->set_fixed_right_arg(fixed_right_arg);
|
| - if (expr->op() == Token::OR || expr->op() == Token::AND) {
|
| - expr->left()->RecordToBooleanTypeFeedback(oracle());
|
| - }
|
| -
|
| - switch (expr->op()) {
|
| - case Token::COMMA:
|
| - RECURSE(Visit(expr->left()));
|
| - RECURSE(Visit(expr->right()));
|
| - NarrowType(expr, expr->right()->bounds());
|
| - break;
|
| - case Token::OR:
|
| - case Token::AND: {
|
| - Effects left_effects = EnterEffects();
|
| - RECURSE(Visit(expr->left()));
|
| - ExitEffects();
|
| - Effects right_effects = EnterEffects();
|
| - RECURSE(Visit(expr->right()));
|
| - ExitEffects();
|
| - left_effects.Alt(right_effects);
|
| - store_.Seq(left_effects);
|
| -
|
| - NarrowType(expr, Bounds::Either(
|
| - expr->left()->bounds(), expr->right()->bounds(), zone()));
|
| - break;
|
| - }
|
| - case Token::BIT_OR:
|
| - case Token::BIT_AND: {
|
| - RECURSE(Visit(expr->left()));
|
| - RECURSE(Visit(expr->right()));
|
| - Type* upper = Type::Union(
|
| - expr->left()->bounds().upper, expr->right()->bounds().upper, zone());
|
| - if (!upper->Is(Type::Signed32())) upper = Type::Signed32(zone());
|
| - Type* lower = Type::Intersect(Type::SignedSmall(zone()), upper, zone());
|
| - NarrowType(expr, Bounds(lower, upper));
|
| - break;
|
| - }
|
| - case Token::BIT_XOR:
|
| - case Token::SHL:
|
| - case Token::SAR:
|
| - RECURSE(Visit(expr->left()));
|
| - RECURSE(Visit(expr->right()));
|
| - NarrowType(expr,
|
| - Bounds(Type::SignedSmall(zone()), Type::Signed32(zone())));
|
| - break;
|
| - case Token::SHR:
|
| - RECURSE(Visit(expr->left()));
|
| - RECURSE(Visit(expr->right()));
|
| - // TODO(rossberg): The upper bound would be Unsigned32, but since there
|
| - // is no 'positive Smi' type for the lower bound, we use the smallest
|
| - // union of Smi and Unsigned32 as upper bound instead.
|
| - NarrowType(expr, Bounds(Type::SignedSmall(zone()), Type::Number(zone())));
|
| - break;
|
| - case Token::ADD: {
|
| - RECURSE(Visit(expr->left()));
|
| - RECURSE(Visit(expr->right()));
|
| - Bounds l = expr->left()->bounds();
|
| - Bounds r = expr->right()->bounds();
|
| - Type* lower =
|
| - !l.lower->IsInhabited() || !r.lower->IsInhabited() ?
|
| - Type::None(zone()) :
|
| - l.lower->Is(Type::String()) || r.lower->Is(Type::String()) ?
|
| - Type::String(zone()) :
|
| - l.lower->Is(Type::Number()) && r.lower->Is(Type::Number()) ?
|
| - Type::SignedSmall(zone()) : Type::None(zone());
|
| - Type* upper =
|
| - l.upper->Is(Type::String()) || r.upper->Is(Type::String()) ?
|
| - Type::String(zone()) :
|
| - l.upper->Is(Type::Number()) && r.upper->Is(Type::Number()) ?
|
| - Type::Number(zone()) : Type::NumberOrString(zone());
|
| - NarrowType(expr, Bounds(lower, upper));
|
| - break;
|
| - }
|
| - case Token::SUB:
|
| - case Token::MUL:
|
| - case Token::DIV:
|
| - case Token::MOD:
|
| - RECURSE(Visit(expr->left()));
|
| - RECURSE(Visit(expr->right()));
|
| - NarrowType(expr, Bounds(Type::SignedSmall(zone()), Type::Number(zone())));
|
| - break;
|
| - default:
|
| - UNREACHABLE();
|
| - }
|
| -}
|
| -
|
| -
|
| -void AstTyper::VisitCompareOperation(CompareOperation* expr) {
|
| - // Collect type feedback.
|
| - Type* left_type;
|
| - Type* right_type;
|
| - Type* combined_type;
|
| - oracle()->CompareType(expr->CompareOperationFeedbackId(),
|
| - &left_type, &right_type, &combined_type);
|
| - NarrowLowerType(expr->left(), left_type);
|
| - NarrowLowerType(expr->right(), right_type);
|
| - expr->set_combined_type(combined_type);
|
| -
|
| - RECURSE(Visit(expr->left()));
|
| - RECURSE(Visit(expr->right()));
|
| -
|
| - NarrowType(expr, Bounds(Type::Boolean(zone())));
|
| -}
|
| -
|
| -
|
| -void AstTyper::VisitSpread(Spread* expr) { RECURSE(Visit(expr->expression())); }
|
| -
|
| -
|
| -void AstTyper::VisitEmptyParentheses(EmptyParentheses* expr) {
|
| - UNREACHABLE();
|
| -}
|
| -
|
| -
|
| -void AstTyper::VisitThisFunction(ThisFunction* expr) {
|
| -}
|
| -
|
| -
|
| -void AstTyper::VisitSuperPropertyReference(SuperPropertyReference* expr) {}
|
| -
|
| -
|
| -void AstTyper::VisitSuperCallReference(SuperCallReference* expr) {}
|
| -
|
| -
|
| -void AstTyper::VisitDeclarations(ZoneList<Declaration*>* decls) {
|
| - for (int i = 0; i < decls->length(); ++i) {
|
| - Declaration* decl = decls->at(i);
|
| - RECURSE(Visit(decl));
|
| - }
|
| -}
|
| -
|
| -
|
| -void AstTyper::VisitVariableDeclaration(VariableDeclaration* declaration) {
|
| -}
|
| -
|
| -
|
| -void AstTyper::VisitFunctionDeclaration(FunctionDeclaration* declaration) {
|
| - RECURSE(Visit(declaration->fun()));
|
| -}
|
| -
|
| -
|
| -void AstTyper::VisitImportDeclaration(ImportDeclaration* declaration) {
|
| -}
|
| -
|
| -
|
| -void AstTyper::VisitExportDeclaration(ExportDeclaration* declaration) {
|
| -}
|
| -
|
| -
|
| -} // namespace internal
|
| -} // namespace v8
|
|
|