Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(319)

Side by Side Diff: src/typing-asm.cc

Issue 1471073003: Make typing-asm match spec more closely around load/store, add more tests. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: fix Created 5 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/typing-asm.h ('k') | test/cctest/expression-type-collector-macros.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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/v8.h" 5 #include "src/v8.h"
6 6
7 #include "src/typing-asm.h" 7 #include "src/typing-asm.h"
8 8
9 #include "src/ast.h" 9 #include "src/ast.h"
10 #include "src/codegen.h" 10 #include "src/codegen.h"
(...skipping 23 matching lines...) Expand all
34 if (!valid_) return; \ 34 if (!valid_) return; \
35 } while (false) 35 } while (false)
36 36
37 37
38 AsmTyper::AsmTyper(Isolate* isolate, Zone* zone, Script* script, 38 AsmTyper::AsmTyper(Isolate* isolate, Zone* zone, Script* script,
39 FunctionLiteral* root) 39 FunctionLiteral* root)
40 : zone_(zone), 40 : zone_(zone),
41 script_(script), 41 script_(script),
42 root_(root), 42 root_(root),
43 valid_(true), 43 valid_(true),
44 intish_(0),
45 assigning_(false),
44 stdlib_types_(zone), 46 stdlib_types_(zone),
45 stdlib_heap_types_(zone), 47 stdlib_heap_types_(zone),
46 stdlib_math_types_(zone), 48 stdlib_math_types_(zone),
47 global_variable_type_(HashMap::PointersMatch, 49 global_variable_type_(HashMap::PointersMatch,
48 ZoneHashMap::kDefaultHashMapCapacity, 50 ZoneHashMap::kDefaultHashMapCapacity,
49 ZoneAllocationPolicy(zone)), 51 ZoneAllocationPolicy(zone)),
50 local_variable_type_(HashMap::PointersMatch, 52 local_variable_type_(HashMap::PointersMatch,
51 ZoneHashMap::kDefaultHashMapCapacity, 53 ZoneHashMap::kDefaultHashMapCapacity,
52 ZoneAllocationPolicy(zone)), 54 ZoneAllocationPolicy(zone)),
53 in_function_(false), 55 in_function_(false),
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after
148 Type* result_type = Type::Undefined(zone()); 150 Type* result_type = Type::Undefined(zone());
149 if (body->length() > 0) { 151 if (body->length() > 0) {
150 ReturnStatement* stmt = body->last()->AsReturnStatement(); 152 ReturnStatement* stmt = body->last()->AsReturnStatement();
151 if (stmt != NULL) { 153 if (stmt != NULL) {
152 Literal* literal = stmt->expression()->AsLiteral(); 154 Literal* literal = stmt->expression()->AsLiteral();
153 Type* old_expected = expected_type_; 155 Type* old_expected = expected_type_;
154 expected_type_ = Type::Any(); 156 expected_type_ = Type::Any();
155 if (literal) { 157 if (literal) {
156 RECURSE(VisitLiteral(literal, true)); 158 RECURSE(VisitLiteral(literal, true));
157 } else { 159 } else {
158 RECURSE(VisitExpressionAnnotation(stmt->expression(), true)); 160 RECURSE(VisitExpressionAnnotation(stmt->expression(), NULL, true));
159 } 161 }
160 expected_type_ = old_expected; 162 expected_type_ = old_expected;
161 result_type = computed_type_; 163 result_type = computed_type_;
162 } 164 }
163 } 165 }
164 Type::FunctionType* type = 166 Type::FunctionType* type =
165 Type::Function(result_type, Type::Any(), fun->parameter_count(), zone()) 167 Type::Function(result_type, Type::Any(), fun->parameter_count(), zone())
166 ->AsFunction(); 168 ->AsFunction();
167 169
168 // Extract parameter types. 170 // Extract parameter types.
169 bool good = true; 171 bool good = true;
170 for (int i = 0; i < fun->parameter_count(); ++i) { 172 for (int i = 0; i < fun->parameter_count(); ++i) {
171 good = false; 173 good = false;
172 if (i >= body->length()) break; 174 if (i >= body->length()) break;
173 ExpressionStatement* stmt = body->at(i)->AsExpressionStatement(); 175 ExpressionStatement* stmt = body->at(i)->AsExpressionStatement();
174 if (stmt == NULL) break; 176 if (stmt == NULL) break;
175 Assignment* expr = stmt->expression()->AsAssignment(); 177 Assignment* expr = stmt->expression()->AsAssignment();
176 if (expr == NULL || expr->is_compound()) break; 178 if (expr == NULL || expr->is_compound()) break;
177 VariableProxy* proxy = expr->target()->AsVariableProxy(); 179 VariableProxy* proxy = expr->target()->AsVariableProxy();
178 if (proxy == NULL) break; 180 if (proxy == NULL) break;
179 Variable* var = proxy->var(); 181 Variable* var = proxy->var();
180 if (var->location() != VariableLocation::PARAMETER || var->index() != i) 182 if (var->location() != VariableLocation::PARAMETER || var->index() != i)
181 break; 183 break;
182 RECURSE(VisitExpressionAnnotation(expr->value(), false)); 184 RECURSE(VisitExpressionAnnotation(expr->value(), var, false));
183 SetType(var, computed_type_); 185 SetType(var, computed_type_);
184 type->InitParameter(i, computed_type_); 186 type->InitParameter(i, computed_type_);
185 good = true; 187 good = true;
186 } 188 }
187 if (!good) FAIL(fun, "missing parameter type annotations"); 189 if (!good) FAIL(fun, "missing parameter type annotations");
188 190
189 SetResult(fun, type); 191 SetResult(fun, type);
190 } 192 }
191 193
192 194
193 void AsmTyper::VisitExpressionAnnotation(Expression* expr, bool is_return) { 195 void AsmTyper::VisitExpressionAnnotation(Expression* expr, Variable* var,
196 bool is_return) {
194 // Normal +x or x|0 annotations. 197 // Normal +x or x|0 annotations.
195 BinaryOperation* bin = expr->AsBinaryOperation(); 198 BinaryOperation* bin = expr->AsBinaryOperation();
196 if (bin != NULL) { 199 if (bin != NULL) {
200 if (var != NULL) {
201 VariableProxy* left = bin->left()->AsVariableProxy();
202 if (!left) {
203 FAIL(expr, "variable name expected in type annotation");
204 }
205 if (left->var() != var) {
206 FAIL(left, "variable type annotation references other variable");
207 }
208 }
197 Literal* right = bin->right()->AsLiteral(); 209 Literal* right = bin->right()->AsLiteral();
198 if (right != NULL) { 210 if (right != NULL) {
199 switch (bin->op()) { 211 switch (bin->op()) {
200 case Token::MUL: // We encode +x as x*1.0 212 case Token::MUL: // We encode +x as x*1.0
201 if (right->raw_value()->ContainsDot() && 213 if (right->raw_value()->ContainsDot() &&
202 right->raw_value()->AsNumber() == 1.0) { 214 right->raw_value()->AsNumber() == 1.0) {
203 SetResult(expr, cache_.kAsmDouble); 215 SetResult(expr, cache_.kAsmDouble);
204 return; 216 return;
205 } 217 }
206 break; 218 break;
(...skipping 283 matching lines...) Expand 10 before | Expand all | Expand 10 after
490 Variable* var = expr->var(); 502 Variable* var = expr->var();
491 if (GetType(var) == NULL) { 503 if (GetType(var) == NULL) {
492 FAIL(expr, "unbound variable"); 504 FAIL(expr, "unbound variable");
493 } 505 }
494 Type* type = Type::Intersect(GetType(var), expected_type_, zone()); 506 Type* type = Type::Intersect(GetType(var), expected_type_, zone());
495 if (type->Is(cache_.kAsmInt)) { 507 if (type->Is(cache_.kAsmInt)) {
496 type = cache_.kAsmInt; 508 type = cache_.kAsmInt;
497 } 509 }
498 SetType(var, type); 510 SetType(var, type);
499 intish_ = 0; 511 intish_ = 0;
512 assigning_ = false;
500 IntersectResult(expr, type); 513 IntersectResult(expr, type);
501 } 514 }
502 515
503 516
504 void AsmTyper::VisitLiteral(Literal* expr, bool is_return) { 517 void AsmTyper::VisitLiteral(Literal* expr, bool is_return) {
505 intish_ = 0; 518 intish_ = 0;
506 Handle<Object> value = expr->value(); 519 Handle<Object> value = expr->value();
507 if (value->IsNumber()) { 520 if (value->IsNumber()) {
508 int32_t i; 521 int32_t i;
509 uint32_t u; 522 uint32_t u;
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after
586 } else { 599 } else {
587 if (building_function_tables_) { 600 if (building_function_tables_) {
588 return; 601 return;
589 } 602 }
590 } 603 }
591 } 604 }
592 if (expr->is_compound()) FAIL(expr, "compound assignment encountered"); 605 if (expr->is_compound()) FAIL(expr, "compound assignment encountered");
593 Type* type = expected_type_; 606 Type* type = expected_type_;
594 RECURSE(VisitWithExpectation( 607 RECURSE(VisitWithExpectation(
595 expr->value(), type, "assignment value expected to match surrounding")); 608 expr->value(), type, "assignment value expected to match surrounding"));
609 Type* target_type = StorageType(computed_type_);
596 if (intish_ != 0) { 610 if (intish_ != 0) {
597 FAIL(expr, "value still an intish"); 611 FAIL(expr, "intish or floatish assignment");
598 } 612 }
599 Type* target_type = computed_type_; 613 assigning_ = true;
titzer 2015/11/24 07:32:32 At first glance this follow a stack discipline, bu
bradn 2015/11/30 20:34:44 So it turns out the spec allows nested assignment,
600 if (target_type->Is(cache_.kAsmInt)) {
601 target_type = cache_.kAsmInt;
602 }
603 RECURSE(VisitWithExpectation(expr->target(), target_type, 614 RECURSE(VisitWithExpectation(expr->target(), target_type,
604 "assignment target expected to match value")); 615 "assignment target expected to match value"));
605 if (intish_ != 0) { 616 DCHECK(!assigning_);
606 FAIL(expr, "value still an intish");
607 }
608 IntersectResult(expr, computed_type_); 617 IntersectResult(expr, computed_type_);
609 } 618 }
610 619
611 620
612 void AsmTyper::VisitYield(Yield* expr) { 621 void AsmTyper::VisitYield(Yield* expr) {
613 FAIL(expr, "yield expression encountered"); 622 FAIL(expr, "yield expression encountered");
614 } 623 }
615 624
616 625
617 void AsmTyper::VisitThrow(Throw* expr) { 626 void AsmTyper::VisitThrow(Throw* expr) {
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
651 Literal* right = bin->right()->AsLiteral(); 660 Literal* right = bin->right()->AsLiteral();
652 if (right == NULL || right->raw_value()->ContainsDot()) { 661 if (right == NULL || right->raw_value()->ContainsDot()) {
653 FAIL(right, "call mask must be integer"); 662 FAIL(right, "call mask must be integer");
654 } 663 }
655 RECURSE(VisitWithExpectation(bin->right(), cache_.kAsmSigned, 664 RECURSE(VisitWithExpectation(bin->right(), cache_.kAsmSigned,
656 "call mask expected to be integer")); 665 "call mask expected to be integer"));
657 if (static_cast<size_t>(right->raw_value()->AsNumber()) != size - 1) { 666 if (static_cast<size_t>(right->raw_value()->AsNumber()) != size - 1) {
658 FAIL(right, "call mask must match function table"); 667 FAIL(right, "call mask must match function table");
659 } 668 }
660 bin->set_bounds(Bounds(cache_.kAsmSigned)); 669 bin->set_bounds(Bounds(cache_.kAsmSigned));
670 IntersectResult(expr, type);
661 } else { 671 } else {
662 Literal* literal = expr->key()->AsLiteral(); 672 Literal* literal = expr->key()->AsLiteral();
663 if (literal) { 673 if (literal) {
664 RECURSE(VisitWithExpectation(literal, cache_.kAsmSigned, 674 RECURSE(VisitWithExpectation(literal, cache_.kAsmSigned,
665 "array index expected to be integer")); 675 "array index expected to be integer"));
666 } else { 676 } else {
667 BinaryOperation* bin = expr->key()->AsBinaryOperation(); 677 BinaryOperation* bin = expr->key()->AsBinaryOperation();
668 if (bin == NULL || bin->op() != Token::SAR) { 678 if (bin == NULL || bin->op() != Token::SAR) {
669 FAIL(expr->key(), "expected >> in heap access"); 679 FAIL(expr->key(), "expected >> in heap access");
670 } 680 }
671 RECURSE(VisitWithExpectation(bin->left(), cache_.kAsmSigned, 681 RECURSE(VisitWithExpectation(bin->left(), cache_.kAsmSigned,
672 "array index expected to be integer")); 682 "array index expected to be integer"));
673 Literal* right = bin->right()->AsLiteral(); 683 Literal* right = bin->right()->AsLiteral();
674 if (right == NULL || right->raw_value()->ContainsDot()) { 684 if (right == NULL || right->raw_value()->ContainsDot()) {
675 FAIL(right, "heap access shift must be integer"); 685 FAIL(right, "heap access shift must be integer");
676 } 686 }
677 RECURSE(VisitWithExpectation(bin->right(), cache_.kAsmSigned, 687 RECURSE(VisitWithExpectation(bin->right(), cache_.kAsmSigned,
678 "array shift expected to be integer")); 688 "array shift expected to be integer"));
679 int n = static_cast<int>(right->raw_value()->AsNumber()); 689 int n = static_cast<int>(right->raw_value()->AsNumber());
680 int expected_shift = ElementShiftSize(type); 690 int expected_shift = ElementShiftSize(type);
681 if (expected_shift < 0 || n != expected_shift) { 691 if (expected_shift < 0 || n != expected_shift) {
682 FAIL(right, "heap access shift must match element size"); 692 FAIL(right, "heap access shift must match element size");
683 } 693 }
684 bin->set_bounds(Bounds(cache_.kAsmSigned)); 694 bin->set_bounds(Bounds(cache_.kAsmSigned));
685 } 695 }
696 Type* result_type;
697 if (type->Is(cache_.kAsmIntArrayElement)) {
698 result_type = cache_.kAsmIntQ;
699 intish_ = kMaxUncombinedAdditiveSteps;
700 } else if (type->Is(cache_.kAsmFloat)) {
701 if (assigning_) {
702 result_type = cache_.kAsmFloatDoubleQ;
703 } else {
704 result_type = cache_.kAsmFloatQ;
705 }
706 intish_ = 0;
707 } else if (type->Is(cache_.kAsmDouble)) {
708 if (assigning_) {
709 result_type = cache_.kAsmFloatDoubleQ;
710 if (intish_ != 0) {
711 FAIL(expr, "Assignment of floatish to Float64Array");
712 }
713 } else {
714 result_type = cache_.kAsmDoubleQ;
715 }
716 intish_ = 0;
717 } else {
718 UNREACHABLE();
719 }
720 IntersectResult(expr, expected_type_);
721 IntersectResult(expr, result_type);
722 assigning_ = false;
686 } 723 }
687 IntersectResult(expr, type);
688 } 724 }
689 725
690 726
691 void AsmTyper::VisitProperty(Property* expr) { 727 void AsmTyper::VisitProperty(Property* expr) {
692 // stdlib.Math.x 728 // stdlib.Math.x
693 Property* inner_prop = expr->obj()->AsProperty(); 729 Property* inner_prop = expr->obj()->AsProperty();
694 if (inner_prop != NULL) { 730 if (inner_prop != NULL) {
695 // Get property name. 731 // Get property name.
696 Literal* key = expr->key()->AsLiteral(); 732 Literal* key = expr->key()->AsLiteral();
697 if (key == NULL || !key->IsPropertyName()) 733 if (key == NULL || !key->IsPropertyName())
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after
773 ZoneList<Expression*>* args = expr->arguments(); 809 ZoneList<Expression*>* args = expr->arguments();
774 if (fun_type->Arity() != args->length()) { 810 if (fun_type->Arity() != args->length()) {
775 FAIL(expr, "call with wrong arity"); 811 FAIL(expr, "call with wrong arity");
776 } 812 }
777 for (int i = 0; i < args->length(); ++i) { 813 for (int i = 0; i < args->length(); ++i) {
778 Expression* arg = args->at(i); 814 Expression* arg = args->at(i);
779 RECURSE(VisitWithExpectation( 815 RECURSE(VisitWithExpectation(
780 arg, fun_type->Parameter(i), 816 arg, fun_type->Parameter(i),
781 "call argument expected to match callee parameter")); 817 "call argument expected to match callee parameter"));
782 } 818 }
819 intish_ = 0;
783 IntersectResult(expr, fun_type->Result()); 820 IntersectResult(expr, fun_type->Result());
784 } else if (computed_type_->Is(Type::Any())) { 821 } else if (computed_type_->Is(Type::Any())) {
785 // For foreign calls. 822 // For foreign calls.
786 ZoneList<Expression*>* args = expr->arguments(); 823 ZoneList<Expression*>* args = expr->arguments();
787 for (int i = 0; i < args->length(); ++i) { 824 for (int i = 0; i < args->length(); ++i) {
788 Expression* arg = args->at(i); 825 Expression* arg = args->at(i);
789 RECURSE(VisitWithExpectation(arg, Type::Any(), 826 RECURSE(VisitWithExpectation(arg, Type::Any(),
790 "foreign call argument expected to be any")); 827 "foreign call argument expected to be any"));
791 } 828 }
829 intish_ = kMaxUncombinedAdditiveSteps;
792 IntersectResult(expr, Type::Number()); 830 IntersectResult(expr, Type::Number());
793 } else { 831 } else {
794 FAIL(expr, "invalid callee"); 832 FAIL(expr, "invalid callee");
795 } 833 }
796 } 834 }
797 835
798 836
799 void AsmTyper::VisitCallNew(CallNew* expr) { 837 void AsmTyper::VisitCallNew(CallNew* expr) {
800 if (in_function_) { 838 if (in_function_) {
801 FAIL(expr, "new not allowed in module function"); 839 FAIL(expr, "new not allowed in module function");
(...skipping 185 matching lines...) Expand 10 before | Expand all | Expand 10 after
987 FAIL(expr, "too many consecutive additive ops"); 1025 FAIL(expr, "too many consecutive additive ops");
988 } 1026 }
989 } else { 1027 } else {
990 if (intish_ > kMaxUncombinedMultiplicativeSteps) { 1028 if (intish_ > kMaxUncombinedMultiplicativeSteps) {
991 FAIL(expr, "too many consecutive multiplicative ops"); 1029 FAIL(expr, "too many consecutive multiplicative ops");
992 } 1030 }
993 } 1031 }
994 IntersectResult(expr, cache_.kAsmInt); 1032 IntersectResult(expr, cache_.kAsmInt);
995 return; 1033 return;
996 } 1034 }
997 } else if (expr->op() == Token::MUL && left_type->Is(cache_.kAsmInt) && 1035 } else if (expr->op() == Token::MUL && expr->right()->IsLiteral() &&
998 right_type->Is(cache_.kAsmDouble)) { 1036 right_type->Is(cache_.kAsmDouble)) {
999 // For unary +, expressed as x * 1.0 1037 // For unary +, expressed as x * 1.0
1000 IntersectResult(expr, cache_.kAsmDouble); 1038 IntersectResult(expr, cache_.kAsmDouble);
1001 return; 1039 return;
1002 } else if (type->Is(cache_.kAsmFloat) && expr->op() != Token::MOD) { 1040 } else if (type->Is(cache_.kAsmFloat) && expr->op() != Token::MOD) {
1041 if (left_intish != 0 || right_intish != 0) {
1042 FAIL(expr, "float operation before required fround");
1043 }
1003 IntersectResult(expr, cache_.kAsmFloat); 1044 IntersectResult(expr, cache_.kAsmFloat);
1045 intish_ = 1;
1004 return; 1046 return;
1005 } else if (type->Is(cache_.kAsmDouble)) { 1047 } else if (type->Is(cache_.kAsmDouble)) {
1006 IntersectResult(expr, cache_.kAsmDouble); 1048 IntersectResult(expr, cache_.kAsmDouble);
1007 return; 1049 return;
1008 } else { 1050 } else {
1009 FAIL(expr, "ill-typed arithmetic operation"); 1051 FAIL(expr, "ill-typed arithmetic operation");
1010 } 1052 }
1011 } 1053 }
1012 default: 1054 default:
1013 UNREACHABLE(); 1055 UNREACHABLE();
(...skipping 192 matching lines...) Expand 10 before | Expand all | Expand 10 after
1206 computed_type_->Print(); 1248 computed_type_->Print();
1207 PrintF("Expected type: "); 1249 PrintF("Expected type: ");
1208 expected_type_->Print(); 1250 expected_type_->Print();
1209 #endif 1251 #endif
1210 FAIL(expr, msg); 1252 FAIL(expr, msg);
1211 } 1253 }
1212 expected_type_ = save; 1254 expected_type_ = save;
1213 } 1255 }
1214 } // namespace internal 1256 } // namespace internal
1215 } // namespace v8 1257 } // namespace v8
OLDNEW
« no previous file with comments | « src/typing-asm.h ('k') | test/cctest/expression-type-collector-macros.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698