Chromium Code Reviews| Index: src/typing.cc |
| diff --git a/src/typing.cc b/src/typing.cc |
| index 4645950bba87e952e38c44c47626a0fd5488bcb9..839c6cdafdee165a734ff6c934415ee2a6529120 100644 |
| --- a/src/typing.cc |
| +++ b/src/typing.cc |
| @@ -74,6 +74,14 @@ void AstTyper::Run(CompilationInfo* info) { |
| if (HasStackOverflow()) return; \ |
| } while (false) |
| +#define RECURSE_EXPR(call, expected_type) \ |
| + do { \ |
| + Handle<Type> save = expected_type_; \ |
| + expected_type_ = handle(expected_type, isolate_); \ |
| + RECURSE(call); \ |
| + expected_type_ = save; \ |
| + } while (false) |
| + |
| void AstTyper::VisitStatements(ZoneList<Statement*>* stmts) { |
| for (int i = 0; i < stmts->length(); ++i) { |
| @@ -89,7 +97,7 @@ void AstTyper::VisitBlock(Block* stmt) { |
| void AstTyper::VisitExpressionStatement(ExpressionStatement* stmt) { |
| - RECURSE(Visit(stmt->expression())); |
| + RECURSE_EXPR(Visit(stmt->expression()), Type::Any()); |
| } |
| @@ -98,14 +106,15 @@ 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_EXPR(Visit(stmt->condition()), Type::Boolean()); |
| + RECURSE(Visit(stmt->then_statement())); |
| + RECURSE(Visit(stmt->else_statement())); |
| } |
| @@ -118,28 +127,29 @@ void AstTyper::VisitBreakStatement(BreakStatement* stmt) { |
| 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_EXPR(Visit(stmt->expression()), Type::Any()); |
| } |
| void AstTyper::VisitWithStatement(WithStatement* stmt) { |
| - RECURSE(stmt->expression()); |
| + RECURSE_EXPR(stmt->expression(), Type::Receiver()); |
| RECURSE(stmt->statement()); |
| } |
| void AstTyper::VisitSwitchStatement(SwitchStatement* stmt) { |
| - RECURSE(Visit(stmt->tag())); |
| + RECURSE_EXPR(Visit(stmt->tag()), Type::Any()); |
| 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(); |
| - RECURSE(Visit(label)); |
| + RECURSE_EXPR(Visit(label), *stmt->tag()->upper_type()); |
| SwitchStatement::SwitchType label_switch_type = |
| label->IsSmiLiteral() ? SwitchStatement::SMI_SWITCH : |
| @@ -156,6 +166,7 @@ void AstTyper::VisitSwitchStatement(SwitchStatement* stmt) { |
| 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 +179,24 @@ 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()); |
| } |
| + |
| + RECURSE(Visit(stmt->body())); |
| + RECURSE_EXPR(Visit(stmt->cond()), Type::Boolean()); |
| } |
| void AstTyper::VisitWhileStatement(WhileStatement* stmt) { |
| - RECURSE(Visit(stmt->cond())); |
| - RECURSE(Visit(stmt->body())); |
| - |
| + // Collect type feedback. |
| if (!stmt->cond()->ToBooleanIsTrue()) { |
| stmt->cond()->RecordToBooleanTypeFeedback(oracle()); |
| } |
| + |
| + RECURSE_EXPR(Visit(stmt->cond()), Type::Boolean()); |
| + RECURSE(Visit(stmt->body())); |
| } |
| @@ -192,9 +205,10 @@ void AstTyper::VisitForStatement(ForStatement* stmt) { |
| RECURSE(Visit(stmt->init())); |
| } |
| if (stmt->cond() != NULL) { |
| - RECURSE(Visit(stmt->cond())); |
| - |
| + // Collect type feedback. |
| stmt->cond()->RecordToBooleanTypeFeedback(oracle()); |
| + |
| + RECURSE_EXPR(Visit(stmt->cond()), Type::Boolean()); |
| } |
| RECURSE(Visit(stmt->body())); |
| if (stmt->next() != NULL) { |
| @@ -204,15 +218,16 @@ void AstTyper::VisitForStatement(ForStatement* stmt) { |
| void AstTyper::VisitForInStatement(ForInStatement* stmt) { |
| - RECURSE(Visit(stmt->enumerable())); |
| - RECURSE(Visit(stmt->body())); |
| - |
| + // Collect type feedback. |
| stmt->RecordTypeFeedback(oracle()); |
| + |
| + RECURSE_EXPR(Visit(stmt->enumerable()), Type::Receiver()); |
| + RECURSE(Visit(stmt->body())); |
| } |
| void AstTyper::VisitForOfStatement(ForOfStatement* stmt) { |
| - RECURSE(Visit(stmt->iterable())); |
| + RECURSE_EXPR(Visit(stmt->iterable()), Type::Receiver()); |
| RECURSE(Visit(stmt->body())); |
| } |
| @@ -242,12 +257,13 @@ void AstTyper::VisitSharedFunctionInfoLiteral(SharedFunctionInfoLiteral* expr) { |
| void AstTyper::VisitConditional(Conditional* expr) { |
| - RECURSE(Visit(expr->condition())); |
| + // Collect type feedback. |
| + expr->condition()->RecordToBooleanTypeFeedback(oracle()); |
| + |
| + RECURSE_EXPR(Visit(expr->condition()), Type::Boolean()); |
| RECURSE(Visit(expr->then_expression())); |
| RECURSE(Visit(expr->else_expression())); |
| - expr->condition()->RecordToBooleanTypeFeedback(oracle()); |
| - |
| MergeLowerType(expr, Type::Intersect( |
| expr->then_expression()->lower_type(), |
| expr->else_expression()->lower_type())); |
| @@ -259,6 +275,10 @@ void AstTyper::VisitConditional(Conditional* expr) { |
| void AstTyper::VisitVariableProxy(VariableProxy* expr) { |
| // TODO(rossberg): typing of variables |
| + |
| + Variable* var = expr->var(); |
| + var->set_expected_type(handle( |
| + Type::Intersect(var->expected_type(), expected_type_), isolate_)); |
|
Jakob Kummerow
2013/07/09 16:01:50
As discussed offline, I still think a Union would
|
| } |
| @@ -279,8 +299,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) { |
| @@ -288,6 +308,8 @@ void AstTyper::VisitObjectLiteral(ObjectLiteral* expr) { |
| prop->RecordTypeFeedback(oracle()); |
| } |
| } |
| + |
| + RECURSE_EXPR(Visit(prop->value()), Type::Any()); |
| } |
| MergeLowerType(expr, Type::Object()); |
| @@ -299,7 +321,7 @@ 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)); |
| + RECURSE_EXPR(Visit(value), Type::Any()); |
| } |
| MergeLowerType(expr, Type::Array()); |
| @@ -310,8 +332,7 @@ 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) { |
| @@ -320,14 +341,18 @@ void AstTyper::VisitAssignment(Assignment* expr) { |
| expr->RecordTypeFeedback(oracle(), zone()); |
| } |
| } |
| - } else { |
| - RECURSE(Visit(expr->target())); |
| - RECURSE(Visit(expr->value())); |
| + RECURSE_EXPR(Visit(expr->binary_operation()), Type::Any()); |
| + MergeLowerType(expr, expr->binary_operation()->lower_type()); |
| + MergeUpperType(expr, expr->binary_operation()->upper_type()); |
| + } else { |
| + // Collect type feedback. |
| if (expr->target()->AsProperty()) { |
| expr->RecordTypeFeedback(oracle(), zone()); |
| } |
| + RECURSE(Visit(expr->target())); |
| + RECURSE(Visit(expr->value())); |
|
Jakob Kummerow
2013/07/09 16:01:50
Shouldn't this be RECURSE_EXPR(_, Type::Any())?
|
| MergeLowerType(expr, expr->value()->lower_type()); |
| MergeUpperType(expr, expr->value()->upper_type()); |
| } |
| @@ -336,15 +361,15 @@ void AstTyper::VisitAssignment(Assignment* expr) { |
| void AstTyper::VisitYield(Yield* expr) { |
| - RECURSE(Visit(expr->generator_object())); |
| - RECURSE(Visit(expr->expression())); |
| + RECURSE_EXPR(Visit(expr->generator_object()), Type::Receiver()); |
| + RECURSE_EXPR(Visit(expr->expression()), Type::Any()); |
| - // 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())); |
| + RECURSE_EXPR(Visit(expr->exception()), Type::Any()); |
| // Lower type is None already. |
| MergeUpperType(expr, Type::None()); |
| @@ -352,23 +377,18 @@ void AstTyper::VisitThrow(Throw* expr) { |
| void AstTyper::VisitProperty(Property* expr) { |
| - RECURSE(Visit(expr->obj())); |
| - RECURSE(Visit(expr->key())); |
| - |
| + // Collect type feedback. |
| expr->RecordTypeFeedback(oracle(), zone()); |
| - // We don't know anything about the type. |
| + RECURSE_EXPR(Visit(expr->obj()), Type::Receiver()); |
| + RECURSE_EXPR(Visit(expr->key()), Type::Name()); |
|
Jakob Kummerow
2013/07/09 16:01:50
I'm pretty sure that the key can also be a number.
|
| + |
| + // 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) { |
| @@ -378,21 +398,29 @@ void AstTyper::VisitCall(Call* expr) { |
| expr->RecordTypeFeedback(oracle(), CALL_AS_FUNCTION); |
| } |
| - // We don't know anything about the type. |
| + RECURSE_EXPR(Visit(expr->expression()), Type::Function()); |
| + ZoneList<Expression*>* args = expr->arguments(); |
| + for (int i = 0; i < args->length(); ++i) { |
| + Expression* arg = args->at(i); |
| + RECURSE_EXPR(Visit(arg), Type::Any()); |
| + } |
| + |
| + // We don't know anything about the result type. |
| } |
| void AstTyper::VisitCallNew(CallNew* expr) { |
| - RECURSE(Visit(expr->expression())); |
| + // Collect type feedback. |
| + expr->RecordTypeFeedback(oracle()); |
| + |
| + RECURSE_EXPR(Visit(expr->expression()), Type::Function()); |
| ZoneList<Expression*>* args = expr->arguments(); |
| for (int i = 0; i < args->length(); ++i) { |
| Expression* arg = args->at(i); |
| - RECURSE(Visit(arg)); |
| + RECURSE_EXPR(Visit(arg), Type::Any()); |
| } |
| - expr->RecordTypeFeedback(oracle()); |
| - |
| - // We don't know anything about the type. |
| + // We don't know anything about the result type. |
| } |
| @@ -400,16 +428,14 @@ 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)); |
| + RECURSE_EXPR(Visit(arg), Type::Any()); |
| } |
| - // 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. |
| Handle<Type> op_type = oracle()->UnaryType(expr->UnaryOperationFeedbackId()); |
| MergeLowerType(expr->expression(), op_type); |
| @@ -420,26 +446,35 @@ void AstTyper::VisitUnaryOperation(UnaryOperation* expr) { |
| switch (expr->op()) { |
| case Token::NOT: |
| + RECURSE_EXPR(Visit(expr->expression()), Type::Boolean()); |
| + MergeLowerType(expr, Type::Boolean()); |
| + MergeUpperType(expr, Type::Boolean()); |
| + break; |
| case Token::DELETE: |
| + RECURSE_EXPR(Visit(expr->expression()), Type::Any()); |
| MergeLowerType(expr, Type::Boolean()); |
| MergeUpperType(expr, Type::Boolean()); |
| break; |
| case Token::VOID: |
| + RECURSE_EXPR(Visit(expr->expression()), Type::Any()); |
| MergeLowerType(expr, Type::Undefined()); |
| MergeUpperType(expr, Type::Undefined()); |
| break; |
| case Token::ADD: |
| case Token::SUB: { |
| + RECURSE_EXPR(Visit(expr->expression()), Type::Number()); |
| MergeLowerType(expr, Type::Smi()); |
| Type* upper = *expr->expression()->upper_type(); |
| MergeUpperType(expr, upper->Is(Type::Number()) ? upper : Type::Number()); |
| break; |
| } |
| case Token::BIT_NOT: |
| + RECURSE_EXPR(Visit(expr->expression()), Type::Signed32()); |
| MergeLowerType(expr, Type::Smi()); |
| MergeUpperType(expr, Type::Signed32()); |
| break; |
| case Token::TYPEOF: |
| + RECURSE_EXPR(Visit(expr->expression()), Type::Any()); |
| MergeLowerType(expr, Type::InternalizedString()); |
| MergeUpperType(expr, Type::InternalizedString()); |
| break; |
| @@ -450,23 +485,20 @@ 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_EXPR(Visit(expr->expression()), Type::Number()); |
| MergeLowerType(expr, Type::Smi()); |
| MergeUpperType(expr, Type::Number()); |
| } |
| 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; |
| @@ -482,11 +514,15 @@ void AstTyper::VisitBinaryOperation(BinaryOperation* expr) { |
| switch (expr->op()) { |
| case Token::COMMA: |
| + RECURSE_EXPR(Visit(expr->left()), Type::Any()); |
| + RECURSE_EXPR(Visit(expr->right()), Type::Any()); |
| MergeLowerType(expr, expr->right()->lower_type()); |
| MergeUpperType(expr, expr->right()->upper_type()); |
| break; |
| case Token::OR: |
| case Token::AND: |
| + RECURSE_EXPR(Visit(expr->left()), Type::Any()); |
| + RECURSE_EXPR(Visit(expr->right()), Type::Any()); |
| MergeLowerType(expr, Type::Intersect( |
| expr->left()->lower_type(), expr->right()->lower_type())); |
| MergeUpperType(expr, Type::Union( |
| @@ -494,6 +530,8 @@ void AstTyper::VisitBinaryOperation(BinaryOperation* expr) { |
| break; |
| case Token::BIT_OR: |
| case Token::BIT_AND: { |
| + RECURSE_EXPR(Visit(expr->left()), Type::Signed32()); |
| + RECURSE_EXPR(Visit(expr->right()), Type::Signed32()); |
| MergeLowerType(expr, Type::Smi()); |
| Type* upper = |
| Type::Union(expr->left()->upper_type(), expr->right()->upper_type()); |
| @@ -502,16 +540,27 @@ void AstTyper::VisitBinaryOperation(BinaryOperation* expr) { |
| break; |
| } |
| case Token::BIT_XOR: |
| + RECURSE_EXPR(Visit(expr->left()), Type::Signed32()); |
| + RECURSE_EXPR(Visit(expr->right()), Type::Signed32()); |
| + MergeLowerType(expr, Type::Smi()); |
| + MergeUpperType(expr, Type::Signed32()); |
| + break; |
| case Token::SHL: |
| case Token::SAR: |
| + RECURSE_EXPR(Visit(expr->left()), Type::Signed32()); |
| + RECURSE_EXPR(Visit(expr->right()), Type::Unsigned32()); |
| MergeLowerType(expr, Type::Smi()); |
| MergeUpperType(expr, Type::Signed32()); |
| break; |
| case Token::SHR: |
| + RECURSE_EXPR(Visit(expr->left()), Type::Unsigned32()); |
| + RECURSE_EXPR(Visit(expr->right()), Type::Unsigned32()); |
| MergeLowerType(expr, Type::Smi()); |
| MergeUpperType(expr, Type::Unsigned32()); |
| break; |
| case Token::ADD: { |
| + RECURSE_EXPR(Visit(expr->left()), Type::NumberOrString()); |
| + RECURSE_EXPR(Visit(expr->right()), Type::NumberOrString()); |
| Handle<Type> l = expr->left()->lower_type(); |
| Handle<Type> r = expr->right()->lower_type(); |
| MergeLowerType(expr, |
| @@ -530,6 +579,8 @@ void AstTyper::VisitBinaryOperation(BinaryOperation* expr) { |
| case Token::MUL: |
| case Token::DIV: |
| case Token::MOD: |
| + RECURSE_EXPR(Visit(expr->left()), Type::Number()); |
| + RECURSE_EXPR(Visit(expr->right()), Type::Number()); |
| MergeLowerType(expr, Type::Smi()); |
| MergeUpperType(expr, Type::Number()); |
| break; |
| @@ -540,9 +591,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(), |
| @@ -551,6 +599,32 @@ void AstTyper::VisitCompareOperation(CompareOperation* expr) { |
| MergeLowerType(expr->right(), right_type); |
| expr->set_combined_type(combined_type); |
| + switch (expr->op()) { |
| + case Token::EQ: |
| + case Token::NE: |
| + case Token::EQ_STRICT: |
| + case Token::NE_STRICT: |
| + RECURSE_EXPR(Visit(expr->left()), Type::Any()); |
| + RECURSE_EXPR(Visit(expr->right()), Type::Any()); |
| + break; |
| + case Token::LT: |
| + case Token::GT: |
| + case Token::LTE: |
| + case Token::GTE: |
| + RECURSE_EXPR(Visit(expr->left()), Type::NumberOrString()); |
| + RECURSE_EXPR(Visit(expr->right()), Type::NumberOrString()); |
| + break; |
| + case Token::INSTANCEOF: |
| + RECURSE_EXPR(Visit(expr->left()), Type::Receiver()); |
| + RECURSE_EXPR(Visit(expr->right()), Type::Function()); |
| + break; |
| + case Token::IN: |
| + RECURSE_EXPR(Visit(expr->left()), Type::Name()); |
| + RECURSE_EXPR(Visit(expr->right()), Type::Receiver()); |
| + break; |
| + default: |
| + UNREACHABLE(); |
| + } |
| MergeLowerType(expr, Type::Boolean()); |
| MergeUpperType(expr, Type::Boolean()); |
| } |