1 // Copyright 2015 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
7 #include "src/typing-asm.h"
10 #include "src/codegen.h"
11 #include "src/scopes.h"
12 #include "src/zone-type-cache.h"
18 base::LazyInstance<ZoneTypeCache>::type kCache = LAZY_INSTANCE_INITIALIZER;
23 #define FAIL(node, msg) \
26 int line = node->position() == RelocInfo::kNoPosition \
28 : script_->GetLineNumber(node->position()); \
29 base::OS::SNPrintF(error_message_, sizeof(error_message_), \
30 "asm: line %d: %s\n", line + 1, msg); \
35 #define RECURSE(call) \
37 DCHECK(!HasStackOverflow()); \
39 if (HasStackOverflow()) return; \
40 if (!valid_) return; \
44 AsmTyper::AsmTyper(Isolate* isolate, Zone* zone, Script* script,
45 FunctionLiteral* root)
50 stdlib_heap_types_(zone),
51 stdlib_math_types_(zone),
52 global_variable_type_(HashMap::PointersMatch,
53 ZoneHashMap::kDefaultHashMapCapacity,
54 ZoneAllocationPolicy(zone)),
55 local_variable_type_(HashMap::PointersMatch,
56 ZoneHashMap::kDefaultHashMapCapacity,
57 ZoneAllocationPolicy(zone)),
59 building_function_tables_(false),
60 cache_(kCache.Get()) {
61 InitializeAstVisitor(isolate, zone);
66 bool AsmTyper::Validate() {
67 VisitAsmModule(root_);
68 return valid_ && !HasStackOverflow();
72 void AsmTyper::VisitAsmModule(FunctionLiteral* fun) {
73 Scope* scope = fun->scope();
74 if (!scope->is_function_scope()) FAIL(fun, "not at function scope");
77 for (int i = 0; i < scope->num_parameters(); ++i) {
78 Variable* param = scope->parameter(i);
79 DCHECK(GetType(param) == NULL);
80 SetType(param, Type::None(zone()));
83 ZoneList<Declaration*>* decls = scope->declarations();
85 // Set all globals to type Any.
86 VariableDeclaration* decl = scope->function();
87 if (decl != NULL) SetType(decl->proxy()->var(), Type::None());
88 RECURSE(VisitDeclarations(scope->declarations()));
90 // Validate global variables.
91 RECURSE(VisitStatements(fun->body()));
93 // Validate function annotations.
94 for (int i = 0; i < decls->length(); ++i) {
95 FunctionDeclaration* decl = decls->at(i)->AsFunctionDeclaration();
97 RECURSE(VisitFunctionAnnotation(decl->fun()));
98 Variable* var = decl->proxy()->var();
99 DCHECK(GetType(var) == NULL);
100 SetType(var, computed_type_);
101 DCHECK(GetType(var) != NULL);
105 // Build function tables.
106 building_function_tables_ = true;
107 RECURSE(VisitStatements(fun->body()));
108 building_function_tables_ = false;
110 // Validate function bodies.
111 for (int i = 0; i < decls->length(); ++i) {
112 FunctionDeclaration* decl = decls->at(i)->AsFunctionDeclaration();
115 VisitWithExpectation(decl->fun(), Type::Any(zone()), "UNREACHABLE"));
116 if (!computed_type_->IsFunction()) {
117 FAIL(decl->fun(), "function literal expected to be a function");
123 ReturnStatement* stmt = fun->body()->last()->AsReturnStatement();
124 RECURSE(VisitWithExpectation(stmt->expression(), Type::Object(),
125 "expected object export"));
129 void AsmTyper::VisitVariableDeclaration(VariableDeclaration* decl) {
130 Variable* var = decl->proxy()->var();
131 if (var->location() != VariableLocation::PARAMETER) {
132 if (GetType(var) == NULL) {
133 SetType(var, Type::Any(zone()));
135 DCHECK(!GetType(var)->IsFunction());
138 DCHECK(GetType(var) != NULL);
143 void AsmTyper::VisitFunctionDeclaration(FunctionDeclaration* decl) {
145 FAIL(decl, "function declared inside another");
150 void AsmTyper::VisitFunctionAnnotation(FunctionLiteral* fun) {
151 // Extract result type.
152 ZoneList<Statement*>* body = fun->body();
153 Type* result_type = Type::Undefined(zone());
154 if (body->length() > 0) {
155 ReturnStatement* stmt = body->last()->AsReturnStatement();
157 RECURSE(VisitExpressionAnnotation(stmt->expression()));
158 result_type = computed_type_;
161 Type::FunctionType* type =
162 Type::Function(result_type, Type::Any(), fun->parameter_count(), zone())
165 // Extract parameter types.
167 for (int i = 0; i < fun->parameter_count(); ++i) {
169 if (i >= body->length()) break;
170 ExpressionStatement* stmt = body->at(i)->AsExpressionStatement();
171 if (stmt == NULL) break;
172 Assignment* expr = stmt->expression()->AsAssignment();
173 if (expr == NULL || expr->is_compound()) break;
174 VariableProxy* proxy = expr->target()->AsVariableProxy();
175 if (proxy == NULL) break;
176 Variable* var = proxy->var();
177 if (var->location() != VariableLocation::PARAMETER || var->index() != i)
179 RECURSE(VisitExpressionAnnotation(expr->value()));
180 SetType(var, computed_type_);
181 type->InitParameter(i, computed_type_);
184 if (!good) FAIL(fun, "missing parameter type annotations");
186 SetResult(fun, type);
190 void AsmTyper::VisitExpressionAnnotation(Expression* expr) {
191 // Normal +x or x|0 annotations.
192 BinaryOperation* bin = expr->AsBinaryOperation();
194 Literal* right = bin->right()->AsLiteral();
197 case Token::MUL: // We encode +x as 1*x
198 if (right->raw_value()->ContainsDot() &&
199 right->raw_value()->AsNumber() == 1.0) {
200 SetResult(expr, cache_.kFloat64);
205 if (!right->raw_value()->ContainsDot() &&
206 right->raw_value()->AsNumber() == 0.0) {
207 SetResult(expr, cache_.kInt32);
215 FAIL(expr, "invalid type annotation on binary op");
218 // Numbers or the undefined literal (for empty returns).
219 if (expr->IsLiteral()) {
220 RECURSE(VisitWithExpectation(expr, Type::Any(), "invalid literal"));
224 Call* call = expr->AsCall();
226 if (call->expression()->IsVariableProxy()) {
227 RECURSE(VisitWithExpectation(
228 call->expression(), Type::Any(zone()),
229 "only fround allowed on expression annotations"));
230 if (!computed_type_->Is(
231 Type::Function(cache_.kFloat32, Type::Number(zone()), zone()))) {
232 FAIL(call->expression(),
233 "only fround allowed on expression annotations");
235 if (call->arguments()->length() != 1) {
236 FAIL(call, "invalid argument count calling fround");
238 SetResult(expr, cache_.kFloat32);
243 FAIL(expr, "invalid type annotation");
247 void AsmTyper::VisitStatements(ZoneList<Statement*>* stmts) {
248 for (int i = 0; i < stmts->length(); ++i) {
249 Statement* stmt = stmts->at(i);
250 RECURSE(Visit(stmt));
255 void AsmTyper::VisitBlock(Block* stmt) {
256 RECURSE(VisitStatements(stmt->statements()));
260 void AsmTyper::VisitExpressionStatement(ExpressionStatement* stmt) {
261 RECURSE(VisitWithExpectation(stmt->expression(), Type::Any(),
262 "expression statement expected to be any"));
266 void AsmTyper::VisitEmptyStatement(EmptyStatement* stmt) {}
269 void AsmTyper::VisitEmptyParentheses(EmptyParentheses* expr) { UNREACHABLE(); }
272 void AsmTyper::VisitIfStatement(IfStatement* stmt) {
274 FAIL(stmt, "if statement inside module body");
276 RECURSE(VisitWithExpectation(stmt->condition(), cache_.kInt32,
277 "if condition expected to be integer"));
278 RECURSE(Visit(stmt->then_statement()));
279 RECURSE(Visit(stmt->else_statement()));
283 void AsmTyper::VisitContinueStatement(ContinueStatement* stmt) {
285 FAIL(stmt, "continue statement inside module body");
290 void AsmTyper::VisitBreakStatement(BreakStatement* stmt) {
292 FAIL(stmt, "continue statement inside module body");
297 void AsmTyper::VisitReturnStatement(ReturnStatement* stmt) {
298 // Handle module return statement in VisitAsmModule.
303 VisitWithExpectation(stmt->expression(), return_type_,
304 "return expression expected to have return type"));
308 void AsmTyper::VisitWithStatement(WithStatement* stmt) {
309 FAIL(stmt, "bad with statement");
313 void AsmTyper::VisitSwitchStatement(SwitchStatement* stmt) {
315 FAIL(stmt, "switch statement inside module body");
317 RECURSE(VisitWithExpectation(stmt->tag(), cache_.kInt32,
318 "switch expression non-integer"));
319 ZoneList<CaseClause*>* clauses = stmt->cases();
320 for (int i = 0; i < clauses->length(); ++i) {
321 CaseClause* clause = clauses->at(i);
322 if (clause->is_default()) continue;
323 Expression* label = clause->label();
325 VisitWithExpectation(label, cache_.kInt32, "case label non-integer"));
326 if (!label->IsLiteral()) FAIL(label, "non-literal case label");
327 Handle<Object> value = label->AsLiteral()->value();
329 if (!value->ToInt32(&value32)) FAIL(label, "illegal case label value");
330 // TODO(bradnelson): Detect duplicates.
331 ZoneList<Statement*>* stmts = clause->statements();
332 RECURSE(VisitStatements(stmts));
337 void AsmTyper::VisitCaseClause(CaseClause* clause) { UNREACHABLE(); }
340 void AsmTyper::VisitDoWhileStatement(DoWhileStatement* stmt) {
342 FAIL(stmt, "do statement inside module body");
344 RECURSE(Visit(stmt->body()));
345 RECURSE(VisitWithExpectation(stmt->cond(), cache_.kInt32,
346 "do condition expected to be integer"));
350 void AsmTyper::VisitWhileStatement(WhileStatement* stmt) {
352 FAIL(stmt, "while statement inside module body");
354 RECURSE(VisitWithExpectation(stmt->cond(), cache_.kInt32,
355 "while condition expected to be integer"));
356 RECURSE(Visit(stmt->body()));
360 void AsmTyper::VisitForStatement(ForStatement* stmt) {
362 FAIL(stmt, "for statement inside module body");
364 if (stmt->init() != NULL) {
365 RECURSE(Visit(stmt->init()));
367 if (stmt->cond() != NULL) {
368 RECURSE(VisitWithExpectation(stmt->cond(), cache_.kInt32,
369 "for condition expected to be integer"));
371 if (stmt->next() != NULL) {
372 RECURSE(Visit(stmt->next()));
374 RECURSE(Visit(stmt->body()));
378 void AsmTyper::VisitForInStatement(ForInStatement* stmt) {
379 FAIL(stmt, "for-in statement encountered");
383 void AsmTyper::VisitForOfStatement(ForOfStatement* stmt) {
384 FAIL(stmt, "for-of statement encountered");
388 void AsmTyper::VisitTryCatchStatement(TryCatchStatement* stmt) {
389 FAIL(stmt, "try statement encountered");
393 void AsmTyper::VisitTryFinallyStatement(TryFinallyStatement* stmt) {
394 FAIL(stmt, "try statement encountered");
398 void AsmTyper::VisitDebuggerStatement(DebuggerStatement* stmt) {
399 FAIL(stmt, "debugger statement encountered");
403 void AsmTyper::VisitFunctionLiteral(FunctionLiteral* expr) {
404 Scope* scope = expr->scope();
405 DCHECK(scope->is_function_scope());
407 FAIL(expr, "invalid nested function");
410 if (!expr->bounds().upper->IsFunction()) {
411 FAIL(expr, "invalid function literal");
414 Type::FunctionType* type = expr->bounds().upper->AsFunction();
415 Type* save_return_type = return_type_;
416 return_type_ = type->Result();
418 local_variable_type_.Clear();
419 RECURSE(VisitDeclarations(scope->declarations()));
420 RECURSE(VisitStatements(expr->body()));
421 in_function_ = false;
422 return_type_ = save_return_type;
423 IntersectResult(expr, type);
427 void AsmTyper::VisitNativeFunctionLiteral(NativeFunctionLiteral* expr) {
428 FAIL(expr, "function info literal encountered");
432 void AsmTyper::VisitConditional(Conditional* expr) {
433 RECURSE(VisitWithExpectation(expr->condition(), cache_.kInt32,
434 "condition expected to be integer"));
435 RECURSE(VisitWithExpectation(
436 expr->then_expression(), expected_type_,
437 "conditional then branch type mismatch with enclosing expression"));
438 Type* then_type = computed_type_;
439 RECURSE(VisitWithExpectation(
440 expr->else_expression(), expected_type_,
441 "conditional else branch type mismatch with enclosing expression"));
442 Type* else_type = computed_type_;
443 Type* type = Type::Intersect(then_type, else_type, zone());
444 if (!(type->Is(cache_.kInt32) || type->Is(cache_.kFloat64))) {
445 FAIL(expr, "ill-typed conditional");
447 IntersectResult(expr, type);
451 void AsmTyper::VisitVariableProxy(VariableProxy* expr) {
452 Variable* var = expr->var();
453 if (GetType(var) == NULL) {
454 FAIL(expr, "unbound variable");
456 Type* type = Type::Intersect(GetType(var), expected_type_, zone());
457 if (type->Is(cache_.kInt32)) {
458 type = cache_.kInt32;
462 IntersectResult(expr, type);
466 void AsmTyper::VisitLiteral(Literal* expr) {
468 Handle<Object> value = expr->value();
469 if (value->IsNumber()) {
472 if (expr->raw_value()->ContainsDot()) {
473 IntersectResult(expr, cache_.kFloat64);
474 } else if (value->ToUint32(&u)) {
475 IntersectResult(expr, cache_.kInt32);
476 } else if (value->ToInt32(&i)) {
477 IntersectResult(expr, cache_.kInt32);
479 FAIL(expr, "illegal number");
481 } else if (value->IsString()) {
482 IntersectResult(expr, Type::String());
483 } else if (value->IsUndefined()) {
484 IntersectResult(expr, Type::Undefined());
486 FAIL(expr, "illegal literal");
491 void AsmTyper::VisitRegExpLiteral(RegExpLiteral* expr) {
492 FAIL(expr, "regular expression encountered");
496 void AsmTyper::VisitObjectLiteral(ObjectLiteral* expr) {
498 FAIL(expr, "object literal in function");
500 // Allowed for asm module's export declaration.
501 ZoneList<ObjectLiteralProperty*>* props = expr->properties();
502 for (int i = 0; i < props->length(); ++i) {
503 ObjectLiteralProperty* prop = props->at(i);
504 RECURSE(VisitWithExpectation(prop->value(), Type::Any(zone()),
505 "object property expected to be a function"));
506 if (!computed_type_->IsFunction()) {
507 FAIL(prop->value(), "non-function in function table");
510 IntersectResult(expr, Type::Object(zone()));
514 void AsmTyper::VisitArrayLiteral(ArrayLiteral* expr) {
516 FAIL(expr, "array literal inside a function");
518 // Allowed for function tables.
519 ZoneList<Expression*>* values = expr->values();
520 Type* elem_type = Type::None(zone());
521 for (int i = 0; i < values->length(); ++i) {
522 Expression* value = values->at(i);
523 RECURSE(VisitWithExpectation(value, Type::Any(), "UNREACHABLE"));
524 if (!computed_type_->IsFunction()) {
525 FAIL(value, "array component expected to be a function");
527 elem_type = Type::Union(elem_type, computed_type_, zone());
529 array_size_ = values->length();
530 IntersectResult(expr, Type::Array(elem_type, zone()));
534 void AsmTyper::VisitAssignment(Assignment* expr) {
535 // Handle function tables and everything else in different passes.
537 if (expr->value()->IsArrayLiteral()) {
538 if (!building_function_tables_) {
542 if (building_function_tables_) {
547 if (expr->is_compound()) FAIL(expr, "compound assignment encountered");
548 Type* type = expected_type_;
549 RECURSE(VisitWithExpectation(
550 expr->value(), type, "assignment value expected to match surrounding"));
552 FAIL(expr, "value still an intish");
554 RECURSE(VisitWithExpectation(expr->target(), computed_type_,
555 "assignment target expected to match value"));
557 FAIL(expr, "value still an intish");
559 IntersectResult(expr, computed_type_);
563 void AsmTyper::VisitYield(Yield* expr) {
564 FAIL(expr, "yield expression encountered");
568 void AsmTyper::VisitThrow(Throw* expr) {
569 FAIL(expr, "throw statement encountered");
573 int AsmTyper::ElementShiftSize(Type* type) {
574 if (type->Is(cache_.kInt8) || type->Is(cache_.kUint8)) return 0;
575 if (type->Is(cache_.kInt16) || type->Is(cache_.kUint16)) return 1;
576 if (type->Is(cache_.kInt32) || type->Is(cache_.kUint32) ||
577 type->Is(cache_.kFloat32))
579 if (type->Is(cache_.kFloat64)) return 3;
584 void AsmTyper::VisitHeapAccess(Property* expr) {
585 Type::ArrayType* array_type = computed_type_->AsArray();
586 size_t size = array_size_;
587 Type* type = array_type->AsArray()->Element();
588 if (type->IsFunction()) {
589 BinaryOperation* bin = expr->key()->AsBinaryOperation();
590 if (bin == NULL || bin->op() != Token::BIT_AND) {
591 FAIL(expr->key(), "expected & in call");
593 RECURSE(VisitWithExpectation(bin->left(), cache_.kInt32,
594 "array index expected to be integer"));
595 Literal* right = bin->right()->AsLiteral();
596 if (right == NULL || right->raw_value()->ContainsDot()) {
597 FAIL(right, "call mask must be integer");
599 RECURSE(VisitWithExpectation(bin->right(), cache_.kInt32,
600 "call mask expected to be integer"));
601 if (static_cast<size_t>(right->raw_value()->AsNumber()) != size - 1) {
602 FAIL(right, "call mask must match function table");
604 bin->set_bounds(Bounds(cache_.kInt32));
606 BinaryOperation* bin = expr->key()->AsBinaryOperation();
607 if (bin == NULL || bin->op() != Token::SAR) {
608 FAIL(expr->key(), "expected >> in heap access");
610 RECURSE(VisitWithExpectation(bin->left(), cache_.kInt32,
611 "array index expected to be integer"));
612 Literal* right = bin->right()->AsLiteral();
613 if (right == NULL || right->raw_value()->ContainsDot()) {
614 FAIL(right, "heap access shift must be integer");
616 RECURSE(VisitWithExpectation(bin->right(), cache_.kInt32,
617 "array shift expected to be integer"));
618 int n = static_cast<int>(right->raw_value()->AsNumber());
619 int expected_shift = ElementShiftSize(type);
620 if (expected_shift < 0 || n != expected_shift) {
621 FAIL(right, "heap access shift must match element size");
623 bin->set_bounds(Bounds(cache_.kInt32));
625 IntersectResult(expr, type);
629 void AsmTyper::VisitProperty(Property* expr) {
631 Property* inner_prop = expr->obj()->AsProperty();
632 if (inner_prop != NULL) {
633 // Get property name.
634 Literal* key = expr->key()->AsLiteral();
635 if (key == NULL || !key->IsPropertyName())
636 FAIL(expr, "invalid type annotation on property 2");
637 Handle<String> name = key->AsPropertyName();
639 // Check that inner property name is "Math".
640 Literal* math_key = inner_prop->key()->AsLiteral();
641 if (math_key == NULL || !math_key->IsPropertyName() ||
642 !math_key->AsPropertyName()->IsUtf8EqualTo(CStrVector("Math")))
643 FAIL(expr, "invalid type annotation on stdlib (a1)");
645 // Check that object is stdlib.
646 VariableProxy* proxy = inner_prop->obj()->AsVariableProxy();
647 if (proxy == NULL) FAIL(expr, "invalid type annotation on stdlib (a2)");
648 Variable* var = proxy->var();
649 if (var->location() != VariableLocation::PARAMETER || var->index() != 0)
650 FAIL(expr, "invalid type annotation on stdlib (a3)");
652 // Look up library type.
653 Type* type = LibType(stdlib_math_types_, name);
654 if (type == NULL) FAIL(expr, "unknown standard function 3 ");
655 SetResult(expr, type);
659 // Only recurse at this point so that we avoid needing
660 // stdlib.Math to have a real type.
661 RECURSE(VisitWithExpectation(expr->obj(), Type::Any(),
662 "property holder expected to be object"));
664 // For heap view or function table access.
665 if (computed_type_->IsArray()) {
666 VisitHeapAccess(expr);
670 // Get property name.
671 Literal* key = expr->key()->AsLiteral();
672 if (key == NULL || !key->IsPropertyName())
673 FAIL(expr, "invalid type annotation on property 3");
674 Handle<String> name = key->AsPropertyName();
676 // stdlib.x or foreign.x
677 VariableProxy* proxy = expr->obj()->AsVariableProxy();
679 Variable* var = proxy->var();
680 if (var->location() != VariableLocation::PARAMETER) {
681 FAIL(expr, "invalid type annotation on variable");
683 switch (var->index()) {
685 // Object is stdlib, look up library type.
686 Type* type = LibType(stdlib_types_, name);
688 FAIL(expr, "unknown standard function 4");
690 SetResult(expr, type);
694 // Object is foreign lib.
695 SetResult(expr, expected_type_);
698 FAIL(expr, "invalid type annotation on parameter");
702 FAIL(expr, "invalid property access");
706 void AsmTyper::VisitCall(Call* expr) {
707 RECURSE(VisitWithExpectation(expr->expression(), Type::Any(),
708 "callee expected to be any"));
709 if (computed_type_->IsFunction()) {
710 Type::FunctionType* fun_type = computed_type_->AsFunction();
711 ZoneList<Expression*>* args = expr->arguments();
712 if (fun_type->Arity() != args->length()) {
713 FAIL(expr, "call with wrong arity");
715 for (int i = 0; i < args->length(); ++i) {
716 Expression* arg = args->at(i);
717 RECURSE(VisitWithExpectation(
718 arg, fun_type->Parameter(i),
719 "call argument expected to match callee parameter"));
721 IntersectResult(expr, fun_type->Result());
722 } else if (computed_type_->Is(Type::Any())) {
723 // For foreign calls.
724 ZoneList<Expression*>* args = expr->arguments();
725 for (int i = 0; i < args->length(); ++i) {
726 Expression* arg = args->at(i);
727 RECURSE(VisitWithExpectation(arg, Type::Any(),
728 "foreign call argument expected to be any"));
730 IntersectResult(expr, Type::Number());
732 FAIL(expr, "invalid callee");
737 void AsmTyper::VisitCallNew(CallNew* expr) {
739 FAIL(expr, "new not allowed in module function");
741 RECURSE(VisitWithExpectation(expr->expression(), Type::Any(),
742 "expected stdlib function"));
743 if (computed_type_->IsFunction()) {
744 Type::FunctionType* fun_type = computed_type_->AsFunction();
745 ZoneList<Expression*>* args = expr->arguments();
746 if (fun_type->Arity() != args->length())
747 FAIL(expr, "call with wrong arity");
748 for (int i = 0; i < args->length(); ++i) {
749 Expression* arg = args->at(i);
750 RECURSE(VisitWithExpectation(
751 arg, fun_type->Parameter(i),
752 "constructor argument expected to match callee parameter"));
754 IntersectResult(expr, fun_type->Result());
758 FAIL(expr, "ill-typed new operator");
762 void AsmTyper::VisitCallRuntime(CallRuntime* expr) {
763 // Allow runtime calls for now.
767 void AsmTyper::VisitUnaryOperation(UnaryOperation* expr) {
768 switch (expr->op()) {
769 case Token::NOT: // Used to encode != and !==
770 RECURSE(VisitWithExpectation(expr->expression(), cache_.kInt32,
771 "operand expected to be integer"));
772 IntersectResult(expr, cache_.kInt32);
775 FAIL(expr, "delete operator encountered");
777 FAIL(expr, "void operator encountered");
779 FAIL(expr, "typeof operator encountered");
786 void AsmTyper::VisitCountOperation(CountOperation* expr) {
787 FAIL(expr, "increment or decrement operator encountered");
791 void AsmTyper::VisitBinaryOperation(BinaryOperation* expr) {
792 switch (expr->op()) {
794 RECURSE(VisitWithExpectation(expr->left(), Type::Any(),
795 "left comma operand expected to be any"));
796 RECURSE(VisitWithExpectation(expr->right(), Type::Any(),
797 "right comma operand expected to be any"));
798 IntersectResult(expr, computed_type_);
803 FAIL(expr, "logical operator encountered");
810 // BIT_OR allows Any since it is used as a type coercion.
811 // BIT_XOR allows Number since it is used as a type coercion (encoding ~).
813 expr->op() == Token::BIT_OR
815 : expr->op() == Token::BIT_XOR ? Type::Number() : cache_.kInt32;
817 expr->op() == Token::SHR ? Type::Unsigned32() : cache_.kInt32;
818 RECURSE(VisitWithExpectation(expr->left(), expectation,
819 "left bit operand expected to be integer"));
820 int left_intish = intish_;
821 RECURSE(VisitWithExpectation(expr->right(), expectation,
822 "right bit operand expected to be integer"));
823 int right_intish = intish_;
824 if (left_intish > kMaxUncombinedAdditiveSteps) {
825 FAIL(expr, "too many consecutive additive ops");
827 if (right_intish > kMaxUncombinedAdditiveSteps) {
828 FAIL(expr, "too many consecutive additive ops");
831 IntersectResult(expr, result);
839 RECURSE(VisitWithExpectation(
840 expr->left(), Type::Number(),
841 "left arithmetic operand expected to be number"));
842 Type* left_type = computed_type_;
843 int left_intish = intish_;
844 RECURSE(VisitWithExpectation(
845 expr->right(), Type::Number(),
846 "right arithmetic operand expected to be number"));
847 Type* right_type = computed_type_;
848 int right_intish = intish_;
849 Type* type = Type::Union(left_type, right_type, zone());
850 if (type->Is(cache_.kInt32)) {
851 if (expr->op() == Token::MUL) {
852 if (!expr->left()->IsLiteral() && !expr->right()->IsLiteral()) {
853 FAIL(expr, "direct integer multiply forbidden");
856 IntersectResult(expr, cache_.kInt32);
859 intish_ = left_intish + right_intish + 1;
860 if (expr->op() == Token::ADD || expr->op() == Token::SUB) {
861 if (intish_ > kMaxUncombinedAdditiveSteps) {
862 FAIL(expr, "too many consecutive additive ops");
865 if (intish_ > kMaxUncombinedMultiplicativeSteps) {
866 FAIL(expr, "too many consecutive multiplicative ops");
869 IntersectResult(expr, cache_.kInt32);
872 } else if (type->Is(Type::Number())) {
873 IntersectResult(expr, cache_.kFloat64);
876 FAIL(expr, "ill-typed arithmetic operation");
885 void AsmTyper::VisitCompareOperation(CompareOperation* expr) {
887 VisitWithExpectation(expr->left(), Type::Number(),
888 "left comparison operand expected to be number"));
889 Type* left_type = computed_type_;
891 VisitWithExpectation(expr->right(), Type::Number(),
892 "right comparison operand expected to be number"));
893 Type* right_type = computed_type_;
894 Type* type = Type::Union(left_type, right_type, zone());
895 expr->set_combined_type(type);
896 if (type->Is(Type::Integral32()) || type->Is(Type::UntaggedFloat64())) {
897 IntersectResult(expr, cache_.kInt32);
899 FAIL(expr, "ill-typed comparison operation");
904 void AsmTyper::VisitThisFunction(ThisFunction* expr) {
905 FAIL(expr, "this function not allowed");
909 void AsmTyper::VisitDeclarations(ZoneList<Declaration*>* decls) {
910 for (int i = 0; i < decls->length(); ++i) {
911 Declaration* decl = decls->at(i);
912 RECURSE(Visit(decl));
917 void AsmTyper::VisitImportDeclaration(ImportDeclaration* decl) {
918 FAIL(decl, "import declaration encountered");
922 void AsmTyper::VisitExportDeclaration(ExportDeclaration* decl) {
923 FAIL(decl, "export declaration encountered");
927 void AsmTyper::VisitClassLiteral(ClassLiteral* expr) {
928 FAIL(expr, "class literal not allowed");
932 void AsmTyper::VisitSpread(Spread* expr) { FAIL(expr, "spread not allowed"); }
935 void AsmTyper::VisitSuperPropertyReference(SuperPropertyReference* expr) {
936 FAIL(expr, "super property reference not allowed");
940 void AsmTyper::VisitSuperCallReference(SuperCallReference* expr) {
941 FAIL(expr, "call reference not allowed");
945 void AsmTyper::InitializeStdlib() {
946 Type* number_type = Type::Number(zone());
947 Type* double_type = cache_.kFloat64;
948 Type* double_fn1_type = Type::Function(double_type, double_type, zone());
949 Type* double_fn2_type =
950 Type::Function(double_type, double_type, double_type, zone());
952 Type* fround_type = Type::Function(cache_.kFloat32, number_type, zone());
954 Type::Function(cache_.kInt32, cache_.kInt32, cache_.kInt32, zone());
955 // TODO(bradnelson): currently only approximating the proper intersection type
956 // (which we cannot currently represent).
957 Type* abs_type = Type::Function(number_type, number_type, zone());
964 const Assignment math[] = {
965 {"PI", double_type}, {"E", double_type},
966 {"LN2", double_type}, {"LN10", double_type},
967 {"LOG2E", double_type}, {"LOG10E", double_type},
968 {"SQRT2", double_type}, {"SQRT1_2", double_type},
969 {"imul", imul_type}, {"abs", abs_type},
970 {"ceil", double_fn1_type}, {"floor", double_fn1_type},
971 {"fround", fround_type}, {"pow", double_fn2_type},
972 {"exp", double_fn1_type}, {"log", double_fn1_type},
973 {"min", double_fn2_type}, {"max", double_fn2_type},
974 {"sqrt", double_fn1_type}, {"cos", double_fn1_type},
975 {"sin", double_fn1_type}, {"tan", double_fn1_type},
976 {"acos", double_fn1_type}, {"asin", double_fn1_type},
977 {"atan", double_fn1_type}, {"atan2", double_fn2_type}};
978 for (unsigned i = 0; i < arraysize(math); ++i) {
979 stdlib_math_types_[math[i].name] = math[i].type;
982 stdlib_types_["Infinity"] = double_type;
983 stdlib_types_["NaN"] = double_type;
984 Type* buffer_type = Type::Any(zone());
985 #define TYPED_ARRAY(TypeName, type_name, TYPE_NAME, ctype, size) \
986 stdlib_types_[#TypeName "Array"] = \
987 Type::Function(cache_.k##TypeName##Array, buffer_type, zone());
988 TYPED_ARRAYS(TYPED_ARRAY)
991 #define TYPED_ARRAY(TypeName, type_name, TYPE_NAME, ctype, size) \
992 stdlib_heap_types_[#TypeName "Array"] = \
993 Type::Function(cache_.k##TypeName##Array, buffer_type, zone());
994 TYPED_ARRAYS(TYPED_ARRAY)
999 Type* AsmTyper::LibType(ObjectTypeMap map, Handle<String> name) {
1000 base::SmartArrayPointer<char> aname = name->ToCString();
1001 ObjectTypeMap::iterator i = map.find(std::string(aname.get()));
1002 if (i == map.end()) {
1009 void AsmTyper::SetType(Variable* variable, Type* type) {
1010 ZoneHashMap::Entry* entry;
1012 entry = local_variable_type_.LookupOrInsert(
1013 variable, ComputePointerHash(variable), ZoneAllocationPolicy(zone()));
1015 entry = global_variable_type_.LookupOrInsert(
1016 variable, ComputePointerHash(variable), ZoneAllocationPolicy(zone()));
1018 entry->value = reinterpret_cast<void*>(type);
1022 Type* AsmTyper::GetType(Variable* variable) {
1023 i::ZoneHashMap::Entry* entry = NULL;
1025 entry = local_variable_type_.Lookup(variable, ComputePointerHash(variable));
1027 if (entry == NULL) {
1029 global_variable_type_.Lookup(variable, ComputePointerHash(variable));
1031 if (entry == NULL) {
1034 return reinterpret_cast<Type*>(entry->value);
1039 void AsmTyper::SetResult(Expression* expr, Type* type) {
1040 computed_type_ = type;
1041 expr->set_bounds(Bounds(computed_type_));
1045 void AsmTyper::IntersectResult(Expression* expr, Type* type) {
1046 computed_type_ = type;
1047 Type* bounded_type = Type::Intersect(computed_type_, expected_type_, zone());
1048 expr->set_bounds(Bounds(bounded_type));
1052 void AsmTyper::VisitWithExpectation(Expression* expr, Type* expected_type,
1054 Type* save = expected_type_;
1055 expected_type_ = expected_type;
1056 RECURSE(Visit(expr));
1057 Type* bounded_type = Type::Intersect(computed_type_, expected_type_, zone());
1058 if (bounded_type->Is(Type::None(zone()))) {
1060 PrintF("Computed type: ");
1061 computed_type_->Print();
1062 PrintF("Expected type: ");
1063 expected_type_->Print();
1067 expected_type_ = save;
1070 } // namespace v8::internal