OLD | NEW |
1 // Copyright 2015 the V8 project authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/typing-asm.h" | 5 #include "src/typing-asm.h" |
6 | 6 |
7 #include <limits> | 7 #include <limits> |
8 | 8 |
9 #include "src/v8.h" | 9 #include "src/v8.h" |
10 | 10 |
(...skipping 490 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
501 | 501 |
502 Type* type = bounds_.get(expr).upper; | 502 Type* type = bounds_.get(expr).upper; |
503 Type* save_return_type = return_type_; | 503 Type* save_return_type = return_type_; |
504 return_type_ = type->AsFunction()->Result(); | 504 return_type_ = type->AsFunction()->Result(); |
505 in_function_ = true; | 505 in_function_ = true; |
506 local_variable_type_.Clear(); | 506 local_variable_type_.Clear(); |
507 RECURSE(VisitDeclarations(scope->declarations())); | 507 RECURSE(VisitDeclarations(scope->declarations())); |
508 RECURSE(VisitStatements(expr->body())); | 508 RECURSE(VisitStatements(expr->body())); |
509 in_function_ = false; | 509 in_function_ = false; |
510 return_type_ = save_return_type; | 510 return_type_ = save_return_type; |
511 IntersectResult(expr, type); | 511 RECURSE(IntersectResult(expr, type)); |
512 } | 512 } |
513 | 513 |
514 | 514 |
515 void AsmTyper::VisitNativeFunctionLiteral(NativeFunctionLiteral* expr) { | 515 void AsmTyper::VisitNativeFunctionLiteral(NativeFunctionLiteral* expr) { |
516 FAIL(expr, "function info literal encountered"); | 516 FAIL(expr, "function info literal encountered"); |
517 } | 517 } |
518 | 518 |
519 | 519 |
520 void AsmTyper::VisitDoExpression(DoExpression* expr) { | 520 void AsmTyper::VisitDoExpression(DoExpression* expr) { |
521 FAIL(expr, "do-expression encountered"); | 521 FAIL(expr, "do-expression encountered"); |
(...skipping 23 matching lines...) Expand all Loading... |
545 "conditional else branch type mismatch with enclosing expression")); | 545 "conditional else branch type mismatch with enclosing expression")); |
546 Type* else_type = StorageType(computed_type_); | 546 Type* else_type = StorageType(computed_type_); |
547 if (intish_ != 0 || !else_type->Is(cache_.kAsmComparable)) { | 547 if (intish_ != 0 || !else_type->Is(cache_.kAsmComparable)) { |
548 FAIL(expr->else_expression(), "invalid type in ? else expression"); | 548 FAIL(expr->else_expression(), "invalid type in ? else expression"); |
549 } | 549 } |
550 | 550 |
551 if (!then_type->Is(else_type) || !else_type->Is(then_type)) { | 551 if (!then_type->Is(else_type) || !else_type->Is(then_type)) { |
552 FAIL(expr, "then and else expressions in ? must have the same type"); | 552 FAIL(expr, "then and else expressions in ? must have the same type"); |
553 } | 553 } |
554 | 554 |
555 IntersectResult(expr, then_type); | 555 RECURSE(IntersectResult(expr, then_type)); |
556 } | 556 } |
557 | 557 |
558 | 558 |
559 void AsmTyper::VisitVariableProxy(VariableProxy* expr) { | 559 void AsmTyper::VisitVariableProxy(VariableProxy* expr) { |
560 Variable* var = expr->var(); | 560 Variable* var = expr->var(); |
561 VariableInfo* info = GetVariableInfo(var); | 561 VariableInfo* info = GetVariableInfo(var); |
562 if (!in_function_ && !building_function_tables_ && !visiting_exports_) { | 562 if (!in_function_ && !building_function_tables_ && !visiting_exports_) { |
563 if (var->location() != VariableLocation::PARAMETER || var->index() >= 3) { | 563 if (var->location() != VariableLocation::PARAMETER || var->index() >= 3) { |
564 FAIL(expr, "illegal variable reference in module body"); | 564 FAIL(expr, "illegal variable reference in module body"); |
565 } | 565 } |
566 } | 566 } |
567 if (info == nullptr || info->type == nullptr) { | 567 if (info == nullptr || info->type == nullptr) { |
568 if (var->mode() == TEMPORARY) { | 568 if (var->mode() == TEMPORARY) { |
569 SetType(var, Type::Any()); | 569 SetType(var, Type::Any()); |
570 info = GetVariableInfo(var); | 570 info = GetVariableInfo(var); |
571 } else { | 571 } else { |
572 FAIL(expr, "unbound variable"); | 572 FAIL(expr, "unbound variable"); |
573 } | 573 } |
574 } | 574 } |
575 if (property_info_ != nullptr) { | 575 if (property_info_ != nullptr) { |
576 SetVariableInfo(var, property_info_); | 576 SetVariableInfo(var, property_info_); |
577 property_info_ = nullptr; | 577 property_info_ = nullptr; |
578 } | 578 } |
579 Type* type = Type::Intersect(info->type, expected_type_, zone()); | 579 Type* type = Type::Intersect(info->type, expected_type_, zone()); |
580 if (type->Is(cache_.kAsmInt)) type = cache_.kAsmInt; | 580 if (type->Is(cache_.kAsmInt)) type = cache_.kAsmInt; |
581 intish_ = 0; | 581 intish_ = 0; |
582 IntersectResult(expr, type); | 582 RECURSE(IntersectResult(expr, type)); |
583 } | 583 } |
584 | 584 |
585 void AsmTyper::VisitLiteral(Literal* expr, bool is_return) { | 585 void AsmTyper::VisitLiteral(Literal* expr, bool is_return) { |
586 intish_ = 0; | 586 intish_ = 0; |
587 Handle<Object> value = expr->value(); | 587 Handle<Object> value = expr->value(); |
588 if (value->IsNumber()) { | 588 if (value->IsNumber()) { |
589 int32_t i; | 589 int32_t i; |
590 uint32_t u; | 590 uint32_t u; |
591 if (expr->raw_value()->ContainsDot()) { | 591 if (expr->raw_value()->ContainsDot()) { |
592 IntersectResult(expr, cache_.kAsmDouble); | 592 RECURSE(IntersectResult(expr, cache_.kAsmDouble)); |
593 } else if (!is_return && value->ToUint32(&u)) { | 593 } else if (!is_return && value->ToUint32(&u)) { |
594 if (u <= 0x7fffffff) { | 594 if (u <= 0x7fffffff) { |
595 IntersectResult(expr, cache_.kAsmFixnum); | 595 RECURSE(IntersectResult(expr, cache_.kAsmFixnum)); |
596 } else { | 596 } else { |
597 IntersectResult(expr, cache_.kAsmUnsigned); | 597 RECURSE(IntersectResult(expr, cache_.kAsmUnsigned)); |
598 } | 598 } |
599 } else if (value->ToInt32(&i)) { | 599 } else if (value->ToInt32(&i)) { |
600 IntersectResult(expr, cache_.kAsmSigned); | 600 RECURSE(IntersectResult(expr, cache_.kAsmSigned)); |
601 } else { | 601 } else { |
602 FAIL(expr, "illegal number"); | 602 FAIL(expr, "illegal number"); |
603 } | 603 } |
604 } else if (!is_return && value->IsString()) { | 604 } else if (!is_return && value->IsString()) { |
605 IntersectResult(expr, Type::String()); | 605 RECURSE(IntersectResult(expr, Type::String())); |
606 } else if (value->IsUndefined()) { | 606 } else if (value->IsUndefined()) { |
607 IntersectResult(expr, Type::Undefined()); | 607 RECURSE(IntersectResult(expr, Type::Undefined())); |
608 } else { | 608 } else { |
609 FAIL(expr, "illegal literal"); | 609 FAIL(expr, "illegal literal"); |
610 } | 610 } |
611 } | 611 } |
612 | 612 |
613 | 613 |
614 void AsmTyper::VisitLiteral(Literal* expr) { VisitLiteral(expr, false); } | 614 void AsmTyper::VisitLiteral(Literal* expr) { VisitLiteral(expr, false); } |
615 | 615 |
616 | 616 |
617 void AsmTyper::VisitRegExpLiteral(RegExpLiteral* expr) { | 617 void AsmTyper::VisitRegExpLiteral(RegExpLiteral* expr) { |
618 FAIL(expr, "regular expression encountered"); | 618 FAIL(expr, "regular expression encountered"); |
619 } | 619 } |
620 | 620 |
621 | 621 |
622 void AsmTyper::VisitObjectLiteral(ObjectLiteral* expr) { | 622 void AsmTyper::VisitObjectLiteral(ObjectLiteral* expr) { |
623 if (in_function_) { | 623 if (in_function_) { |
624 FAIL(expr, "object literal in function"); | 624 FAIL(expr, "object literal in function"); |
625 } | 625 } |
626 // Allowed for asm module's export declaration. | 626 // Allowed for asm module's export declaration. |
627 ZoneList<ObjectLiteralProperty*>* props = expr->properties(); | 627 ZoneList<ObjectLiteralProperty*>* props = expr->properties(); |
628 for (int i = 0; i < props->length(); ++i) { | 628 for (int i = 0; i < props->length(); ++i) { |
629 ObjectLiteralProperty* prop = props->at(i); | 629 ObjectLiteralProperty* prop = props->at(i); |
630 RECURSE(VisitWithExpectation(prop->value(), Type::Any(), | 630 RECURSE(VisitWithExpectation(prop->value(), Type::Any(), |
631 "object property expected to be a function")); | 631 "object property expected to be a function")); |
632 if (!computed_type_->IsFunction()) { | 632 if (!computed_type_->IsFunction()) { |
633 FAIL(prop->value(), "non-function in function table"); | 633 FAIL(prop->value(), "non-function in function table"); |
634 } | 634 } |
635 } | 635 } |
636 IntersectResult(expr, Type::Object()); | 636 RECURSE(IntersectResult(expr, Type::Object())); |
637 } | 637 } |
638 | 638 |
639 | 639 |
640 void AsmTyper::VisitArrayLiteral(ArrayLiteral* expr) { | 640 void AsmTyper::VisitArrayLiteral(ArrayLiteral* expr) { |
641 if (in_function_) { | 641 if (in_function_) { |
642 FAIL(expr, "array literal inside a function"); | 642 FAIL(expr, "array literal inside a function"); |
643 } | 643 } |
644 // Allowed for function tables. | 644 // Allowed for function tables. |
645 ZoneList<Expression*>* values = expr->values(); | 645 ZoneList<Expression*>* values = expr->values(); |
646 Type* elem_type = Type::None(); | 646 Type* elem_type = Type::None(); |
647 for (int i = 0; i < values->length(); ++i) { | 647 for (int i = 0; i < values->length(); ++i) { |
648 Expression* value = values->at(i); | 648 Expression* value = values->at(i); |
649 RECURSE(VisitWithExpectation(value, Type::Any(), "UNREACHABLE")); | 649 RECURSE(VisitWithExpectation(value, Type::Any(), "UNREACHABLE")); |
650 if (!computed_type_->IsFunction()) { | 650 if (!computed_type_->IsFunction()) { |
651 FAIL(value, "array component expected to be a function"); | 651 FAIL(value, "array component expected to be a function"); |
652 } | 652 } |
653 elem_type = Type::Union(elem_type, computed_type_, zone()); | 653 elem_type = Type::Union(elem_type, computed_type_, zone()); |
654 } | 654 } |
655 array_size_ = values->length(); | 655 array_size_ = values->length(); |
656 IntersectResult(expr, Type::Array(elem_type, zone())); | 656 RECURSE(IntersectResult(expr, Type::Array(elem_type, zone()))); |
657 } | 657 } |
658 | 658 |
659 | 659 |
660 void AsmTyper::VisitAssignment(Assignment* expr) { | 660 void AsmTyper::VisitAssignment(Assignment* expr) { |
661 // Handle function tables and everything else in different passes. | 661 // Handle function tables and everything else in different passes. |
662 if (!in_function_) { | 662 if (!in_function_) { |
663 if (expr->value()->IsArrayLiteral()) { | 663 if (expr->value()->IsArrayLiteral()) { |
664 if (!building_function_tables_) { | 664 if (!building_function_tables_) { |
665 return; | 665 return; |
666 } | 666 } |
(...skipping 27 matching lines...) Expand all Loading... |
694 } | 694 } |
695 } | 695 } |
696 if (property_info_ != nullptr) { | 696 if (property_info_ != nullptr) { |
697 SetVariableInfo(var, property_info_); | 697 SetVariableInfo(var, property_info_); |
698 property_info_ = nullptr; | 698 property_info_ = nullptr; |
699 } | 699 } |
700 Type* type = Type::Intersect(info->type, expected_type_, zone()); | 700 Type* type = Type::Intersect(info->type, expected_type_, zone()); |
701 if (type->Is(cache_.kAsmInt)) type = cache_.kAsmInt; | 701 if (type->Is(cache_.kAsmInt)) type = cache_.kAsmInt; |
702 info->type = type; | 702 info->type = type; |
703 intish_ = 0; | 703 intish_ = 0; |
704 IntersectResult(proxy, type); | 704 RECURSE(IntersectResult(proxy, type)); |
705 } else if (expr->target()->IsProperty()) { | 705 } else if (expr->target()->IsProperty()) { |
706 // Assignment to a property: should be a heap assignment {H[x] = y}. | 706 // Assignment to a property: should be a heap assignment {H[x] = y}. |
707 int32_t value_intish = intish_; | 707 int32_t value_intish = intish_; |
708 Property* property = expr->target()->AsProperty(); | 708 Property* property = expr->target()->AsProperty(); |
709 RECURSE(VisitWithExpectation(property->obj(), Type::Any(), | 709 RECURSE(VisitWithExpectation(property->obj(), Type::Any(), |
710 "bad propety object")); | 710 "bad propety object")); |
711 if (!computed_type_->IsArray()) { | 711 if (!computed_type_->IsArray()) { |
712 FAIL(property->obj(), "array expected"); | 712 FAIL(property->obj(), "array expected"); |
713 } | 713 } |
714 if (value_intish != 0 && computed_type_->Is(cache_.kFloat64Array)) { | 714 if (value_intish != 0 && computed_type_->Is(cache_.kFloat64Array)) { |
715 FAIL(expr, "floatish assignment to double array"); | 715 FAIL(expr, "floatish assignment to double array"); |
716 } | 716 } |
717 VisitHeapAccess(property, true, target_type); | 717 VisitHeapAccess(property, true, target_type); |
718 } | 718 } |
719 IntersectResult(expr, target_type); | 719 RECURSE(IntersectResult(expr, target_type)); |
720 } | 720 } |
721 | 721 |
722 | 722 |
723 void AsmTyper::VisitYield(Yield* expr) { | 723 void AsmTyper::VisitYield(Yield* expr) { |
724 FAIL(expr, "yield expression encountered"); | 724 FAIL(expr, "yield expression encountered"); |
725 } | 725 } |
726 | 726 |
727 | 727 |
728 void AsmTyper::VisitThrow(Throw* expr) { | 728 void AsmTyper::VisitThrow(Throw* expr) { |
729 FAIL(expr, "throw statement encountered"); | 729 FAIL(expr, "throw statement encountered"); |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
769 // FAIL(right, "call mask must be integer"); | 769 // FAIL(right, "call mask must be integer"); |
770 // } | 770 // } |
771 // RECURSE(VisitWithExpectation(bin->right(), cache_.kAsmSigned, | 771 // RECURSE(VisitWithExpectation(bin->right(), cache_.kAsmSigned, |
772 // "call mask expected to be integer")); | 772 // "call mask expected to be integer")); |
773 // if (static_cast<size_t>(right->raw_value()->AsNumber()) != size - 1) { | 773 // if (static_cast<size_t>(right->raw_value()->AsNumber()) != size - 1) { |
774 // FAIL(right, "call mask must match function table"); | 774 // FAIL(right, "call mask must match function table"); |
775 // } | 775 // } |
776 // bin->set_bounds(Bounds(cache_.kAsmSigned)); | 776 // bin->set_bounds(Bounds(cache_.kAsmSigned)); |
777 RECURSE(VisitWithExpectation(expr->key(), cache_.kAsmSigned, | 777 RECURSE(VisitWithExpectation(expr->key(), cache_.kAsmSigned, |
778 "must be integer")); | 778 "must be integer")); |
779 IntersectResult(expr, type); | 779 RECURSE(IntersectResult(expr, type)); |
780 } else { | 780 } else { |
781 Literal* literal = expr->key()->AsLiteral(); | 781 Literal* literal = expr->key()->AsLiteral(); |
782 if (literal) { | 782 if (literal) { |
783 RECURSE(VisitWithExpectation(literal, cache_.kAsmSigned, | 783 RECURSE(VisitWithExpectation(literal, cache_.kAsmSigned, |
784 "array index expected to be integer")); | 784 "array index expected to be integer")); |
785 } else { | 785 } else { |
786 int expected_shift = ElementShiftSize(type); | 786 int expected_shift = ElementShiftSize(type); |
787 if (expected_shift == 0) { | 787 if (expected_shift == 0) { |
788 RECURSE(Visit(expr->key())); | 788 RECURSE(Visit(expr->key())); |
789 } else { | 789 } else { |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
828 } | 828 } |
829 intish_ = 0; | 829 intish_ = 0; |
830 } else { | 830 } else { |
831 UNREACHABLE(); | 831 UNREACHABLE(); |
832 } | 832 } |
833 if (assigning) { | 833 if (assigning) { |
834 if (!assignment_type->Is(result_type)) { | 834 if (!assignment_type->Is(result_type)) { |
835 FAIL(expr, "illegal type in assignment"); | 835 FAIL(expr, "illegal type in assignment"); |
836 } | 836 } |
837 } else { | 837 } else { |
838 IntersectResult(expr, expected_type_); | 838 RECURSE(IntersectResult(expr, expected_type_)); |
839 IntersectResult(expr, result_type); | 839 RECURSE(IntersectResult(expr, result_type)); |
840 } | 840 } |
841 } | 841 } |
842 } | 842 } |
843 | 843 |
844 | 844 |
845 bool AsmTyper::IsStdlibObject(Expression* expr) { | 845 bool AsmTyper::IsStdlibObject(Expression* expr) { |
846 VariableProxy* proxy = expr->AsVariableProxy(); | 846 VariableProxy* proxy = expr->AsVariableProxy(); |
847 if (proxy == nullptr) { | 847 if (proxy == nullptr) { |
848 return false; | 848 return false; |
849 } | 849 } |
(...skipping 177 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1027 if (!computed_type_->Is(cache_.kAsmSigned) && | 1027 if (!computed_type_->Is(cache_.kAsmSigned) && |
1028 !computed_type_->Is(cache_.kAsmFixnum) && | 1028 !computed_type_->Is(cache_.kAsmFixnum) && |
1029 !computed_type_->Is(cache_.kAsmDouble)) { | 1029 !computed_type_->Is(cache_.kAsmDouble)) { |
1030 FAIL(arg, | 1030 FAIL(arg, |
1031 "foreign call argument expected to be int, double, or fixnum"); | 1031 "foreign call argument expected to be int, double, or fixnum"); |
1032 } | 1032 } |
1033 } | 1033 } |
1034 intish_ = 0; | 1034 intish_ = 0; |
1035 bounds_.set(expr->expression(), | 1035 bounds_.set(expr->expression(), |
1036 Bounds(Type::Function(Type::Any(), zone()))); | 1036 Bounds(Type::Function(Type::Any(), zone()))); |
1037 IntersectResult(expr, expected_type); | 1037 RECURSE(IntersectResult(expr, expected_type)); |
1038 } else { | 1038 } else { |
1039 if (fun_type->Arity() != args->length()) { | 1039 if (fun_type->Arity() != args->length()) { |
1040 FAIL(expr, "call with wrong arity"); | 1040 FAIL(expr, "call with wrong arity"); |
1041 } | 1041 } |
1042 for (int i = 0; i < args->length(); ++i) { | 1042 for (int i = 0; i < args->length(); ++i) { |
1043 Expression* arg = args->at(i); | 1043 Expression* arg = args->at(i); |
1044 RECURSE(VisitWithExpectation( | 1044 RECURSE(VisitWithExpectation( |
1045 arg, fun_type->Parameter(i), | 1045 arg, fun_type->Parameter(i), |
1046 "call argument expected to match callee parameter")); | 1046 "call argument expected to match callee parameter")); |
1047 if (standard_member != kNone && standard_member != kMathFround && | 1047 if (standard_member != kNone && standard_member != kMathFround && |
1048 i == 0) { | 1048 i == 0) { |
1049 result_type = computed_type_; | 1049 result_type = computed_type_; |
1050 } | 1050 } |
1051 } | 1051 } |
1052 RECURSE(CheckPolymorphicStdlibArguments(standard_member, args)); | 1052 RECURSE(CheckPolymorphicStdlibArguments(standard_member, args)); |
1053 intish_ = 0; | 1053 intish_ = 0; |
1054 IntersectResult(expr, result_type); | 1054 RECURSE(IntersectResult(expr, result_type)); |
1055 } | 1055 } |
1056 } else { | 1056 } else { |
1057 FAIL(expr, "invalid callee"); | 1057 FAIL(expr, "invalid callee"); |
1058 } | 1058 } |
1059 } | 1059 } |
1060 | 1060 |
1061 | 1061 |
1062 void AsmTyper::VisitCallNew(CallNew* expr) { | 1062 void AsmTyper::VisitCallNew(CallNew* expr) { |
1063 if (in_function_) { | 1063 if (in_function_) { |
1064 FAIL(expr, "new not allowed in module function"); | 1064 FAIL(expr, "new not allowed in module function"); |
1065 } | 1065 } |
1066 RECURSE(VisitWithExpectation(expr->expression(), Type::Any(), | 1066 RECURSE(VisitWithExpectation(expr->expression(), Type::Any(), |
1067 "expected stdlib function")); | 1067 "expected stdlib function")); |
1068 if (computed_type_->IsFunction()) { | 1068 if (computed_type_->IsFunction()) { |
1069 FunctionType* fun_type = computed_type_->AsFunction(); | 1069 FunctionType* fun_type = computed_type_->AsFunction(); |
1070 ZoneList<Expression*>* args = expr->arguments(); | 1070 ZoneList<Expression*>* args = expr->arguments(); |
1071 if (fun_type->Arity() != args->length()) | 1071 if (fun_type->Arity() != args->length()) |
1072 FAIL(expr, "call with wrong arity"); | 1072 FAIL(expr, "call with wrong arity"); |
1073 for (int i = 0; i < args->length(); ++i) { | 1073 for (int i = 0; i < args->length(); ++i) { |
1074 Expression* arg = args->at(i); | 1074 Expression* arg = args->at(i); |
1075 RECURSE(VisitWithExpectation( | 1075 RECURSE(VisitWithExpectation( |
1076 arg, fun_type->Parameter(i), | 1076 arg, fun_type->Parameter(i), |
1077 "constructor argument expected to match callee parameter")); | 1077 "constructor argument expected to match callee parameter")); |
1078 } | 1078 } |
1079 IntersectResult(expr, fun_type->Result()); | 1079 RECURSE(IntersectResult(expr, fun_type->Result())); |
1080 return; | 1080 return; |
1081 } | 1081 } |
1082 | 1082 |
1083 FAIL(expr, "ill-typed new operator"); | 1083 FAIL(expr, "ill-typed new operator"); |
1084 } | 1084 } |
1085 | 1085 |
1086 | 1086 |
1087 void AsmTyper::VisitCallRuntime(CallRuntime* expr) { | 1087 void AsmTyper::VisitCallRuntime(CallRuntime* expr) { |
1088 FAIL(expr, "runtime call not allowed"); | 1088 FAIL(expr, "runtime call not allowed"); |
1089 } | 1089 } |
1090 | 1090 |
1091 | 1091 |
1092 void AsmTyper::VisitUnaryOperation(UnaryOperation* expr) { | 1092 void AsmTyper::VisitUnaryOperation(UnaryOperation* expr) { |
1093 if (!in_function_) { | 1093 if (!in_function_) { |
1094 FAIL(expr, "unary operator inside module body"); | 1094 FAIL(expr, "unary operator inside module body"); |
1095 } | 1095 } |
1096 switch (expr->op()) { | 1096 switch (expr->op()) { |
1097 case Token::NOT: // Used to encode != and !== | 1097 case Token::NOT: // Used to encode != and !== |
1098 RECURSE(VisitWithExpectation(expr->expression(), cache_.kAsmInt, | 1098 RECURSE(VisitWithExpectation(expr->expression(), cache_.kAsmInt, |
1099 "operand expected to be integer")); | 1099 "operand expected to be integer")); |
1100 IntersectResult(expr, cache_.kAsmSigned); | 1100 RECURSE(IntersectResult(expr, cache_.kAsmSigned)); |
1101 return; | 1101 return; |
1102 case Token::DELETE: | 1102 case Token::DELETE: |
1103 FAIL(expr, "delete operator encountered"); | 1103 FAIL(expr, "delete operator encountered"); |
1104 case Token::VOID: | 1104 case Token::VOID: |
1105 FAIL(expr, "void operator encountered"); | 1105 FAIL(expr, "void operator encountered"); |
1106 case Token::TYPEOF: | 1106 case Token::TYPEOF: |
1107 FAIL(expr, "typeof operator encountered"); | 1107 FAIL(expr, "typeof operator encountered"); |
1108 default: | 1108 default: |
1109 UNREACHABLE(); | 1109 UNREACHABLE(); |
1110 } | 1110 } |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1149 left_type = right_type; | 1149 left_type = right_type; |
1150 } | 1150 } |
1151 if (right_type->Is(cache_.kAsmFixnum) && left_type->Is(cache_.kAsmInt)) { | 1151 if (right_type->Is(cache_.kAsmFixnum) && left_type->Is(cache_.kAsmInt)) { |
1152 right_type = left_type; | 1152 right_type = left_type; |
1153 } | 1153 } |
1154 if (!conversion) { | 1154 if (!conversion) { |
1155 if (!left_type->Is(cache_.kAsmIntQ) || !right_type->Is(cache_.kAsmIntQ)) { | 1155 if (!left_type->Is(cache_.kAsmIntQ) || !right_type->Is(cache_.kAsmIntQ)) { |
1156 FAIL(expr, "ill-typed bitwise operation"); | 1156 FAIL(expr, "ill-typed bitwise operation"); |
1157 } | 1157 } |
1158 } | 1158 } |
1159 IntersectResult(expr, result_type); | 1159 RECURSE(IntersectResult(expr, result_type)); |
1160 } | 1160 } |
1161 | 1161 |
1162 | 1162 |
1163 void AsmTyper::VisitBinaryOperation(BinaryOperation* expr) { | 1163 void AsmTyper::VisitBinaryOperation(BinaryOperation* expr) { |
1164 if (!in_function_) { | 1164 if (!in_function_) { |
1165 if (expr->op() != Token::BIT_OR && expr->op() != Token::MUL) { | 1165 if (expr->op() != Token::BIT_OR && expr->op() != Token::MUL) { |
1166 FAIL(expr, "illegal binary operator inside module body"); | 1166 FAIL(expr, "illegal binary operator inside module body"); |
1167 } | 1167 } |
1168 if (!(expr->left()->IsProperty() || expr->left()->IsVariableProxy()) || | 1168 if (!(expr->left()->IsProperty() || expr->left()->IsVariableProxy()) || |
1169 !expr->right()->IsLiteral()) { | 1169 !expr->right()->IsLiteral()) { |
(...skipping 11 matching lines...) Expand all Loading... |
1181 FAIL(expr, "illegal double annotation value"); | 1181 FAIL(expr, "illegal double annotation value"); |
1182 } | 1182 } |
1183 } | 1183 } |
1184 } | 1184 } |
1185 switch (expr->op()) { | 1185 switch (expr->op()) { |
1186 case Token::COMMA: { | 1186 case Token::COMMA: { |
1187 RECURSE(VisitWithExpectation(expr->left(), Type::Any(), | 1187 RECURSE(VisitWithExpectation(expr->left(), Type::Any(), |
1188 "left comma operand expected to be any")); | 1188 "left comma operand expected to be any")); |
1189 RECURSE(VisitWithExpectation(expr->right(), Type::Any(), | 1189 RECURSE(VisitWithExpectation(expr->right(), Type::Any(), |
1190 "right comma operand expected to be any")); | 1190 "right comma operand expected to be any")); |
1191 IntersectResult(expr, computed_type_); | 1191 RECURSE(IntersectResult(expr, computed_type_)); |
1192 return; | 1192 return; |
1193 } | 1193 } |
1194 case Token::OR: | 1194 case Token::OR: |
1195 case Token::AND: | 1195 case Token::AND: |
1196 FAIL(expr, "illegal logical operator"); | 1196 FAIL(expr, "illegal logical operator"); |
1197 case Token::BIT_OR: { | 1197 case Token::BIT_OR: { |
1198 // BIT_OR allows Any since it is used as a type coercion. | 1198 // BIT_OR allows Any since it is used as a type coercion. |
1199 RECURSE(VisitIntegerBitwiseOperator(expr, Type::Any(), cache_.kAsmIntQ, | 1199 RECURSE(VisitIntegerBitwiseOperator(expr, Type::Any(), cache_.kAsmIntQ, |
1200 cache_.kAsmSigned, true)); | 1200 cache_.kAsmSigned, true)); |
1201 if (expr->left()->IsCall() && expr->op() == Token::BIT_OR && | 1201 if (expr->left()->IsCall() && expr->op() == Token::BIT_OR && |
1202 Type::Number()->Is(bounds_.get(expr->left()).upper)) { | 1202 Type::Number()->Is(bounds_.get(expr->left()).upper)) { |
1203 // Force the return types of foreign functions. | 1203 // Force the return types of foreign functions. |
1204 bounds_.set(expr->left(), Bounds(cache_.kAsmSigned)); | 1204 bounds_.set(expr->left(), Bounds(cache_.kAsmSigned)); |
1205 } | 1205 } |
1206 if (in_function_ && | 1206 if (in_function_ && |
1207 !bounds_.get(expr->left()).upper->Is(cache_.kAsmIntQ)) { | 1207 !bounds_.get(expr->left()).upper->Is(cache_.kAsmIntQ)) { |
1208 FAIL(expr->left(), "intish required"); | 1208 FAIL(expr->left(), "intish required"); |
1209 } | 1209 } |
1210 return; | 1210 return; |
1211 } | 1211 } |
1212 case Token::BIT_XOR: { | 1212 case Token::BIT_XOR: { |
1213 // Handle booleans specially to handle de-sugared ! | 1213 // Handle booleans specially to handle de-sugared ! |
1214 Literal* left = expr->left()->AsLiteral(); | 1214 Literal* left = expr->left()->AsLiteral(); |
1215 if (left && left->value()->IsBoolean()) { | 1215 if (left && left->value()->IsBoolean()) { |
1216 if (left->ToBooleanIsTrue()) { | 1216 if (left->ToBooleanIsTrue()) { |
1217 bounds_.set(left, Bounds(cache_.kSingletonOne)); | 1217 bounds_.set(left, Bounds(cache_.kSingletonOne)); |
1218 RECURSE(VisitWithExpectation(expr->right(), cache_.kAsmIntQ, | 1218 RECURSE(VisitWithExpectation(expr->right(), cache_.kAsmIntQ, |
1219 "not operator expects an integer")); | 1219 "not operator expects an integer")); |
1220 IntersectResult(expr, cache_.kAsmSigned); | 1220 RECURSE(IntersectResult(expr, cache_.kAsmSigned)); |
1221 return; | 1221 return; |
1222 } else { | 1222 } else { |
1223 FAIL(left, "unexpected false"); | 1223 FAIL(left, "unexpected false"); |
1224 } | 1224 } |
1225 } | 1225 } |
1226 // BIT_XOR allows Any since it is used as a type coercion (via ~~). | 1226 // BIT_XOR allows Any since it is used as a type coercion (via ~~). |
1227 RECURSE(VisitIntegerBitwiseOperator(expr, Type::Any(), cache_.kAsmIntQ, | 1227 RECURSE(VisitIntegerBitwiseOperator(expr, Type::Any(), cache_.kAsmIntQ, |
1228 cache_.kAsmSigned, true)); | 1228 cache_.kAsmSigned, true)); |
1229 return; | 1229 return; |
1230 } | 1230 } |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1272 FAIL(expr, "intish not allowed in multiply"); | 1272 FAIL(expr, "intish not allowed in multiply"); |
1273 } | 1273 } |
1274 } else { | 1274 } else { |
1275 FAIL(expr, "multiply must be by an integer literal"); | 1275 FAIL(expr, "multiply must be by an integer literal"); |
1276 } | 1276 } |
1277 i = abs(i); | 1277 i = abs(i); |
1278 if (i >= (1 << 20)) { | 1278 if (i >= (1 << 20)) { |
1279 FAIL(expr, "multiply must be by value in -2^20 < n < 2^20"); | 1279 FAIL(expr, "multiply must be by value in -2^20 < n < 2^20"); |
1280 } | 1280 } |
1281 intish_ = i; | 1281 intish_ = i; |
1282 IntersectResult(expr, cache_.kAsmInt); | 1282 RECURSE(IntersectResult(expr, cache_.kAsmInt)); |
1283 return; | 1283 return; |
1284 } else { | 1284 } else { |
1285 intish_ = left_intish + right_intish + 1; | 1285 intish_ = left_intish + right_intish + 1; |
1286 if (expr->op() == Token::ADD || expr->op() == Token::SUB) { | 1286 if (expr->op() == Token::ADD || expr->op() == Token::SUB) { |
1287 if (intish_ > kMaxUncombinedAdditiveSteps) { | 1287 if (intish_ > kMaxUncombinedAdditiveSteps) { |
1288 FAIL(expr, "too many consecutive additive ops"); | 1288 FAIL(expr, "too many consecutive additive ops"); |
1289 } | 1289 } |
1290 } else { | 1290 } else { |
1291 if (intish_ > kMaxUncombinedMultiplicativeSteps) { | 1291 if (intish_ > kMaxUncombinedMultiplicativeSteps) { |
1292 FAIL(expr, "too many consecutive multiplicative ops"); | 1292 FAIL(expr, "too many consecutive multiplicative ops"); |
1293 } | 1293 } |
1294 } | 1294 } |
1295 IntersectResult(expr, cache_.kAsmInt); | 1295 RECURSE(IntersectResult(expr, cache_.kAsmInt)); |
1296 return; | 1296 return; |
1297 } | 1297 } |
1298 } else if (expr->op() == Token::MUL && expr->right()->IsLiteral() && | 1298 } else if (expr->op() == Token::MUL && expr->right()->IsLiteral() && |
1299 right_type->Is(cache_.kAsmDouble) && | 1299 right_type->Is(cache_.kAsmDouble) && |
1300 expr->right()->AsLiteral()->raw_value()->ContainsDot() && | 1300 expr->right()->AsLiteral()->raw_value()->ContainsDot() && |
1301 expr->right()->AsLiteral()->raw_value()->AsNumber() == 1.0) { | 1301 expr->right()->AsLiteral()->raw_value()->AsNumber() == 1.0) { |
1302 // For unary +, expressed as x * 1.0 | 1302 // For unary +, expressed as x * 1.0 |
1303 if (expr->left()->IsCall() && | 1303 if (expr->left()->IsCall() && |
1304 Type::Number()->Is(bounds_.get(expr->left()).upper)) { | 1304 Type::Number()->Is(bounds_.get(expr->left()).upper)) { |
1305 // Force the return types of foreign functions. | 1305 // Force the return types of foreign functions. |
1306 bounds_.set(expr->left(), Bounds(cache_.kAsmDouble)); | 1306 bounds_.set(expr->left(), Bounds(cache_.kAsmDouble)); |
1307 left_type = bounds_.get(expr->left()).upper; | 1307 left_type = bounds_.get(expr->left()).upper; |
1308 } | 1308 } |
1309 if (!(expr->left()->IsProperty() && | 1309 if (!(expr->left()->IsProperty() && |
1310 Type::Number()->Is(bounds_.get(expr->left()).upper))) { | 1310 Type::Number()->Is(bounds_.get(expr->left()).upper))) { |
1311 if (!left_type->Is(cache_.kAsmSigned) && | 1311 if (!left_type->Is(cache_.kAsmSigned) && |
1312 !left_type->Is(cache_.kAsmUnsigned) && | 1312 !left_type->Is(cache_.kAsmUnsigned) && |
1313 !left_type->Is(cache_.kAsmFixnum) && | 1313 !left_type->Is(cache_.kAsmFixnum) && |
1314 !left_type->Is(cache_.kAsmFloatQ) && | 1314 !left_type->Is(cache_.kAsmFloatQ) && |
1315 !left_type->Is(cache_.kAsmDoubleQ)) { | 1315 !left_type->Is(cache_.kAsmDoubleQ)) { |
1316 FAIL( | 1316 FAIL( |
1317 expr->left(), | 1317 expr->left(), |
1318 "unary + only allowed on signed, unsigned, float?, or double?"); | 1318 "unary + only allowed on signed, unsigned, float?, or double?"); |
1319 } | 1319 } |
1320 } | 1320 } |
1321 IntersectResult(expr, cache_.kAsmDouble); | 1321 RECURSE(IntersectResult(expr, cache_.kAsmDouble)); |
1322 return; | 1322 return; |
1323 } else if (expr->op() == Token::MUL && left_type->Is(cache_.kAsmDouble) && | 1323 } else if (expr->op() == Token::MUL && left_type->Is(cache_.kAsmDouble) && |
1324 expr->right()->IsLiteral() && | 1324 expr->right()->IsLiteral() && |
1325 !expr->right()->AsLiteral()->raw_value()->ContainsDot() && | 1325 !expr->right()->AsLiteral()->raw_value()->ContainsDot() && |
1326 expr->right()->AsLiteral()->raw_value()->AsNumber() == -1.0) { | 1326 expr->right()->AsLiteral()->raw_value()->AsNumber() == -1.0) { |
1327 // For unary -, expressed as x * -1 | 1327 // For unary -, expressed as x * -1 |
1328 bounds_.set(expr->right(), Bounds(cache_.kAsmDouble)); | 1328 bounds_.set(expr->right(), Bounds(cache_.kAsmDouble)); |
1329 IntersectResult(expr, cache_.kAsmDouble); | 1329 RECURSE(IntersectResult(expr, cache_.kAsmDouble)); |
1330 return; | 1330 return; |
1331 } else if (type->Is(cache_.kAsmFloat) && expr->op() != Token::MOD) { | 1331 } else if (type->Is(cache_.kAsmFloat) && expr->op() != Token::MOD) { |
1332 if (left_intish != 0 || right_intish != 0) { | 1332 if (left_intish != 0 || right_intish != 0) { |
1333 FAIL(expr, "float operation before required fround"); | 1333 FAIL(expr, "float operation before required fround"); |
1334 } | 1334 } |
1335 IntersectResult(expr, cache_.kAsmFloat); | 1335 RECURSE(IntersectResult(expr, cache_.kAsmFloat)); |
1336 intish_ = 1; | 1336 intish_ = 1; |
1337 return; | 1337 return; |
1338 } else if (type->Is(cache_.kAsmDouble)) { | 1338 } else if (type->Is(cache_.kAsmDouble)) { |
1339 IntersectResult(expr, cache_.kAsmDouble); | 1339 RECURSE(IntersectResult(expr, cache_.kAsmDouble)); |
1340 return; | 1340 return; |
1341 } else { | 1341 } else { |
1342 FAIL(expr, "ill-typed arithmetic operation"); | 1342 FAIL(expr, "ill-typed arithmetic operation"); |
1343 } | 1343 } |
1344 } | 1344 } |
1345 default: | 1345 default: |
1346 UNREACHABLE(); | 1346 UNREACHABLE(); |
1347 } | 1347 } |
1348 } | 1348 } |
1349 | 1349 |
(...skipping 21 matching lines...) Expand all Loading... |
1371 "right comparison operand expected to be number")); | 1371 "right comparison operand expected to be number")); |
1372 Type* right_type = computed_type_; | 1372 Type* right_type = computed_type_; |
1373 if (!right_type->Is(cache_.kAsmComparable)) { | 1373 if (!right_type->Is(cache_.kAsmComparable)) { |
1374 FAIL(expr->right(), "bad type on right side of comparison"); | 1374 FAIL(expr->right(), "bad type on right side of comparison"); |
1375 } | 1375 } |
1376 | 1376 |
1377 if (!left_type->Is(right_type) && !right_type->Is(left_type)) { | 1377 if (!left_type->Is(right_type) && !right_type->Is(left_type)) { |
1378 FAIL(expr, "left and right side of comparison must match"); | 1378 FAIL(expr, "left and right side of comparison must match"); |
1379 } | 1379 } |
1380 | 1380 |
1381 IntersectResult(expr, cache_.kAsmSigned); | 1381 RECURSE(IntersectResult(expr, cache_.kAsmSigned)); |
1382 } | 1382 } |
1383 | 1383 |
1384 | 1384 |
1385 void AsmTyper::VisitThisFunction(ThisFunction* expr) { | 1385 void AsmTyper::VisitThisFunction(ThisFunction* expr) { |
1386 FAIL(expr, "this function not allowed"); | 1386 FAIL(expr, "this function not allowed"); |
1387 } | 1387 } |
1388 | 1388 |
1389 | 1389 |
1390 void AsmTyper::VisitDeclarations(ZoneList<Declaration*>* decls) { | 1390 void AsmTyper::VisitDeclarations(ZoneList<Declaration*>* decls) { |
1391 for (int i = 0; i < decls->length(); ++i) { | 1391 for (int i = 0; i < decls->length(); ++i) { |
(...skipping 199 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1591 | 1591 |
1592 void AsmTyper::SetResult(Expression* expr, Type* type) { | 1592 void AsmTyper::SetResult(Expression* expr, Type* type) { |
1593 computed_type_ = type; | 1593 computed_type_ = type; |
1594 bounds_.set(expr, Bounds(computed_type_)); | 1594 bounds_.set(expr, Bounds(computed_type_)); |
1595 } | 1595 } |
1596 | 1596 |
1597 | 1597 |
1598 void AsmTyper::IntersectResult(Expression* expr, Type* type) { | 1598 void AsmTyper::IntersectResult(Expression* expr, Type* type) { |
1599 computed_type_ = type; | 1599 computed_type_ = type; |
1600 Type* bounded_type = Type::Intersect(computed_type_, expected_type_, zone()); | 1600 Type* bounded_type = Type::Intersect(computed_type_, expected_type_, zone()); |
| 1601 if (Type::Representation(bounded_type, zone())->Is(Type::None())) { |
| 1602 #ifdef DEBUG |
| 1603 PrintF("Computed type: "); |
| 1604 computed_type_->Print(); |
| 1605 PrintF("Expected type: "); |
| 1606 expected_type_->Print(); |
| 1607 #endif |
| 1608 FAIL(expr, "type mismatch"); |
| 1609 } |
1601 bounds_.set(expr, Bounds(bounded_type)); | 1610 bounds_.set(expr, Bounds(bounded_type)); |
1602 } | 1611 } |
1603 | 1612 |
1604 | 1613 |
1605 void AsmTyper::VisitWithExpectation(Expression* expr, Type* expected_type, | 1614 void AsmTyper::VisitWithExpectation(Expression* expr, Type* expected_type, |
1606 const char* msg) { | 1615 const char* msg) { |
1607 Type* save = expected_type_; | 1616 Type* save = expected_type_; |
1608 expected_type_ = expected_type; | 1617 expected_type_ = expected_type; |
1609 RECURSE(Visit(expr)); | 1618 RECURSE(Visit(expr)); |
1610 Type* bounded_type = Type::Intersect(computed_type_, expected_type_, zone()); | 1619 Type* bounded_type = Type::Intersect(computed_type_, expected_type_, zone()); |
1611 if (bounded_type->Is(Type::None())) { | 1620 if (Type::Representation(bounded_type, zone())->Is(Type::None())) { |
1612 #ifdef DEBUG | 1621 #ifdef DEBUG |
1613 PrintF("Computed type: "); | 1622 PrintF("Computed type: "); |
1614 computed_type_->Print(); | 1623 computed_type_->Print(); |
1615 PrintF("Expected type: "); | 1624 PrintF("Expected type: "); |
1616 expected_type_->Print(); | 1625 expected_type_->Print(); |
1617 #endif | 1626 #endif |
1618 FAIL(expr, msg); | 1627 FAIL(expr, msg); |
1619 } | 1628 } |
1620 expected_type_ = save; | 1629 expected_type_ = save; |
1621 } | 1630 } |
1622 | 1631 |
1623 | 1632 |
1624 void AsmTyper::VisitRewritableExpression(RewritableExpression* expr) { | 1633 void AsmTyper::VisitRewritableExpression(RewritableExpression* expr) { |
1625 RECURSE(Visit(expr->expression())); | 1634 RECURSE(Visit(expr->expression())); |
1626 } | 1635 } |
1627 | 1636 |
1628 | 1637 |
1629 } // namespace internal | 1638 } // namespace internal |
1630 } // namespace v8 | 1639 } // namespace v8 |
OLD | NEW |