| 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 |