diff options
Diffstat (limited to 'deps/v8/src/typing.cc')
-rw-r--r-- | deps/v8/src/typing.cc | 240 |
1 files changed, 179 insertions, 61 deletions
diff --git a/deps/v8/src/typing.cc b/deps/v8/src/typing.cc index 727c104ab5..f8e2a7c206 100644 --- a/deps/v8/src/typing.cc +++ b/deps/v8/src/typing.cc @@ -40,7 +40,8 @@ AstTyper::AstTyper(CompilationInfo* info) Handle<Code>(info->closure()->shared()->code()), Handle<Context>(info->closure()->context()->native_context()), info->isolate(), - info->zone()) { + info->zone()), + store_(info->zone()) { InitializeAstVisitor(); } @@ -79,12 +80,16 @@ 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'. + } } @@ -98,30 +103,41 @@ void AstTyper::VisitEmptyStatement(EmptyStatement* stmt) { void AstTyper::VisitIfStatement(IfStatement* stmt) { - RECURSE(Visit(stmt->condition())); - RECURSE(Visit(stmt->then_statement())); - RECURSE(Visit(stmt->else_statement())); - + // 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) { - RECURSE(Visit(stmt->expression())); - + // 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? } @@ -133,14 +149,18 @@ void AstTyper::VisitWithStatement(WithStatement* stmt) { void AstTyper::VisitSwitchStatement(SwitchStatement* stmt) { RECURSE(Visit(stmt->tag())); + ZoneList<CaseClause*>* clauses = stmt->cases(); SwitchStatement::SwitchType switch_type = stmt->switch_type(); + 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(); - RECURSE(Visit(label)); - SwitchStatement::SwitchType label_switch_type = label->IsSmiLiteral() ? SwitchStatement::SMI_SWITCH : label->IsStringLiteral() ? SwitchStatement::STRING_SWITCH : @@ -149,13 +169,32 @@ void AstTyper::VisitSwitchStatement(SwitchStatement* stmt) { switch_type = label_switch_type; else if (switch_type != label_switch_type) switch_type = SwitchStatement::GENERIC_SWITCH; + + 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; } - RECURSE(VisitStatements(clause->statements())); } + + if (complex_effects) { + store_.Forget(); // Reached this in unknown state. + } else { + store_.Seq(local_effects); + } + if (switch_type == SwitchStatement::UNKNOWN_SWITCH) switch_type = SwitchStatement::GENERIC_SWITCH; stmt->set_switch_type(switch_type); + // Collect type feedback. // 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) { @@ -168,22 +207,31 @@ void AstTyper::VisitSwitchStatement(SwitchStatement* stmt) { void AstTyper::VisitDoWhileStatement(DoWhileStatement* stmt) { - RECURSE(Visit(stmt->body())); - RECURSE(Visit(stmt->cond())); - + // 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'. + RECURSE(Visit(stmt->body())); + RECURSE(Visit(stmt->cond())); + store_.Forget(); // Control may transfer here via 'break'. } void AstTyper::VisitWhileStatement(WhileStatement* stmt) { - RECURSE(Visit(stmt->cond())); - RECURSE(Visit(stmt->body())); - + // 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())); + RECURSE(Visit(stmt->body())); + store_.Forget(); // Control may transfer here via termination or 'break'. } @@ -191,45 +239,65 @@ 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) { - RECURSE(Visit(stmt->cond())); - + // Collect type feedback. stmt->cond()->RecordToBooleanTypeFeedback(oracle()); + + RECURSE(Visit(stmt->cond())); } RECURSE(Visit(stmt->body())); + store_.Forget(); // Control may transfer here via 'continue'. if (stmt->next() != NULL) { RECURSE(Visit(stmt->next())); } + store_.Forget(); // Control may transfer here via termination or 'break'. } void AstTyper::VisitForInStatement(ForInStatement* stmt) { + // Collect type feedback. + stmt->RecordTypeFeedback(oracle()); + RECURSE(Visit(stmt->enumerable())); + store_.Forget(); // Control may transfer here via looping or 'continue'. RECURSE(Visit(stmt->body())); - - stmt->RecordTypeFeedback(oracle()); + 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. } @@ -242,11 +310,18 @@ void AstTyper::VisitSharedFunctionInfoLiteral(SharedFunctionInfoLiteral* 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())); - - expr->condition()->RecordToBooleanTypeFeedback(oracle()); + ExitEffects(); + then_effects.Alt(else_effects); + store_.Seq(then_effects); NarrowType(expr, Bounds::Either( expr->then_expression()->bounds(), @@ -255,7 +330,10 @@ void AstTyper::VisitConditional(Conditional* expr) { void AstTyper::VisitVariableProxy(VariableProxy* expr) { - // TODO(rossberg): typing of variables + Variable* var = expr->var(); + if (var->IsStackAllocated()) { + NarrowType(expr, store_.LookupBounds(variable_index(var))); + } } @@ -274,8 +352,8 @@ 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); - RECURSE(Visit(prop->value())); + // Collect type feedback. if ((prop->kind() == ObjectLiteral::Property::MATERIALIZED_LITERAL && !CompileTimeValue::IsCompileTimeValue(prop->value())) || prop->kind() == ObjectLiteral::Property::COMPUTED) { @@ -283,6 +361,8 @@ void AstTyper::VisitObjectLiteral(ObjectLiteral* expr) { prop->RecordTypeFeedback(oracle()); } } + + RECURSE(Visit(prop->value())); } NarrowType(expr, Bounds(Type::Object(), isolate_)); @@ -303,29 +383,33 @@ void AstTyper::VisitArrayLiteral(ArrayLiteral* expr) { void AstTyper::VisitAssignment(Assignment* expr) { // TODO(rossberg): Can we clean this up? if (expr->is_compound()) { - RECURSE(Visit(expr->binary_operation())); - + // Collect type feedback. 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()); - } + expr->RecordTypeFeedback(oracle(), zone()); } + RECURSE(Visit(expr->binary_operation())); + NarrowType(expr, expr->binary_operation()->bounds()); } else { - RECURSE(Visit(expr->target())); - RECURSE(Visit(expr->value())); - - if (expr->target()->AsProperty()) { + // Collect type feedback. + if (expr->target()->IsProperty()) { expr->RecordTypeFeedback(oracle(), zone()); } + RECURSE(Visit(expr->target())); + RECURSE(Visit(expr->value())); + NarrowType(expr, expr->value()->bounds()); } - // TODO(rossberg): handle target variables + + VariableProxy* proxy = expr->target()->AsVariableProxy(); + if (proxy != NULL && proxy->var()->IsStackAllocated()) { + store_.Seq(variable_index(proxy->var()), Effect(expr->bounds())); + } } @@ -333,35 +417,31 @@ void AstTyper::VisitYield(Yield* expr) { RECURSE(Visit(expr->generator_object())); RECURSE(Visit(expr->expression())); - // We don't know anything about the type. + // 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(), isolate_)); } void AstTyper::VisitProperty(Property* expr) { + // Collect type feedback. + expr->RecordTypeFeedback(oracle(), zone()); + RECURSE(Visit(expr->obj())); RECURSE(Visit(expr->key())); - expr->RecordTypeFeedback(oracle(), zone()); - - // We don't know anything about the type. + // We don't know anything about the result type. } void AstTyper::VisitCall(Call* expr) { - 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)); - } - + // Collect type feedback. Expression* callee = expr->expression(); Property* prop = callee->AsProperty(); if (prop != NULL) { @@ -371,11 +451,26 @@ void AstTyper::VisitCall(Call* expr) { expr->RecordTypeFeedback(oracle(), CALL_AS_FUNCTION); } - // We don't know anything about the type. + 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)); + } + + 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. + expr->RecordTypeFeedback(oracle()); + RECURSE(Visit(expr->expression())); ZoneList<Expression*>* args = expr->arguments(); for (int i = 0; i < args->length(); ++i) { @@ -383,9 +478,7 @@ void AstTyper::VisitCallNew(CallNew* expr) { RECURSE(Visit(arg)); } - expr->RecordTypeFeedback(oracle()); - - // We don't know anything about the type. + // We don't know anything about the result type. } @@ -396,19 +489,19 @@ void AstTyper::VisitCallRuntime(CallRuntime* expr) { RECURSE(Visit(arg)); } - // We don't know anything about the type. + // We don't know anything about the result type. } void AstTyper::VisitUnaryOperation(UnaryOperation* expr) { - RECURSE(Visit(expr->expression())); - // 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: @@ -427,22 +520,25 @@ void AstTyper::VisitUnaryOperation(UnaryOperation* expr) { void AstTyper::VisitCountOperation(CountOperation* expr) { - RECURSE(Visit(expr->expression())); - + // Collect type feedback. expr->RecordTypeFeedback(oracle(), zone()); Property* prop = expr->expression()->AsProperty(); if (prop != NULL) { prop->RecordTypeFeedback(oracle(), zone()); } + RECURSE(Visit(expr->expression())); + NarrowType(expr, Bounds(Type::Smi(), Type::Number(), isolate_)); + + 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) { - RECURSE(Visit(expr->left())); - RECURSE(Visit(expr->right())); - // Collect type feedback. Handle<Type> type, left_type, right_type; Maybe<int> fixed_right_arg; @@ -458,15 +554,29 @@ void AstTyper::VisitBinaryOperation(BinaryOperation* expr) { 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: + 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(), isolate_)); 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); if (!upper->Is(Type::Signed32())) upper = Type::Signed32(); @@ -476,12 +586,18 @@ void AstTyper::VisitBinaryOperation(BinaryOperation* expr) { case Token::BIT_XOR: case Token::SHL: case Token::SAR: + RECURSE(Visit(expr->left())); + RECURSE(Visit(expr->right())); NarrowType(expr, Bounds(Type::Smi(), Type::Signed32(), isolate_)); break; case Token::SHR: + RECURSE(Visit(expr->left())); + RECURSE(Visit(expr->right())); NarrowType(expr, Bounds(Type::Smi(), Type::Unsigned32(), isolate_)); break; case Token::ADD: { + RECURSE(Visit(expr->left())); + RECURSE(Visit(expr->right())); Bounds l = expr->left()->bounds(); Bounds r = expr->right()->bounds(); Type* lower = @@ -501,6 +617,8 @@ void AstTyper::VisitBinaryOperation(BinaryOperation* expr) { case Token::MUL: case Token::DIV: case Token::MOD: + RECURSE(Visit(expr->left())); + RECURSE(Visit(expr->right())); NarrowType(expr, Bounds(Type::Smi(), Type::Number(), isolate_)); break; default: @@ -510,9 +628,6 @@ void AstTyper::VisitBinaryOperation(BinaryOperation* expr) { void AstTyper::VisitCompareOperation(CompareOperation* expr) { - RECURSE(Visit(expr->left())); - RECURSE(Visit(expr->right())); - // Collect type feedback. Handle<Type> left_type, right_type, combined_type; oracle()->CompareType(expr->CompareOperationFeedbackId(), @@ -521,6 +636,9 @@ void AstTyper::VisitCompareOperation(CompareOperation* expr) { NarrowLowerType(expr->right(), right_type); expr->set_combined_type(combined_type); + RECURSE(Visit(expr->left())); + RECURSE(Visit(expr->right())); + NarrowType(expr, Bounds(Type::Boolean(), isolate_)); } |