Index: src/typing-asm.cc |
diff --git a/src/typing-asm.cc b/src/typing-asm.cc |
index 14db16ba94b36aeba4e97dfd503ee061f1000e4c..c17e19b33a40ff957f9cd749f54570b7f2cedd33 100644 |
--- a/src/typing-asm.cc |
+++ b/src/typing-asm.cc |
@@ -36,7 +36,6 @@ namespace internal { |
if (!valid_) return; \ |
} while (false) |
- |
AsmTyper::AsmTyper(Isolate* isolate, Zone* zone, Script* script, |
FunctionLiteral* root) |
: zone_(zone), |
@@ -62,6 +61,7 @@ AsmTyper::AsmTyper(Isolate* isolate, Zone* zone, Script* script, |
ZoneAllocationPolicy(zone)), |
in_function_(false), |
building_function_tables_(false), |
+ visiting_exports_(false), |
cache_(TypeCache::Get()) { |
InitializeAstVisitor(isolate); |
InitializeStdlib(); |
@@ -135,6 +135,7 @@ void AsmTyper::VisitAsmModule(FunctionLiteral* fun) { |
} |
// Validate exports. |
+ visiting_exports_ = true; |
ReturnStatement* stmt = fun->body()->last()->AsReturnStatement(); |
if (stmt == nullptr) { |
FAIL(fun->body()->last(), "last statement in module is not a return"); |
@@ -178,7 +179,7 @@ void AsmTyper::VisitFunctionAnnotation(FunctionLiteral* fun) { |
if (stmt != NULL) { |
Literal* literal = stmt->expression()->AsLiteral(); |
Type* old_expected = expected_type_; |
- expected_type_ = Type::Any(); |
+ expected_type_ = Type::Any(zone()); |
if (literal) { |
RECURSE(VisitLiteral(literal, true)); |
} else { |
@@ -188,9 +189,9 @@ void AsmTyper::VisitFunctionAnnotation(FunctionLiteral* fun) { |
result_type = computed_type_; |
} |
} |
- Type::FunctionType* type = |
- Type::Function(result_type, Type::Any(), fun->parameter_count(), zone()) |
- ->AsFunction(); |
+ Type::FunctionType* type = Type::Function(result_type, Type::Any(zone()), |
+ fun->parameter_count(), zone()) |
+ ->AsFunction(); |
// Extract parameter types. |
bool good = true; |
@@ -265,7 +266,7 @@ void AsmTyper::VisitExpressionAnnotation(Expression* expr, Variable* var, |
// Numbers or the undefined literal (for empty returns). |
if (expr->IsLiteral()) { |
- RECURSE(VisitWithExpectation(expr, Type::Any(), "invalid literal")); |
+ RECURSE(VisitWithExpectation(expr, Type::Any(zone()), "invalid literal")); |
return; |
} |
@@ -315,7 +316,7 @@ void AsmTyper::VisitBlock(Block* stmt) { |
void AsmTyper::VisitExpressionStatement(ExpressionStatement* stmt) { |
- RECURSE(VisitWithExpectation(stmt->expression(), Type::Any(), |
+ RECURSE(VisitWithExpectation(stmt->expression(), Type::Any(zone()), |
"expression statement expected to be any")); |
} |
@@ -367,7 +368,7 @@ void AsmTyper::VisitReturnStatement(ReturnStatement* stmt) { |
VisitLiteral(literal, true); |
} else { |
RECURSE( |
- VisitWithExpectation(stmt->expression(), Type::Any(), |
+ VisitWithExpectation(stmt->expression(), Type::Any(zone()), |
"return expression expected to have return type")); |
} |
if (!computed_type_->Is(return_type_) || !return_type_->Is(computed_type_)) { |
@@ -489,11 +490,11 @@ void AsmTyper::VisitDebuggerStatement(DebuggerStatement* stmt) { |
void AsmTyper::VisitFunctionLiteral(FunctionLiteral* expr) { |
- Scope* scope = expr->scope(); |
- DCHECK(scope->is_function_scope()); |
if (in_function_) { |
FAIL(expr, "invalid nested function"); |
} |
+ Scope* scope = expr->scope(); |
+ DCHECK(scope->is_function_scope()); |
if (!expr->bounds().upper->IsFunction()) { |
FAIL(expr, "invalid function literal"); |
@@ -523,7 +524,10 @@ void AsmTyper::VisitDoExpression(DoExpression* expr) { |
void AsmTyper::VisitConditional(Conditional* expr) { |
- RECURSE(VisitWithExpectation(expr->condition(), Type::Number(), |
+ if (!in_function_) { |
+ FAIL(expr, "ternary operator inside module body"); |
+ } |
+ RECURSE(VisitWithExpectation(expr->condition(), Type::Number(zone()), |
"condition expected to be integer")); |
if (!computed_type_->Is(cache_.kAsmInt)) { |
FAIL(expr->condition(), "condition must be of type int"); |
@@ -554,8 +558,18 @@ void AsmTyper::VisitConditional(Conditional* expr) { |
void AsmTyper::VisitVariableProxy(VariableProxy* expr) { |
+ VisitVariableProxy(expr, false); |
+} |
+ |
+void AsmTyper::VisitVariableProxy(VariableProxy* expr, bool assignment) { |
Variable* var = expr->var(); |
VariableInfo* info = GetVariableInfo(var, false); |
+ if (!assignment && !in_function_ && !building_function_tables_ && |
+ !visiting_exports_) { |
+ if (var->location() != VariableLocation::PARAMETER || var->index() >= 3) { |
+ FAIL(expr, "illegal variable reference in module body"); |
+ } |
+ } |
if (info == NULL || info->type == NULL) { |
if (var->mode() == TEMPORARY) { |
SetType(var, Type::Any(zone())); |
@@ -642,7 +656,7 @@ void AsmTyper::VisitArrayLiteral(ArrayLiteral* expr) { |
Type* elem_type = Type::None(zone()); |
for (int i = 0; i < values->length(); ++i) { |
Expression* value = values->at(i); |
- RECURSE(VisitWithExpectation(value, Type::Any(), "UNREACHABLE")); |
+ RECURSE(VisitWithExpectation(value, Type::Any(zone()), "UNREACHABLE")); |
if (!computed_type_->IsFunction()) { |
FAIL(value, "array component expected to be a function"); |
} |
@@ -675,11 +689,11 @@ void AsmTyper::VisitAssignment(Assignment* expr) { |
FAIL(expr, "intish or floatish assignment"); |
} |
if (expr->target()->IsVariableProxy()) { |
- RECURSE(VisitWithExpectation(expr->target(), target_type, |
- "assignment target expected to match value")); |
+ expected_type_ = target_type; |
+ VisitVariableProxy(expr->target()->AsVariableProxy(), true); |
} else if (expr->target()->IsProperty()) { |
Property* property = expr->target()->AsProperty(); |
- RECURSE(VisitWithExpectation(property->obj(), Type::Any(), |
+ RECURSE(VisitWithExpectation(property->obj(), Type::Any(zone()), |
"bad propety object")); |
if (!computed_type_->IsArray()) { |
FAIL(property->obj(), "array expected"); |
@@ -888,7 +902,8 @@ void AsmTyper::VisitProperty(Property* expr) { |
// Only recurse at this point so that we avoid needing |
// stdlib.Math to have a real type. |
- RECURSE(VisitWithExpectation(expr->obj(), Type::Any(), "bad propety object")); |
+ RECURSE(VisitWithExpectation(expr->obj(), Type::Any(zone()), |
+ "bad propety object")); |
// For heap view or function table access. |
if (computed_type_->IsArray()) { |
@@ -912,7 +927,8 @@ void AsmTyper::VisitProperty(Property* expr) { |
void AsmTyper::VisitCall(Call* expr) { |
- RECURSE(VisitWithExpectation(expr->expression(), Type::Any(), |
+ Type* expected_type = expected_type_; |
+ RECURSE(VisitWithExpectation(expr->expression(), Type::Any(zone()), |
"callee expected to be any")); |
StandardMember standard_member = kNone; |
VariableProxy* proxy = expr->expression()->AsVariableProxy(); |
@@ -967,16 +983,24 @@ void AsmTyper::VisitCall(Call* expr) { |
} |
intish_ = 0; |
IntersectResult(expr, result_type); |
- } else if (computed_type_->Is(Type::Any())) { |
+ } else if (computed_type_->Is(Type::Any(zone()))) { |
// For foreign calls. |
ZoneList<Expression*>* args = expr->arguments(); |
for (int i = 0; i < args->length(); ++i) { |
Expression* arg = args->at(i); |
- RECURSE(VisitWithExpectation(arg, Type::Any(), |
+ RECURSE(VisitWithExpectation(arg, Type::Any(zone()), |
"foreign call argument expected to be any")); |
+ // Checking for asm extern types explicitly, as the type system |
+ // doesn't correctly check their inheritance relationship. |
+ if (!computed_type_->Is(cache_.kAsmSigned) && |
+ !computed_type_->Is(cache_.kAsmFixnum) && |
+ !computed_type_->Is(cache_.kAsmDouble)) { |
+ FAIL(arg, |
+ "foreign call argument expected to be int, double, or fixnum"); |
+ } |
} |
intish_ = kMaxUncombinedAdditiveSteps; |
- IntersectResult(expr, Type::Number()); |
+ IntersectResult(expr, expected_type); |
} else { |
FAIL(expr, "invalid callee"); |
} |
@@ -987,7 +1011,7 @@ void AsmTyper::VisitCallNew(CallNew* expr) { |
if (in_function_) { |
FAIL(expr, "new not allowed in module function"); |
} |
- RECURSE(VisitWithExpectation(expr->expression(), Type::Any(), |
+ RECURSE(VisitWithExpectation(expr->expression(), Type::Any(zone()), |
"expected stdlib function")); |
if (computed_type_->IsFunction()) { |
Type::FunctionType* fun_type = computed_type_->AsFunction(); |
@@ -1014,6 +1038,9 @@ void AsmTyper::VisitCallRuntime(CallRuntime* expr) { |
void AsmTyper::VisitUnaryOperation(UnaryOperation* expr) { |
+ if (!in_function_) { |
+ FAIL(expr, "unary operator inside module body"); |
+ } |
switch (expr->op()) { |
case Token::NOT: // Used to encode != and !== |
RECURSE(VisitWithExpectation(expr->expression(), cache_.kAsmInt, |
@@ -1041,7 +1068,7 @@ void AsmTyper::VisitIntegerBitwiseOperator(BinaryOperation* expr, |
Type* left_expected, |
Type* right_expected, |
Type* result_type, bool conversion) { |
- RECURSE(VisitWithExpectation(expr->left(), Type::Number(), |
+ RECURSE(VisitWithExpectation(expr->left(), Type::Number(zone()), |
"left bitwise operand expected to be a number")); |
int left_intish = intish_; |
Type* left_type = computed_type_; |
@@ -1053,7 +1080,7 @@ void AsmTyper::VisitIntegerBitwiseOperator(BinaryOperation* expr, |
} |
RECURSE( |
- VisitWithExpectation(expr->right(), Type::Number(), |
+ VisitWithExpectation(expr->right(), Type::Number(zone()), |
"right bitwise operand expected to be a number")); |
int right_intish = intish_; |
Type* right_type = computed_type_; |
@@ -1082,11 +1109,20 @@ void AsmTyper::VisitIntegerBitwiseOperator(BinaryOperation* expr, |
void AsmTyper::VisitBinaryOperation(BinaryOperation* expr) { |
+ if (!in_function_) { |
+ if (expr->op() != Token::BIT_OR && expr->op() != Token::MUL) { |
+ FAIL(expr, "illegal binary operator inside module body"); |
+ } |
+ if (!(expr->left()->IsProperty() || expr->left()->IsVariableProxy()) || |
+ !expr->right()->IsLiteral()) { |
+ FAIL(expr, "illegal computation inside module body"); |
+ } |
+ } |
switch (expr->op()) { |
case Token::COMMA: { |
- RECURSE(VisitWithExpectation(expr->left(), Type::Any(), |
+ RECURSE(VisitWithExpectation(expr->left(), Type::Any(zone()), |
"left comma operand expected to be any")); |
- RECURSE(VisitWithExpectation(expr->right(), Type::Any(), |
+ RECURSE(VisitWithExpectation(expr->right(), Type::Any(zone()), |
"right comma operand expected to be any")); |
IntersectResult(expr, computed_type_); |
return; |
@@ -1096,8 +1132,11 @@ void AsmTyper::VisitBinaryOperation(BinaryOperation* expr) { |
FAIL(expr, "illegal logical operator"); |
case Token::BIT_OR: { |
// BIT_OR allows Any since it is used as a type coercion. |
- VisitIntegerBitwiseOperator(expr, Type::Any(), cache_.kAsmInt, |
+ VisitIntegerBitwiseOperator(expr, Type::Any(zone()), cache_.kAsmInt, |
cache_.kAsmSigned, true); |
+ if (expr->left()->IsCall() && expr->op() == Token::BIT_OR) { |
+ IntersectResult(expr->left(), cache_.kAsmSigned); |
+ } |
return; |
} |
case Token::BIT_XOR: { |
@@ -1115,7 +1154,7 @@ void AsmTyper::VisitBinaryOperation(BinaryOperation* expr) { |
} |
} |
// BIT_XOR allows Number since it is used as a type coercion (via ~~). |
- VisitIntegerBitwiseOperator(expr, Type::Number(), cache_.kAsmInt, |
+ VisitIntegerBitwiseOperator(expr, Type::Number(zone()), cache_.kAsmInt, |
cache_.kAsmSigned, true); |
return; |
} |
@@ -1137,12 +1176,12 @@ void AsmTyper::VisitBinaryOperation(BinaryOperation* expr) { |
case Token::DIV: |
case Token::MOD: { |
RECURSE(VisitWithExpectation( |
- expr->left(), Type::Number(), |
+ expr->left(), Type::Number(zone()), |
"left arithmetic operand expected to be number")); |
Type* left_type = computed_type_; |
int left_intish = intish_; |
RECURSE(VisitWithExpectation( |
- expr->right(), Type::Number(), |
+ expr->right(), Type::Number(zone()), |
"right arithmetic operand expected to be number")); |
Type* right_type = computed_type_; |
int right_intish = intish_; |
@@ -1184,6 +1223,9 @@ void AsmTyper::VisitBinaryOperation(BinaryOperation* expr) { |
} else if (expr->op() == Token::MUL && expr->right()->IsLiteral() && |
right_type->Is(cache_.kAsmDouble)) { |
// For unary +, expressed as x * 1.0 |
+ if (expr->left()->IsCall() && expr->op() == Token::MUL) { |
+ IntersectResult(expr->left(), cache_.kAsmDouble); |
+ } |
IntersectResult(expr, cache_.kAsmDouble); |
return; |
} else if (type->Is(cache_.kAsmFloat) && expr->op() != Token::MOD) { |
@@ -1207,6 +1249,9 @@ void AsmTyper::VisitBinaryOperation(BinaryOperation* expr) { |
void AsmTyper::VisitCompareOperation(CompareOperation* expr) { |
+ if (!in_function_) { |
+ FAIL(expr, "comparison inside module body"); |
+ } |
Token::Value op = expr->op(); |
if (op != Token::EQ && op != Token::NE && op != Token::LT && |
op != Token::LTE && op != Token::GT && op != Token::GTE) { |
@@ -1214,7 +1259,7 @@ void AsmTyper::VisitCompareOperation(CompareOperation* expr) { |
} |
RECURSE( |
- VisitWithExpectation(expr->left(), Type::Number(), |
+ VisitWithExpectation(expr->left(), Type::Number(zone()), |
"left comparison operand expected to be number")); |
Type* left_type = computed_type_; |
if (!left_type->Is(cache_.kAsmComparable)) { |
@@ -1222,7 +1267,7 @@ void AsmTyper::VisitCompareOperation(CompareOperation* expr) { |
} |
RECURSE( |
- VisitWithExpectation(expr->right(), Type::Number(), |
+ VisitWithExpectation(expr->right(), Type::Number(zone()), |
"right comparison operand expected to be number")); |
Type* right_type = computed_type_; |
if (!right_type->Is(cache_.kAsmComparable)) { |
@@ -1281,10 +1326,10 @@ void AsmTyper::VisitSuperCallReference(SuperCallReference* expr) { |
void AsmTyper::InitializeStdlibSIMD() { |
#define V(NAME, Name, name, lane_count, lane_type) \ |
{ \ |
- Type* type = Type::Function(Type::Name(isolate_, zone()), Type::Any(), \ |
- lane_count, zone()); \ |
+ Type* type = Type::Function(Type::Name(isolate_, zone()), \ |
+ Type::Any(zone()), lane_count, zone()); \ |
for (int i = 0; i < lane_count; ++i) { \ |
- type->AsFunction()->InitParameter(i, Type::Number()); \ |
+ type->AsFunction()->InitParameter(i, Type::Number(zone())); \ |
} \ |
stdlib_simd_##name##_constructor_type_ = new (zone()) VariableInfo(type); \ |
stdlib_simd_##name##_constructor_type_->is_constructor_function = true; \ |