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::VisitSloppyBlockFunctionStatement(
270 SloppyBlockFunctionStatement* stmt) {
271 Visit(stmt->statement());
275 void AsmTyper::VisitEmptyParentheses(EmptyParentheses* expr) { UNREACHABLE(); }
278 void AsmTyper::VisitIfStatement(IfStatement* stmt) {
280 FAIL(stmt, "if statement inside module body");
282 RECURSE(VisitWithExpectation(stmt->condition(), cache_.kInt32,
283 "if condition expected to be integer"));
284 RECURSE(Visit(stmt->then_statement()));
285 RECURSE(Visit(stmt->else_statement()));
289 void AsmTyper::VisitContinueStatement(ContinueStatement* stmt) {
291 FAIL(stmt, "continue statement inside module body");
296 void AsmTyper::VisitBreakStatement(BreakStatement* stmt) {
298 FAIL(stmt, "continue statement inside module body");
303 void AsmTyper::VisitReturnStatement(ReturnStatement* stmt) {
304 // Handle module return statement in VisitAsmModule.
309 VisitWithExpectation(stmt->expression(), return_type_,
310 "return expression expected to have return type"));
314 void AsmTyper::VisitWithStatement(WithStatement* stmt) {
315 FAIL(stmt, "bad with statement");
319 void AsmTyper::VisitSwitchStatement(SwitchStatement* stmt) {
321 FAIL(stmt, "switch statement inside module body");
323 RECURSE(VisitWithExpectation(stmt->tag(), cache_.kInt32,
324 "switch expression non-integer"));
325 ZoneList<CaseClause*>* clauses = stmt->cases();
326 for (int i = 0; i < clauses->length(); ++i) {
327 CaseClause* clause = clauses->at(i);
328 if (clause->is_default()) continue;
329 Expression* label = clause->label();
331 VisitWithExpectation(label, cache_.kInt32, "case label non-integer"));
332 if (!label->IsLiteral()) FAIL(label, "non-literal case label");
333 Handle<Object> value = label->AsLiteral()->value();
335 if (!value->ToInt32(&value32)) FAIL(label, "illegal case label value");
336 // TODO(bradnelson): Detect duplicates.
337 ZoneList<Statement*>* stmts = clause->statements();
338 RECURSE(VisitStatements(stmts));
343 void AsmTyper::VisitCaseClause(CaseClause* clause) { UNREACHABLE(); }
346 void AsmTyper::VisitDoWhileStatement(DoWhileStatement* stmt) {
348 FAIL(stmt, "do statement inside module body");
350 RECURSE(Visit(stmt->body()));
351 RECURSE(VisitWithExpectation(stmt->cond(), cache_.kInt32,
352 "do condition expected to be integer"));
356 void AsmTyper::VisitWhileStatement(WhileStatement* stmt) {
358 FAIL(stmt, "while statement inside module body");
360 RECURSE(VisitWithExpectation(stmt->cond(), cache_.kInt32,
361 "while condition expected to be integer"));
362 RECURSE(Visit(stmt->body()));
366 void AsmTyper::VisitForStatement(ForStatement* stmt) {
368 FAIL(stmt, "for statement inside module body");
370 if (stmt->init() != NULL) {
371 RECURSE(Visit(stmt->init()));
373 if (stmt->cond() != NULL) {
374 RECURSE(VisitWithExpectation(stmt->cond(), cache_.kInt32,
375 "for condition expected to be integer"));
377 if (stmt->next() != NULL) {
378 RECURSE(Visit(stmt->next()));
380 RECURSE(Visit(stmt->body()));
384 void AsmTyper::VisitForInStatement(ForInStatement* stmt) {
385 FAIL(stmt, "for-in statement encountered");
389 void AsmTyper::VisitForOfStatement(ForOfStatement* stmt) {
390 FAIL(stmt, "for-of statement encountered");
394 void AsmTyper::VisitTryCatchStatement(TryCatchStatement* stmt) {
395 FAIL(stmt, "try statement encountered");
399 void AsmTyper::VisitTryFinallyStatement(TryFinallyStatement* stmt) {
400 FAIL(stmt, "try statement encountered");
404 void AsmTyper::VisitDebuggerStatement(DebuggerStatement* stmt) {
405 FAIL(stmt, "debugger statement encountered");
409 void AsmTyper::VisitFunctionLiteral(FunctionLiteral* expr) {
410 Scope* scope = expr->scope();
411 DCHECK(scope->is_function_scope());
413 FAIL(expr, "invalid nested function");
416 if (!expr->bounds().upper->IsFunction()) {
417 FAIL(expr, "invalid function literal");
420 Type::FunctionType* type = expr->bounds().upper->AsFunction();
421 Type* save_return_type = return_type_;
422 return_type_ = type->Result();
424 local_variable_type_.Clear();
425 RECURSE(VisitDeclarations(scope->declarations()));
426 RECURSE(VisitStatements(expr->body()));
427 in_function_ = false;
428 return_type_ = save_return_type;
429 IntersectResult(expr, type);
433 void AsmTyper::VisitNativeFunctionLiteral(NativeFunctionLiteral* expr) {
434 FAIL(expr, "function info literal encountered");
438 void AsmTyper::VisitConditional(Conditional* expr) {
439 RECURSE(VisitWithExpectation(expr->condition(), cache_.kInt32,
440 "condition expected to be integer"));
441 RECURSE(VisitWithExpectation(
442 expr->then_expression(), expected_type_,
443 "conditional then branch type mismatch with enclosing expression"));
444 Type* then_type = computed_type_;
445 RECURSE(VisitWithExpectation(
446 expr->else_expression(), expected_type_,
447 "conditional else branch type mismatch with enclosing expression"));
448 Type* else_type = computed_type_;
449 Type* type = Type::Intersect(then_type, else_type, zone());
450 if (!(type->Is(cache_.kInt32) || type->Is(cache_.kFloat64))) {
451 FAIL(expr, "ill-typed conditional");
453 IntersectResult(expr, type);
457 void AsmTyper::VisitVariableProxy(VariableProxy* expr) {
458 Variable* var = expr->var();
459 if (GetType(var) == NULL) {
460 FAIL(expr, "unbound variable");
462 Type* type = Type::Intersect(GetType(var), expected_type_, zone());
463 if (type->Is(cache_.kInt32)) {
464 type = cache_.kInt32;
468 IntersectResult(expr, type);
472 void AsmTyper::VisitLiteral(Literal* expr) {
474 Handle<Object> value = expr->value();
475 if (value->IsNumber()) {
478 if (expr->raw_value()->ContainsDot()) {
479 IntersectResult(expr, cache_.kFloat64);
480 } else if (value->ToUint32(&u)) {
481 IntersectResult(expr, cache_.kInt32);
482 } else if (value->ToInt32(&i)) {
483 IntersectResult(expr, cache_.kInt32);
485 FAIL(expr, "illegal number");
487 } else if (value->IsString()) {
488 IntersectResult(expr, Type::String());
489 } else if (value->IsUndefined()) {
490 IntersectResult(expr, Type::Undefined());
492 FAIL(expr, "illegal literal");
497 void AsmTyper::VisitRegExpLiteral(RegExpLiteral* expr) {
498 FAIL(expr, "regular expression encountered");
502 void AsmTyper::VisitObjectLiteral(ObjectLiteral* expr) {
504 FAIL(expr, "object literal in function");
506 // Allowed for asm module's export declaration.
507 ZoneList<ObjectLiteralProperty*>* props = expr->properties();
508 for (int i = 0; i < props->length(); ++i) {
509 ObjectLiteralProperty* prop = props->at(i);
510 RECURSE(VisitWithExpectation(prop->value(), Type::Any(zone()),
511 "object property expected to be a function"));
512 if (!computed_type_->IsFunction()) {
513 FAIL(prop->value(), "non-function in function table");
516 IntersectResult(expr, Type::Object(zone()));
520 void AsmTyper::VisitArrayLiteral(ArrayLiteral* expr) {
522 FAIL(expr, "array literal inside a function");
524 // Allowed for function tables.
525 ZoneList<Expression*>* values = expr->values();
526 Type* elem_type = Type::None(zone());
527 for (int i = 0; i < values->length(); ++i) {
528 Expression* value = values->at(i);
529 RECURSE(VisitWithExpectation(value, Type::Any(), "UNREACHABLE"));
530 if (!computed_type_->IsFunction()) {
531 FAIL(value, "array component expected to be a function");
533 elem_type = Type::Union(elem_type, computed_type_, zone());
535 array_size_ = values->length();
536 IntersectResult(expr, Type::Array(elem_type, zone()));
540 void AsmTyper::VisitAssignment(Assignment* expr) {
541 // Handle function tables and everything else in different passes.
543 if (expr->value()->IsArrayLiteral()) {
544 if (!building_function_tables_) {
548 if (building_function_tables_) {
553 if (expr->is_compound()) FAIL(expr, "compound assignment encountered");
554 Type* type = expected_type_;
555 RECURSE(VisitWithExpectation(
556 expr->value(), type, "assignment value expected to match surrounding"));
558 FAIL(expr, "value still an intish");
560 RECURSE(VisitWithExpectation(expr->target(), computed_type_,
561 "assignment target expected to match value"));
563 FAIL(expr, "value still an intish");
565 IntersectResult(expr, computed_type_);
569 void AsmTyper::VisitYield(Yield* expr) {
570 FAIL(expr, "yield expression encountered");
574 void AsmTyper::VisitThrow(Throw* expr) {
575 FAIL(expr, "throw statement encountered");
579 int AsmTyper::ElementShiftSize(Type* type) {
580 if (type->Is(cache_.kInt8) || type->Is(cache_.kUint8)) return 0;
581 if (type->Is(cache_.kInt16) || type->Is(cache_.kUint16)) return 1;
582 if (type->Is(cache_.kInt32) || type->Is(cache_.kUint32) ||
583 type->Is(cache_.kFloat32))
585 if (type->Is(cache_.kFloat64)) return 3;
590 void AsmTyper::VisitHeapAccess(Property* expr) {
591 Type::ArrayType* array_type = computed_type_->AsArray();
592 size_t size = array_size_;
593 Type* type = array_type->AsArray()->Element();
594 if (type->IsFunction()) {
595 BinaryOperation* bin = expr->key()->AsBinaryOperation();
596 if (bin == NULL || bin->op() != Token::BIT_AND) {
597 FAIL(expr->key(), "expected & in call");
599 RECURSE(VisitWithExpectation(bin->left(), cache_.kInt32,
600 "array index expected to be integer"));
601 Literal* right = bin->right()->AsLiteral();
602 if (right == NULL || right->raw_value()->ContainsDot()) {
603 FAIL(right, "call mask must be integer");
605 RECURSE(VisitWithExpectation(bin->right(), cache_.kInt32,
606 "call mask expected to be integer"));
607 if (static_cast<size_t>(right->raw_value()->AsNumber()) != size - 1) {
608 FAIL(right, "call mask must match function table");
610 bin->set_bounds(Bounds(cache_.kInt32));
612 BinaryOperation* bin = expr->key()->AsBinaryOperation();
613 if (bin == NULL || bin->op() != Token::SAR) {
614 FAIL(expr->key(), "expected >> in heap access");
616 RECURSE(VisitWithExpectation(bin->left(), cache_.kInt32,
617 "array index expected to be integer"));
618 Literal* right = bin->right()->AsLiteral();
619 if (right == NULL || right->raw_value()->ContainsDot()) {
620 FAIL(right, "heap access shift must be integer");
622 RECURSE(VisitWithExpectation(bin->right(), cache_.kInt32,
623 "array shift expected to be integer"));
624 int n = static_cast<int>(right->raw_value()->AsNumber());
625 int expected_shift = ElementShiftSize(type);
626 if (expected_shift < 0 || n != expected_shift) {
627 FAIL(right, "heap access shift must match element size");
629 bin->set_bounds(Bounds(cache_.kInt32));
631 IntersectResult(expr, type);
635 void AsmTyper::VisitProperty(Property* expr) {
637 Property* inner_prop = expr->obj()->AsProperty();
638 if (inner_prop != NULL) {
639 // Get property name.
640 Literal* key = expr->key()->AsLiteral();
641 if (key == NULL || !key->IsPropertyName())
642 FAIL(expr, "invalid type annotation on property 2");
643 Handle<String> name = key->AsPropertyName();
645 // Check that inner property name is "Math".
646 Literal* math_key = inner_prop->key()->AsLiteral();
647 if (math_key == NULL || !math_key->IsPropertyName() ||
648 !math_key->AsPropertyName()->IsUtf8EqualTo(CStrVector("Math")))
649 FAIL(expr, "invalid type annotation on stdlib (a1)");
651 // Check that object is stdlib.
652 VariableProxy* proxy = inner_prop->obj()->AsVariableProxy();
653 if (proxy == NULL) FAIL(expr, "invalid type annotation on stdlib (a2)");
654 Variable* var = proxy->var();
655 if (var->location() != VariableLocation::PARAMETER || var->index() != 0)
656 FAIL(expr, "invalid type annotation on stdlib (a3)");
658 // Look up library type.
659 Type* type = LibType(stdlib_math_types_, name);
660 if (type == NULL) FAIL(expr, "unknown standard function 3 ");
661 SetResult(expr, type);
665 // Only recurse at this point so that we avoid needing
666 // stdlib.Math to have a real type.
667 RECURSE(VisitWithExpectation(expr->obj(), Type::Any(),
668 "property holder expected to be object"));
670 // For heap view or function table access.
671 if (computed_type_->IsArray()) {
672 VisitHeapAccess(expr);
676 // Get property name.
677 Literal* key = expr->key()->AsLiteral();
678 if (key == NULL || !key->IsPropertyName())
679 FAIL(expr, "invalid type annotation on property 3");
680 Handle<String> name = key->AsPropertyName();
682 // stdlib.x or foreign.x
683 VariableProxy* proxy = expr->obj()->AsVariableProxy();
685 Variable* var = proxy->var();
686 if (var->location() != VariableLocation::PARAMETER) {
687 FAIL(expr, "invalid type annotation on variable");
689 switch (var->index()) {
691 // Object is stdlib, look up library type.
692 Type* type = LibType(stdlib_types_, name);
694 FAIL(expr, "unknown standard function 4");
696 SetResult(expr, type);
700 // Object is foreign lib.
701 SetResult(expr, expected_type_);
704 FAIL(expr, "invalid type annotation on parameter");
708 FAIL(expr, "invalid property access");
712 void AsmTyper::VisitCall(Call* expr) {
713 RECURSE(VisitWithExpectation(expr->expression(), Type::Any(),
714 "callee expected to be any"));
715 if (computed_type_->IsFunction()) {
716 Type::FunctionType* fun_type = computed_type_->AsFunction();
717 ZoneList<Expression*>* args = expr->arguments();
718 if (fun_type->Arity() != args->length()) {
719 FAIL(expr, "call with wrong arity");
721 for (int i = 0; i < args->length(); ++i) {
722 Expression* arg = args->at(i);
723 RECURSE(VisitWithExpectation(
724 arg, fun_type->Parameter(i),
725 "call argument expected to match callee parameter"));
727 IntersectResult(expr, fun_type->Result());
728 } else if (computed_type_->Is(Type::Any())) {
729 // For foreign calls.
730 ZoneList<Expression*>* args = expr->arguments();
731 for (int i = 0; i < args->length(); ++i) {
732 Expression* arg = args->at(i);
733 RECURSE(VisitWithExpectation(arg, Type::Any(),
734 "foreign call argument expected to be any"));
736 IntersectResult(expr, Type::Number());
738 FAIL(expr, "invalid callee");
743 void AsmTyper::VisitCallNew(CallNew* expr) {
745 FAIL(expr, "new not allowed in module function");
747 RECURSE(VisitWithExpectation(expr->expression(), Type::Any(),
748 "expected stdlib function"));
749 if (computed_type_->IsFunction()) {
750 Type::FunctionType* fun_type = computed_type_->AsFunction();
751 ZoneList<Expression*>* args = expr->arguments();
752 if (fun_type->Arity() != args->length())
753 FAIL(expr, "call with wrong arity");
754 for (int i = 0; i < args->length(); ++i) {
755 Expression* arg = args->at(i);
756 RECURSE(VisitWithExpectation(
757 arg, fun_type->Parameter(i),
758 "constructor argument expected to match callee parameter"));
760 IntersectResult(expr, fun_type->Result());
764 FAIL(expr, "ill-typed new operator");
768 void AsmTyper::VisitCallRuntime(CallRuntime* expr) {
769 // Allow runtime calls for now.
773 void AsmTyper::VisitUnaryOperation(UnaryOperation* expr) {
774 switch (expr->op()) {
775 case Token::NOT: // Used to encode != and !==
776 RECURSE(VisitWithExpectation(expr->expression(), cache_.kInt32,
777 "operand expected to be integer"));
778 IntersectResult(expr, cache_.kInt32);
781 FAIL(expr, "delete operator encountered");
783 FAIL(expr, "void operator encountered");
785 FAIL(expr, "typeof operator encountered");
792 void AsmTyper::VisitCountOperation(CountOperation* expr) {
793 FAIL(expr, "increment or decrement operator encountered");
797 void AsmTyper::VisitBinaryOperation(BinaryOperation* expr) {
798 switch (expr->op()) {
800 RECURSE(VisitWithExpectation(expr->left(), Type::Any(),
801 "left comma operand expected to be any"));
802 RECURSE(VisitWithExpectation(expr->right(), Type::Any(),
803 "right comma operand expected to be any"));
804 IntersectResult(expr, computed_type_);
809 FAIL(expr, "logical operator encountered");
816 // BIT_OR allows Any since it is used as a type coercion.
817 // BIT_XOR allows Number since it is used as a type coercion (encoding ~).
819 expr->op() == Token::BIT_OR
821 : expr->op() == Token::BIT_XOR ? Type::Number() : cache_.kInt32;
823 expr->op() == Token::SHR ? Type::Unsigned32() : cache_.kInt32;
824 RECURSE(VisitWithExpectation(expr->left(), expectation,
825 "left bit operand expected to be integer"));
826 int left_intish = intish_;
827 RECURSE(VisitWithExpectation(expr->right(), expectation,
828 "right bit operand expected to be integer"));
829 int right_intish = intish_;
830 if (left_intish > kMaxUncombinedAdditiveSteps) {
831 FAIL(expr, "too many consecutive additive ops");
833 if (right_intish > kMaxUncombinedAdditiveSteps) {
834 FAIL(expr, "too many consecutive additive ops");
837 IntersectResult(expr, result);
845 RECURSE(VisitWithExpectation(
846 expr->left(), Type::Number(),
847 "left arithmetic operand expected to be number"));
848 Type* left_type = computed_type_;
849 int left_intish = intish_;
850 RECURSE(VisitWithExpectation(
851 expr->right(), Type::Number(),
852 "right arithmetic operand expected to be number"));
853 Type* right_type = computed_type_;
854 int right_intish = intish_;
855 Type* type = Type::Union(left_type, right_type, zone());
856 if (type->Is(cache_.kInt32)) {
857 if (expr->op() == Token::MUL) {
858 if (!expr->left()->IsLiteral() && !expr->right()->IsLiteral()) {
859 FAIL(expr, "direct integer multiply forbidden");
862 IntersectResult(expr, cache_.kInt32);
865 intish_ = left_intish + right_intish + 1;
866 if (expr->op() == Token::ADD || expr->op() == Token::SUB) {
867 if (intish_ > kMaxUncombinedAdditiveSteps) {
868 FAIL(expr, "too many consecutive additive ops");
871 if (intish_ > kMaxUncombinedMultiplicativeSteps) {
872 FAIL(expr, "too many consecutive multiplicative ops");
875 IntersectResult(expr, cache_.kInt32);
878 } else if (type->Is(Type::Number())) {
879 IntersectResult(expr, cache_.kFloat64);
882 FAIL(expr, "ill-typed arithmetic operation");
891 void AsmTyper::VisitCompareOperation(CompareOperation* expr) {
893 VisitWithExpectation(expr->left(), Type::Number(),
894 "left comparison operand expected to be number"));
895 Type* left_type = computed_type_;
897 VisitWithExpectation(expr->right(), Type::Number(),
898 "right comparison operand expected to be number"));
899 Type* right_type = computed_type_;
900 Type* type = Type::Union(left_type, right_type, zone());
901 expr->set_combined_type(type);
902 if (type->Is(Type::Integral32()) || type->Is(Type::UntaggedFloat64())) {
903 IntersectResult(expr, cache_.kInt32);
905 FAIL(expr, "ill-typed comparison operation");
910 void AsmTyper::VisitThisFunction(ThisFunction* expr) {
911 FAIL(expr, "this function not allowed");
915 void AsmTyper::VisitDeclarations(ZoneList<Declaration*>* decls) {
916 for (int i = 0; i < decls->length(); ++i) {
917 Declaration* decl = decls->at(i);
918 RECURSE(Visit(decl));
923 void AsmTyper::VisitImportDeclaration(ImportDeclaration* decl) {
924 FAIL(decl, "import declaration encountered");
928 void AsmTyper::VisitExportDeclaration(ExportDeclaration* decl) {
929 FAIL(decl, "export declaration encountered");
933 void AsmTyper::VisitClassLiteral(ClassLiteral* expr) {
934 FAIL(expr, "class literal not allowed");
938 void AsmTyper::VisitSpread(Spread* expr) { FAIL(expr, "spread not allowed"); }
941 void AsmTyper::VisitSuperPropertyReference(SuperPropertyReference* expr) {
942 FAIL(expr, "super property reference not allowed");
946 void AsmTyper::VisitSuperCallReference(SuperCallReference* expr) {
947 FAIL(expr, "call reference not allowed");
951 void AsmTyper::InitializeStdlib() {
952 Type* number_type = Type::Number(zone());
953 Type* double_type = cache_.kFloat64;
954 Type* double_fn1_type = Type::Function(double_type, double_type, zone());
955 Type* double_fn2_type =
956 Type::Function(double_type, double_type, double_type, zone());
958 Type* fround_type = Type::Function(cache_.kFloat32, number_type, zone());
960 Type::Function(cache_.kInt32, cache_.kInt32, cache_.kInt32, zone());
961 // TODO(bradnelson): currently only approximating the proper intersection type
962 // (which we cannot currently represent).
963 Type* abs_type = Type::Function(number_type, number_type, zone());
970 const Assignment math[] = {
971 {"PI", double_type}, {"E", double_type},
972 {"LN2", double_type}, {"LN10", double_type},
973 {"LOG2E", double_type}, {"LOG10E", double_type},
974 {"SQRT2", double_type}, {"SQRT1_2", double_type},
975 {"imul", imul_type}, {"abs", abs_type},
976 {"ceil", double_fn1_type}, {"floor", double_fn1_type},
977 {"fround", fround_type}, {"pow", double_fn2_type},
978 {"exp", double_fn1_type}, {"log", double_fn1_type},
979 {"min", double_fn2_type}, {"max", double_fn2_type},
980 {"sqrt", double_fn1_type}, {"cos", double_fn1_type},
981 {"sin", double_fn1_type}, {"tan", double_fn1_type},
982 {"acos", double_fn1_type}, {"asin", double_fn1_type},
983 {"atan", double_fn1_type}, {"atan2", double_fn2_type}};
984 for (unsigned i = 0; i < arraysize(math); ++i) {
985 stdlib_math_types_[math[i].name] = math[i].type;
988 stdlib_types_["Infinity"] = double_type;
989 stdlib_types_["NaN"] = double_type;
990 Type* buffer_type = Type::Any(zone());
991 #define TYPED_ARRAY(TypeName, type_name, TYPE_NAME, ctype, size) \
992 stdlib_types_[#TypeName "Array"] = \
993 Type::Function(cache_.k##TypeName##Array, buffer_type, zone());
994 TYPED_ARRAYS(TYPED_ARRAY)
997 #define TYPED_ARRAY(TypeName, type_name, TYPE_NAME, ctype, size) \
998 stdlib_heap_types_[#TypeName "Array"] = \
999 Type::Function(cache_.k##TypeName##Array, buffer_type, zone());
1000 TYPED_ARRAYS(TYPED_ARRAY)
1005 Type* AsmTyper::LibType(ObjectTypeMap map, Handle<String> name) {
1006 base::SmartArrayPointer<char> aname = name->ToCString();
1007 ObjectTypeMap::iterator i = map.find(std::string(aname.get()));
1008 if (i == map.end()) {
1015 void AsmTyper::SetType(Variable* variable, Type* type) {
1016 ZoneHashMap::Entry* entry;
1018 entry = local_variable_type_.LookupOrInsert(
1019 variable, ComputePointerHash(variable), ZoneAllocationPolicy(zone()));
1021 entry = global_variable_type_.LookupOrInsert(
1022 variable, ComputePointerHash(variable), ZoneAllocationPolicy(zone()));
1024 entry->value = reinterpret_cast<void*>(type);
1028 Type* AsmTyper::GetType(Variable* variable) {
1029 i::ZoneHashMap::Entry* entry = NULL;
1031 entry = local_variable_type_.Lookup(variable, ComputePointerHash(variable));
1033 if (entry == NULL) {
1035 global_variable_type_.Lookup(variable, ComputePointerHash(variable));
1037 if (entry == NULL) {
1040 return reinterpret_cast<Type*>(entry->value);
1045 void AsmTyper::SetResult(Expression* expr, Type* type) {
1046 computed_type_ = type;
1047 expr->set_bounds(Bounds(computed_type_));
1051 void AsmTyper::IntersectResult(Expression* expr, Type* type) {
1052 computed_type_ = type;
1053 Type* bounded_type = Type::Intersect(computed_type_, expected_type_, zone());
1054 expr->set_bounds(Bounds(bounded_type));
1058 void AsmTyper::VisitWithExpectation(Expression* expr, Type* expected_type,
1060 Type* save = expected_type_;
1061 expected_type_ = expected_type;
1062 RECURSE(Visit(expr));
1063 Type* bounded_type = Type::Intersect(computed_type_, expected_type_, zone());
1064 if (bounded_type->Is(Type::None(zone()))) {
1066 PrintF("Computed type: ");
1067 computed_type_->Print();
1068 PrintF("Expected type: ");
1069 expected_type_->Print();
1073 expected_type_ = save;
1076 } // namespace v8::internal