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 if (bounds_.get(expr).upper->Is(Type::None())) { | |
ahaas
2016/05/25 10:09:11
You could just write
DCHECK(bounds_.get(expr).uppe
bradn
2016/05/25 16:26:49
Done.
| |
721 DCHECK(false); | |
722 } | |
720 } | 723 } |
721 | 724 |
722 | 725 |
723 void AsmTyper::VisitYield(Yield* expr) { | 726 void AsmTyper::VisitYield(Yield* expr) { |
724 FAIL(expr, "yield expression encountered"); | 727 FAIL(expr, "yield expression encountered"); |
725 } | 728 } |
726 | 729 |
727 | 730 |
728 void AsmTyper::VisitThrow(Throw* expr) { | 731 void AsmTyper::VisitThrow(Throw* expr) { |
729 FAIL(expr, "throw statement encountered"); | 732 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"); | 772 // FAIL(right, "call mask must be integer"); |
770 // } | 773 // } |
771 // RECURSE(VisitWithExpectation(bin->right(), cache_.kAsmSigned, | 774 // RECURSE(VisitWithExpectation(bin->right(), cache_.kAsmSigned, |
772 // "call mask expected to be integer")); | 775 // "call mask expected to be integer")); |
773 // if (static_cast<size_t>(right->raw_value()->AsNumber()) != size - 1) { | 776 // if (static_cast<size_t>(right->raw_value()->AsNumber()) != size - 1) { |
774 // FAIL(right, "call mask must match function table"); | 777 // FAIL(right, "call mask must match function table"); |
775 // } | 778 // } |
776 // bin->set_bounds(Bounds(cache_.kAsmSigned)); | 779 // bin->set_bounds(Bounds(cache_.kAsmSigned)); |
777 RECURSE(VisitWithExpectation(expr->key(), cache_.kAsmSigned, | 780 RECURSE(VisitWithExpectation(expr->key(), cache_.kAsmSigned, |
778 "must be integer")); | 781 "must be integer")); |
779 IntersectResult(expr, type); | 782 RECURSE(IntersectResult(expr, type)); |
780 } else { | 783 } else { |
781 Literal* literal = expr->key()->AsLiteral(); | 784 Literal* literal = expr->key()->AsLiteral(); |
782 if (literal) { | 785 if (literal) { |
783 RECURSE(VisitWithExpectation(literal, cache_.kAsmSigned, | 786 RECURSE(VisitWithExpectation(literal, cache_.kAsmSigned, |
784 "array index expected to be integer")); | 787 "array index expected to be integer")); |
785 } else { | 788 } else { |
786 int expected_shift = ElementShiftSize(type); | 789 int expected_shift = ElementShiftSize(type); |
787 if (expected_shift == 0) { | 790 if (expected_shift == 0) { |
788 RECURSE(Visit(expr->key())); | 791 RECURSE(Visit(expr->key())); |
789 } else { | 792 } else { |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
828 } | 831 } |
829 intish_ = 0; | 832 intish_ = 0; |
830 } else { | 833 } else { |
831 UNREACHABLE(); | 834 UNREACHABLE(); |
832 } | 835 } |
833 if (assigning) { | 836 if (assigning) { |
834 if (!assignment_type->Is(result_type)) { | 837 if (!assignment_type->Is(result_type)) { |
835 FAIL(expr, "illegal type in assignment"); | 838 FAIL(expr, "illegal type in assignment"); |
836 } | 839 } |
837 } else { | 840 } else { |
838 IntersectResult(expr, expected_type_); | 841 RECURSE(IntersectResult(expr, expected_type_)); |
839 IntersectResult(expr, result_type); | 842 RECURSE(IntersectResult(expr, result_type)); |
840 } | 843 } |
841 } | 844 } |
842 } | 845 } |
843 | 846 |
844 | 847 |
845 bool AsmTyper::IsStdlibObject(Expression* expr) { | 848 bool AsmTyper::IsStdlibObject(Expression* expr) { |
846 VariableProxy* proxy = expr->AsVariableProxy(); | 849 VariableProxy* proxy = expr->AsVariableProxy(); |
847 if (proxy == nullptr) { | 850 if (proxy == nullptr) { |
848 return false; | 851 return false; |
849 } | 852 } |
(...skipping 177 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1027 if (!computed_type_->Is(cache_.kAsmSigned) && | 1030 if (!computed_type_->Is(cache_.kAsmSigned) && |
1028 !computed_type_->Is(cache_.kAsmFixnum) && | 1031 !computed_type_->Is(cache_.kAsmFixnum) && |
1029 !computed_type_->Is(cache_.kAsmDouble)) { | 1032 !computed_type_->Is(cache_.kAsmDouble)) { |
1030 FAIL(arg, | 1033 FAIL(arg, |
1031 "foreign call argument expected to be int, double, or fixnum"); | 1034 "foreign call argument expected to be int, double, or fixnum"); |
1032 } | 1035 } |
1033 } | 1036 } |
1034 intish_ = 0; | 1037 intish_ = 0; |
1035 bounds_.set(expr->expression(), | 1038 bounds_.set(expr->expression(), |
1036 Bounds(Type::Function(Type::Any(), zone()))); | 1039 Bounds(Type::Function(Type::Any(), zone()))); |
1037 IntersectResult(expr, expected_type); | 1040 RECURSE(IntersectResult(expr, expected_type)); |
1038 } else { | 1041 } else { |
1039 if (fun_type->Arity() != args->length()) { | 1042 if (fun_type->Arity() != args->length()) { |
1040 FAIL(expr, "call with wrong arity"); | 1043 FAIL(expr, "call with wrong arity"); |
1041 } | 1044 } |
1042 for (int i = 0; i < args->length(); ++i) { | 1045 for (int i = 0; i < args->length(); ++i) { |
1043 Expression* arg = args->at(i); | 1046 Expression* arg = args->at(i); |
1044 RECURSE(VisitWithExpectation( | 1047 RECURSE(VisitWithExpectation( |
1045 arg, fun_type->Parameter(i), | 1048 arg, fun_type->Parameter(i), |
1046 "call argument expected to match callee parameter")); | 1049 "call argument expected to match callee parameter")); |
1047 if (standard_member != kNone && standard_member != kMathFround && | 1050 if (standard_member != kNone && standard_member != kMathFround && |
1048 i == 0) { | 1051 i == 0) { |
1049 result_type = computed_type_; | 1052 result_type = computed_type_; |
1050 } | 1053 } |
1051 } | 1054 } |
1052 RECURSE(CheckPolymorphicStdlibArguments(standard_member, args)); | 1055 RECURSE(CheckPolymorphicStdlibArguments(standard_member, args)); |
1053 intish_ = 0; | 1056 intish_ = 0; |
1054 IntersectResult(expr, result_type); | 1057 RECURSE(IntersectResult(expr, result_type)); |
1055 } | 1058 } |
1056 } else { | 1059 } else { |
1057 FAIL(expr, "invalid callee"); | 1060 FAIL(expr, "invalid callee"); |
1058 } | 1061 } |
1059 } | 1062 } |
1060 | 1063 |
1061 | 1064 |
1062 void AsmTyper::VisitCallNew(CallNew* expr) { | 1065 void AsmTyper::VisitCallNew(CallNew* expr) { |
1063 if (in_function_) { | 1066 if (in_function_) { |
1064 FAIL(expr, "new not allowed in module function"); | 1067 FAIL(expr, "new not allowed in module function"); |
1065 } | 1068 } |
1066 RECURSE(VisitWithExpectation(expr->expression(), Type::Any(), | 1069 RECURSE(VisitWithExpectation(expr->expression(), Type::Any(), |
1067 "expected stdlib function")); | 1070 "expected stdlib function")); |
1068 if (computed_type_->IsFunction()) { | 1071 if (computed_type_->IsFunction()) { |
1069 FunctionType* fun_type = computed_type_->AsFunction(); | 1072 FunctionType* fun_type = computed_type_->AsFunction(); |
1070 ZoneList<Expression*>* args = expr->arguments(); | 1073 ZoneList<Expression*>* args = expr->arguments(); |
1071 if (fun_type->Arity() != args->length()) | 1074 if (fun_type->Arity() != args->length()) |
1072 FAIL(expr, "call with wrong arity"); | 1075 FAIL(expr, "call with wrong arity"); |
1073 for (int i = 0; i < args->length(); ++i) { | 1076 for (int i = 0; i < args->length(); ++i) { |
1074 Expression* arg = args->at(i); | 1077 Expression* arg = args->at(i); |
1075 RECURSE(VisitWithExpectation( | 1078 RECURSE(VisitWithExpectation( |
1076 arg, fun_type->Parameter(i), | 1079 arg, fun_type->Parameter(i), |
1077 "constructor argument expected to match callee parameter")); | 1080 "constructor argument expected to match callee parameter")); |
1078 } | 1081 } |
1079 IntersectResult(expr, fun_type->Result()); | 1082 RECURSE(IntersectResult(expr, fun_type->Result())); |
1080 return; | 1083 return; |
1081 } | 1084 } |
1082 | 1085 |
1083 FAIL(expr, "ill-typed new operator"); | 1086 FAIL(expr, "ill-typed new operator"); |
1084 } | 1087 } |
1085 | 1088 |
1086 | 1089 |
1087 void AsmTyper::VisitCallRuntime(CallRuntime* expr) { | 1090 void AsmTyper::VisitCallRuntime(CallRuntime* expr) { |
1088 FAIL(expr, "runtime call not allowed"); | 1091 FAIL(expr, "runtime call not allowed"); |
1089 } | 1092 } |
1090 | 1093 |
1091 | 1094 |
1092 void AsmTyper::VisitUnaryOperation(UnaryOperation* expr) { | 1095 void AsmTyper::VisitUnaryOperation(UnaryOperation* expr) { |
1093 if (!in_function_) { | 1096 if (!in_function_) { |
1094 FAIL(expr, "unary operator inside module body"); | 1097 FAIL(expr, "unary operator inside module body"); |
1095 } | 1098 } |
1096 switch (expr->op()) { | 1099 switch (expr->op()) { |
1097 case Token::NOT: // Used to encode != and !== | 1100 case Token::NOT: // Used to encode != and !== |
1098 RECURSE(VisitWithExpectation(expr->expression(), cache_.kAsmInt, | 1101 RECURSE(VisitWithExpectation(expr->expression(), cache_.kAsmInt, |
1099 "operand expected to be integer")); | 1102 "operand expected to be integer")); |
1100 IntersectResult(expr, cache_.kAsmSigned); | 1103 RECURSE(IntersectResult(expr, cache_.kAsmSigned)); |
1101 return; | 1104 return; |
1102 case Token::DELETE: | 1105 case Token::DELETE: |
1103 FAIL(expr, "delete operator encountered"); | 1106 FAIL(expr, "delete operator encountered"); |
1104 case Token::VOID: | 1107 case Token::VOID: |
1105 FAIL(expr, "void operator encountered"); | 1108 FAIL(expr, "void operator encountered"); |
1106 case Token::TYPEOF: | 1109 case Token::TYPEOF: |
1107 FAIL(expr, "typeof operator encountered"); | 1110 FAIL(expr, "typeof operator encountered"); |
1108 default: | 1111 default: |
1109 UNREACHABLE(); | 1112 UNREACHABLE(); |
1110 } | 1113 } |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1149 left_type = right_type; | 1152 left_type = right_type; |
1150 } | 1153 } |
1151 if (right_type->Is(cache_.kAsmFixnum) && left_type->Is(cache_.kAsmInt)) { | 1154 if (right_type->Is(cache_.kAsmFixnum) && left_type->Is(cache_.kAsmInt)) { |
1152 right_type = left_type; | 1155 right_type = left_type; |
1153 } | 1156 } |
1154 if (!conversion) { | 1157 if (!conversion) { |
1155 if (!left_type->Is(cache_.kAsmIntQ) || !right_type->Is(cache_.kAsmIntQ)) { | 1158 if (!left_type->Is(cache_.kAsmIntQ) || !right_type->Is(cache_.kAsmIntQ)) { |
1156 FAIL(expr, "ill-typed bitwise operation"); | 1159 FAIL(expr, "ill-typed bitwise operation"); |
1157 } | 1160 } |
1158 } | 1161 } |
1159 IntersectResult(expr, result_type); | 1162 RECURSE(IntersectResult(expr, result_type)); |
1160 } | 1163 } |
1161 | 1164 |
1162 | 1165 |
1163 void AsmTyper::VisitBinaryOperation(BinaryOperation* expr) { | 1166 void AsmTyper::VisitBinaryOperation(BinaryOperation* expr) { |
1164 if (!in_function_) { | 1167 if (!in_function_) { |
1165 if (expr->op() != Token::BIT_OR && expr->op() != Token::MUL) { | 1168 if (expr->op() != Token::BIT_OR && expr->op() != Token::MUL) { |
1166 FAIL(expr, "illegal binary operator inside module body"); | 1169 FAIL(expr, "illegal binary operator inside module body"); |
1167 } | 1170 } |
1168 if (!(expr->left()->IsProperty() || expr->left()->IsVariableProxy()) || | 1171 if (!(expr->left()->IsProperty() || expr->left()->IsVariableProxy()) || |
1169 !expr->right()->IsLiteral()) { | 1172 !expr->right()->IsLiteral()) { |
(...skipping 11 matching lines...) Expand all Loading... | |
1181 FAIL(expr, "illegal double annotation value"); | 1184 FAIL(expr, "illegal double annotation value"); |
1182 } | 1185 } |
1183 } | 1186 } |
1184 } | 1187 } |
1185 switch (expr->op()) { | 1188 switch (expr->op()) { |
1186 case Token::COMMA: { | 1189 case Token::COMMA: { |
1187 RECURSE(VisitWithExpectation(expr->left(), Type::Any(), | 1190 RECURSE(VisitWithExpectation(expr->left(), Type::Any(), |
1188 "left comma operand expected to be any")); | 1191 "left comma operand expected to be any")); |
1189 RECURSE(VisitWithExpectation(expr->right(), Type::Any(), | 1192 RECURSE(VisitWithExpectation(expr->right(), Type::Any(), |
1190 "right comma operand expected to be any")); | 1193 "right comma operand expected to be any")); |
1191 IntersectResult(expr, computed_type_); | 1194 RECURSE(IntersectResult(expr, computed_type_)); |
1192 return; | 1195 return; |
1193 } | 1196 } |
1194 case Token::OR: | 1197 case Token::OR: |
1195 case Token::AND: | 1198 case Token::AND: |
1196 FAIL(expr, "illegal logical operator"); | 1199 FAIL(expr, "illegal logical operator"); |
1197 case Token::BIT_OR: { | 1200 case Token::BIT_OR: { |
1198 // BIT_OR allows Any since it is used as a type coercion. | 1201 // BIT_OR allows Any since it is used as a type coercion. |
1199 RECURSE(VisitIntegerBitwiseOperator(expr, Type::Any(), cache_.kAsmIntQ, | 1202 RECURSE(VisitIntegerBitwiseOperator(expr, Type::Any(), cache_.kAsmIntQ, |
1200 cache_.kAsmSigned, true)); | 1203 cache_.kAsmSigned, true)); |
1201 if (expr->left()->IsCall() && expr->op() == Token::BIT_OR && | 1204 if (expr->left()->IsCall() && expr->op() == Token::BIT_OR && |
1202 Type::Number()->Is(bounds_.get(expr->left()).upper)) { | 1205 Type::Number()->Is(bounds_.get(expr->left()).upper)) { |
1203 // Force the return types of foreign functions. | 1206 // Force the return types of foreign functions. |
1204 bounds_.set(expr->left(), Bounds(cache_.kAsmSigned)); | 1207 bounds_.set(expr->left(), Bounds(cache_.kAsmSigned)); |
1205 } | 1208 } |
1206 if (in_function_ && | 1209 if (in_function_ && |
1207 !bounds_.get(expr->left()).upper->Is(cache_.kAsmIntQ)) { | 1210 !bounds_.get(expr->left()).upper->Is(cache_.kAsmIntQ)) { |
1208 FAIL(expr->left(), "intish required"); | 1211 FAIL(expr->left(), "intish required"); |
1209 } | 1212 } |
1210 return; | 1213 return; |
1211 } | 1214 } |
1212 case Token::BIT_XOR: { | 1215 case Token::BIT_XOR: { |
1213 // Handle booleans specially to handle de-sugared ! | 1216 // Handle booleans specially to handle de-sugared ! |
1214 Literal* left = expr->left()->AsLiteral(); | 1217 Literal* left = expr->left()->AsLiteral(); |
1215 if (left && left->value()->IsBoolean()) { | 1218 if (left && left->value()->IsBoolean()) { |
1216 if (left->ToBooleanIsTrue()) { | 1219 if (left->ToBooleanIsTrue()) { |
1217 bounds_.set(left, Bounds(cache_.kSingletonOne)); | 1220 bounds_.set(left, Bounds(cache_.kSingletonOne)); |
1218 RECURSE(VisitWithExpectation(expr->right(), cache_.kAsmIntQ, | 1221 RECURSE(VisitWithExpectation(expr->right(), cache_.kAsmIntQ, |
1219 "not operator expects an integer")); | 1222 "not operator expects an integer")); |
1220 IntersectResult(expr, cache_.kAsmSigned); | 1223 RECURSE(IntersectResult(expr, cache_.kAsmSigned)); |
1221 return; | 1224 return; |
1222 } else { | 1225 } else { |
1223 FAIL(left, "unexpected false"); | 1226 FAIL(left, "unexpected false"); |
1224 } | 1227 } |
1225 } | 1228 } |
1226 // BIT_XOR allows Any since it is used as a type coercion (via ~~). | 1229 // BIT_XOR allows Any since it is used as a type coercion (via ~~). |
1227 RECURSE(VisitIntegerBitwiseOperator(expr, Type::Any(), cache_.kAsmIntQ, | 1230 RECURSE(VisitIntegerBitwiseOperator(expr, Type::Any(), cache_.kAsmIntQ, |
1228 cache_.kAsmSigned, true)); | 1231 cache_.kAsmSigned, true)); |
1229 return; | 1232 return; |
1230 } | 1233 } |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1272 FAIL(expr, "intish not allowed in multiply"); | 1275 FAIL(expr, "intish not allowed in multiply"); |
1273 } | 1276 } |
1274 } else { | 1277 } else { |
1275 FAIL(expr, "multiply must be by an integer literal"); | 1278 FAIL(expr, "multiply must be by an integer literal"); |
1276 } | 1279 } |
1277 i = abs(i); | 1280 i = abs(i); |
1278 if (i >= (1 << 20)) { | 1281 if (i >= (1 << 20)) { |
1279 FAIL(expr, "multiply must be by value in -2^20 < n < 2^20"); | 1282 FAIL(expr, "multiply must be by value in -2^20 < n < 2^20"); |
1280 } | 1283 } |
1281 intish_ = i; | 1284 intish_ = i; |
1282 IntersectResult(expr, cache_.kAsmInt); | 1285 RECURSE(IntersectResult(expr, cache_.kAsmInt)); |
1283 return; | 1286 return; |
1284 } else { | 1287 } else { |
1285 intish_ = left_intish + right_intish + 1; | 1288 intish_ = left_intish + right_intish + 1; |
1286 if (expr->op() == Token::ADD || expr->op() == Token::SUB) { | 1289 if (expr->op() == Token::ADD || expr->op() == Token::SUB) { |
1287 if (intish_ > kMaxUncombinedAdditiveSteps) { | 1290 if (intish_ > kMaxUncombinedAdditiveSteps) { |
1288 FAIL(expr, "too many consecutive additive ops"); | 1291 FAIL(expr, "too many consecutive additive ops"); |
1289 } | 1292 } |
1290 } else { | 1293 } else { |
1291 if (intish_ > kMaxUncombinedMultiplicativeSteps) { | 1294 if (intish_ > kMaxUncombinedMultiplicativeSteps) { |
1292 FAIL(expr, "too many consecutive multiplicative ops"); | 1295 FAIL(expr, "too many consecutive multiplicative ops"); |
1293 } | 1296 } |
1294 } | 1297 } |
1295 IntersectResult(expr, cache_.kAsmInt); | 1298 RECURSE(IntersectResult(expr, cache_.kAsmInt)); |
1296 return; | 1299 return; |
1297 } | 1300 } |
1298 } else if (expr->op() == Token::MUL && expr->right()->IsLiteral() && | 1301 } else if (expr->op() == Token::MUL && expr->right()->IsLiteral() && |
1299 right_type->Is(cache_.kAsmDouble) && | 1302 right_type->Is(cache_.kAsmDouble) && |
1300 expr->right()->AsLiteral()->raw_value()->ContainsDot() && | 1303 expr->right()->AsLiteral()->raw_value()->ContainsDot() && |
1301 expr->right()->AsLiteral()->raw_value()->AsNumber() == 1.0) { | 1304 expr->right()->AsLiteral()->raw_value()->AsNumber() == 1.0) { |
1302 // For unary +, expressed as x * 1.0 | 1305 // For unary +, expressed as x * 1.0 |
1303 if (expr->left()->IsCall() && | 1306 if (expr->left()->IsCall() && |
1304 Type::Number()->Is(bounds_.get(expr->left()).upper)) { | 1307 Type::Number()->Is(bounds_.get(expr->left()).upper)) { |
1305 // Force the return types of foreign functions. | 1308 // Force the return types of foreign functions. |
1306 bounds_.set(expr->left(), Bounds(cache_.kAsmDouble)); | 1309 bounds_.set(expr->left(), Bounds(cache_.kAsmDouble)); |
1307 left_type = bounds_.get(expr->left()).upper; | 1310 left_type = bounds_.get(expr->left()).upper; |
1308 } | 1311 } |
1309 if (!(expr->left()->IsProperty() && | 1312 if (!(expr->left()->IsProperty() && |
1310 Type::Number()->Is(bounds_.get(expr->left()).upper))) { | 1313 Type::Number()->Is(bounds_.get(expr->left()).upper))) { |
1311 if (!left_type->Is(cache_.kAsmSigned) && | 1314 if (!left_type->Is(cache_.kAsmSigned) && |
1312 !left_type->Is(cache_.kAsmUnsigned) && | 1315 !left_type->Is(cache_.kAsmUnsigned) && |
1313 !left_type->Is(cache_.kAsmFixnum) && | 1316 !left_type->Is(cache_.kAsmFixnum) && |
1314 !left_type->Is(cache_.kAsmFloatQ) && | 1317 !left_type->Is(cache_.kAsmFloatQ) && |
1315 !left_type->Is(cache_.kAsmDoubleQ)) { | 1318 !left_type->Is(cache_.kAsmDoubleQ)) { |
1316 FAIL( | 1319 FAIL( |
1317 expr->left(), | 1320 expr->left(), |
1318 "unary + only allowed on signed, unsigned, float?, or double?"); | 1321 "unary + only allowed on signed, unsigned, float?, or double?"); |
1319 } | 1322 } |
1320 } | 1323 } |
1321 IntersectResult(expr, cache_.kAsmDouble); | 1324 RECURSE(IntersectResult(expr, cache_.kAsmDouble)); |
1322 return; | 1325 return; |
1323 } else if (expr->op() == Token::MUL && left_type->Is(cache_.kAsmDouble) && | 1326 } else if (expr->op() == Token::MUL && left_type->Is(cache_.kAsmDouble) && |
1324 expr->right()->IsLiteral() && | 1327 expr->right()->IsLiteral() && |
1325 !expr->right()->AsLiteral()->raw_value()->ContainsDot() && | 1328 !expr->right()->AsLiteral()->raw_value()->ContainsDot() && |
1326 expr->right()->AsLiteral()->raw_value()->AsNumber() == -1.0) { | 1329 expr->right()->AsLiteral()->raw_value()->AsNumber() == -1.0) { |
1327 // For unary -, expressed as x * -1 | 1330 // For unary -, expressed as x * -1 |
1328 bounds_.set(expr->right(), Bounds(cache_.kAsmDouble)); | 1331 bounds_.set(expr->right(), Bounds(cache_.kAsmDouble)); |
1329 IntersectResult(expr, cache_.kAsmDouble); | 1332 RECURSE(IntersectResult(expr, cache_.kAsmDouble)); |
1330 return; | 1333 return; |
1331 } else if (type->Is(cache_.kAsmFloat) && expr->op() != Token::MOD) { | 1334 } else if (type->Is(cache_.kAsmFloat) && expr->op() != Token::MOD) { |
1332 if (left_intish != 0 || right_intish != 0) { | 1335 if (left_intish != 0 || right_intish != 0) { |
1333 FAIL(expr, "float operation before required fround"); | 1336 FAIL(expr, "float operation before required fround"); |
1334 } | 1337 } |
1335 IntersectResult(expr, cache_.kAsmFloat); | 1338 RECURSE(IntersectResult(expr, cache_.kAsmFloat)); |
1336 intish_ = 1; | 1339 intish_ = 1; |
1337 return; | 1340 return; |
1338 } else if (type->Is(cache_.kAsmDouble)) { | 1341 } else if (type->Is(cache_.kAsmDouble)) { |
1339 IntersectResult(expr, cache_.kAsmDouble); | 1342 RECURSE(IntersectResult(expr, cache_.kAsmDouble)); |
1340 return; | 1343 return; |
1341 } else { | 1344 } else { |
1342 FAIL(expr, "ill-typed arithmetic operation"); | 1345 FAIL(expr, "ill-typed arithmetic operation"); |
1343 } | 1346 } |
1344 } | 1347 } |
1345 default: | 1348 default: |
1346 UNREACHABLE(); | 1349 UNREACHABLE(); |
1347 } | 1350 } |
1348 } | 1351 } |
1349 | 1352 |
(...skipping 21 matching lines...) Expand all Loading... | |
1371 "right comparison operand expected to be number")); | 1374 "right comparison operand expected to be number")); |
1372 Type* right_type = computed_type_; | 1375 Type* right_type = computed_type_; |
1373 if (!right_type->Is(cache_.kAsmComparable)) { | 1376 if (!right_type->Is(cache_.kAsmComparable)) { |
1374 FAIL(expr->right(), "bad type on right side of comparison"); | 1377 FAIL(expr->right(), "bad type on right side of comparison"); |
1375 } | 1378 } |
1376 | 1379 |
1377 if (!left_type->Is(right_type) && !right_type->Is(left_type)) { | 1380 if (!left_type->Is(right_type) && !right_type->Is(left_type)) { |
1378 FAIL(expr, "left and right side of comparison must match"); | 1381 FAIL(expr, "left and right side of comparison must match"); |
1379 } | 1382 } |
1380 | 1383 |
1381 IntersectResult(expr, cache_.kAsmSigned); | 1384 RECURSE(IntersectResult(expr, cache_.kAsmSigned)); |
1382 } | 1385 } |
1383 | 1386 |
1384 | 1387 |
1385 void AsmTyper::VisitThisFunction(ThisFunction* expr) { | 1388 void AsmTyper::VisitThisFunction(ThisFunction* expr) { |
1386 FAIL(expr, "this function not allowed"); | 1389 FAIL(expr, "this function not allowed"); |
1387 } | 1390 } |
1388 | 1391 |
1389 | 1392 |
1390 void AsmTyper::VisitDeclarations(ZoneList<Declaration*>* decls) { | 1393 void AsmTyper::VisitDeclarations(ZoneList<Declaration*>* decls) { |
1391 for (int i = 0; i < decls->length(); ++i) { | 1394 for (int i = 0; i < decls->length(); ++i) { |
(...skipping 199 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1591 | 1594 |
1592 void AsmTyper::SetResult(Expression* expr, Type* type) { | 1595 void AsmTyper::SetResult(Expression* expr, Type* type) { |
1593 computed_type_ = type; | 1596 computed_type_ = type; |
1594 bounds_.set(expr, Bounds(computed_type_)); | 1597 bounds_.set(expr, Bounds(computed_type_)); |
1595 } | 1598 } |
1596 | 1599 |
1597 | 1600 |
1598 void AsmTyper::IntersectResult(Expression* expr, Type* type) { | 1601 void AsmTyper::IntersectResult(Expression* expr, Type* type) { |
1599 computed_type_ = type; | 1602 computed_type_ = type; |
1600 Type* bounded_type = Type::Intersect(computed_type_, expected_type_, zone()); | 1603 Type* bounded_type = Type::Intersect(computed_type_, expected_type_, zone()); |
1604 if (bounded_type->Is(Type::None())) { | |
1605 #ifdef DEBUG | |
1606 PrintF("Computed type: "); | |
1607 computed_type_->Print(); | |
1608 PrintF("Expected type: "); | |
1609 expected_type_->Print(); | |
1610 #endif | |
1611 FAIL(expr, "type mismatch"); | |
1612 } | |
1601 bounds_.set(expr, Bounds(bounded_type)); | 1613 bounds_.set(expr, Bounds(bounded_type)); |
1602 } | 1614 } |
1603 | 1615 |
1604 | 1616 |
1605 void AsmTyper::VisitWithExpectation(Expression* expr, Type* expected_type, | 1617 void AsmTyper::VisitWithExpectation(Expression* expr, Type* expected_type, |
1606 const char* msg) { | 1618 const char* msg) { |
1607 Type* save = expected_type_; | 1619 Type* save = expected_type_; |
1608 expected_type_ = expected_type; | 1620 expected_type_ = expected_type; |
1609 RECURSE(Visit(expr)); | 1621 RECURSE(Visit(expr)); |
1610 Type* bounded_type = Type::Intersect(computed_type_, expected_type_, zone()); | 1622 Type* bounded_type = Type::Intersect(computed_type_, expected_type_, zone()); |
(...skipping 10 matching lines...) Expand all Loading... | |
1621 } | 1633 } |
1622 | 1634 |
1623 | 1635 |
1624 void AsmTyper::VisitRewritableExpression(RewritableExpression* expr) { | 1636 void AsmTyper::VisitRewritableExpression(RewritableExpression* expr) { |
1625 RECURSE(Visit(expr->expression())); | 1637 RECURSE(Visit(expr->expression())); |
1626 } | 1638 } |
1627 | 1639 |
1628 | 1640 |
1629 } // namespace internal | 1641 } // namespace internal |
1630 } // namespace v8 | 1642 } // namespace v8 |
OLD | NEW |