OLD | NEW |
1 // Copyright 2016 the V8 project authors. All rights reserved. | 1 // Copyright 2016 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/asmjs/asm-typer.h" | 5 #include "src/asmjs/asm-typer.h" |
6 | 6 |
7 #include <limits> | 7 #include <limits> |
8 #include <string> | 8 #include <string> |
9 | 9 |
10 #include "src/v8.h" | 10 #include "src/v8.h" |
(...skipping 30 matching lines...) Expand all Loading... |
41 } \ | 41 } \ |
42 \ | 42 \ |
43 if (result == AsmType::None()) { \ | 43 if (result == AsmType::None()) { \ |
44 return AsmType::None(); \ | 44 return AsmType::None(); \ |
45 } \ | 45 } \ |
46 } while (false) | 46 } while (false) |
47 | 47 |
48 namespace v8 { | 48 namespace v8 { |
49 namespace internal { | 49 namespace internal { |
50 namespace wasm { | 50 namespace wasm { |
| 51 namespace { |
| 52 static const uint32_t LargestFixNum = std::numeric_limits<int32_t>::max(); |
| 53 } // namespace |
51 | 54 |
52 using v8::internal::AstNode; | 55 using v8::internal::AstNode; |
53 using v8::internal::GetCurrentStackPosition; | 56 using v8::internal::GetCurrentStackPosition; |
54 | 57 |
55 // ---------------------------------------------------------------------------- | 58 // ---------------------------------------------------------------------------- |
56 // Implementation of AsmTyper::FlattenedStatements | 59 // Implementation of AsmTyper::FlattenedStatements |
57 | 60 |
58 AsmTyper::FlattenedStatements::FlattenedStatements(Zone* zone, | 61 AsmTyper::FlattenedStatements::FlattenedStatements(Zone* zone, |
59 ZoneList<Statement*>* s) | 62 ZoneList<Statement*>* s) |
60 : context_stack_(zone) { | 63 : context_stack_(zone) { |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
115 forward_definitions_(zone), | 118 forward_definitions_(zone), |
116 stdlib_types_(zone), | 119 stdlib_types_(zone), |
117 stdlib_math_types_(zone), | 120 stdlib_math_types_(zone), |
118 global_scope_(ZoneHashMap::PointersMatch, | 121 global_scope_(ZoneHashMap::PointersMatch, |
119 ZoneHashMap::kDefaultHashMapCapacity, | 122 ZoneHashMap::kDefaultHashMapCapacity, |
120 ZoneAllocationPolicy(zone)), | 123 ZoneAllocationPolicy(zone)), |
121 local_scope_(ZoneHashMap::PointersMatch, | 124 local_scope_(ZoneHashMap::PointersMatch, |
122 ZoneHashMap::kDefaultHashMapCapacity, | 125 ZoneHashMap::kDefaultHashMapCapacity, |
123 ZoneAllocationPolicy(zone)), | 126 ZoneAllocationPolicy(zone)), |
124 stack_limit_(isolate->stack_guard()->real_climit()), | 127 stack_limit_(isolate->stack_guard()->real_climit()), |
125 node_types_(zone_) { | 128 node_types_(zone_), |
| 129 fround_type_(AsmType::FroundType(zone_)) { |
126 InitializeStdlib(); | 130 InitializeStdlib(); |
127 module_info_.set_standard_member(kModule); | 131 module_info_.set_standard_member(kModule); |
128 } | 132 } |
129 | 133 |
130 namespace { | 134 namespace { |
131 bool ValidAsmIdentifier(Handle<String> name) { | 135 bool ValidAsmIdentifier(Handle<String> name) { |
132 static const char* kInvalidAsmNames[] = {"eval", "arguments"}; | 136 static const char* kInvalidAsmNames[] = {"eval", "arguments"}; |
133 | 137 |
134 for (size_t ii = 0; ii < arraysize(kInvalidAsmNames); ++ii) { | 138 for (size_t ii = 0; ii < arraysize(kInvalidAsmNames); ++ii) { |
135 if (strcmp(name->ToCString().get(), kInvalidAsmNames[ii]) == 0) { | 139 if (strcmp(name->ToCString().get(), kInvalidAsmNames[ii]) == 0) { |
(...skipping 22 matching lines...) Expand all Loading... |
158 auto* s = AsmType::Signed(); | 162 auto* s = AsmType::Signed(); |
159 auto* s2s = AsmType::Function(zone_, s); | 163 auto* s2s = AsmType::Function(zone_, s); |
160 s2s->AsFunctionType()->AddArgument(s); | 164 s2s->AsFunctionType()->AddArgument(s); |
161 | 165 |
162 auto* i = AsmType::Int(); | 166 auto* i = AsmType::Int(); |
163 auto* ii2s = AsmType::Function(zone_, s); | 167 auto* ii2s = AsmType::Function(zone_, s); |
164 ii2s->AsFunctionType()->AddArgument(i); | 168 ii2s->AsFunctionType()->AddArgument(i); |
165 ii2s->AsFunctionType()->AddArgument(i); | 169 ii2s->AsFunctionType()->AddArgument(i); |
166 | 170 |
167 auto* minmax_d = AsmType::MinMaxType(zone_, d, d); | 171 auto* minmax_d = AsmType::MinMaxType(zone_, d, d); |
| 172 // *VIOLATION* The float variant is not part of the spec, but firefox accepts |
| 173 // it. |
| 174 auto* minmax_f = AsmType::MinMaxType(zone_, f, f); |
168 auto* minmax_i = AsmType::MinMaxType(zone_, s, i); | 175 auto* minmax_i = AsmType::MinMaxType(zone_, s, i); |
169 auto* minmax = AsmType::OverloadedFunction(zone_); | 176 auto* minmax = AsmType::OverloadedFunction(zone_); |
170 minmax->AsOverloadedFunctionType()->AddOverload(minmax_i); | 177 minmax->AsOverloadedFunctionType()->AddOverload(minmax_i); |
| 178 minmax->AsOverloadedFunctionType()->AddOverload(minmax_f); |
171 minmax->AsOverloadedFunctionType()->AddOverload(minmax_d); | 179 minmax->AsOverloadedFunctionType()->AddOverload(minmax_d); |
172 | 180 |
173 auto* fround = AsmType::FroundType(zone_); | 181 auto* fround = fround_type_; |
174 | 182 |
175 auto* abs = AsmType::OverloadedFunction(zone_); | 183 auto* abs = AsmType::OverloadedFunction(zone_); |
176 abs->AsOverloadedFunctionType()->AddOverload(s2s); | 184 abs->AsOverloadedFunctionType()->AddOverload(s2s); |
177 abs->AsOverloadedFunctionType()->AddOverload(dq2d); | 185 abs->AsOverloadedFunctionType()->AddOverload(dq2d); |
178 abs->AsOverloadedFunctionType()->AddOverload(fq2f); | 186 abs->AsOverloadedFunctionType()->AddOverload(fq2f); |
179 | 187 |
180 auto* ceil = AsmType::OverloadedFunction(zone_); | 188 auto* ceil = AsmType::OverloadedFunction(zone_); |
181 ceil->AsOverloadedFunctionType()->AddOverload(dq2d); | 189 ceil->AsOverloadedFunctionType()->AddOverload(dq2d); |
182 ceil->AsOverloadedFunctionType()->AddOverload(fq2f); | 190 ceil->AsOverloadedFunctionType()->AddOverload(fq2f); |
183 | 191 |
(...skipping 171 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
355 if (entry->value != nullptr) { | 363 if (entry->value != nullptr) { |
356 return false; | 364 return false; |
357 } | 365 } |
358 | 366 |
359 entry->value = info; | 367 entry->value = info; |
360 return true; | 368 return true; |
361 } | 369 } |
362 | 370 |
363 void AsmTyper::SetTypeOf(AstNode* node, AsmType* type) { | 371 void AsmTyper::SetTypeOf(AstNode* node, AsmType* type) { |
364 DCHECK_NE(type, AsmType::None()); | 372 DCHECK_NE(type, AsmType::None()); |
365 auto** node_type = &node_types_[node]; | 373 DCHECK(node_types_.find(node) == node_types_.end()); |
366 DCHECK(*node_type == nullptr); | 374 node_types_.insert(std::make_pair(node, type)); |
367 *node_type = type; | |
368 } | 375 } |
369 | 376 |
370 AsmType* AsmTyper::TypeOf(AstNode* node) const { | 377 AsmType* AsmTyper::TypeOf(AstNode* node) const { |
371 auto node_type_iter = node_types_.find(node); | 378 auto node_type_iter = node_types_.find(node); |
372 if (node_type_iter == node_types_.end()) { | 379 if (node_type_iter != node_types_.end()) { |
373 return AsmType::None(); | 380 return node_type_iter->second; |
374 } | 381 } |
375 return node_type_iter->second; | 382 |
| 383 // Sometimes literal nodes are not added to the node_type_ map simply because |
| 384 // their are not visited with ValidateExpression(). |
| 385 if (auto* literal = node->AsLiteral()) { |
| 386 if (literal->raw_value()->ContainsDot()) { |
| 387 return AsmType::Double(); |
| 388 } |
| 389 uint32_t u; |
| 390 if (literal->value()->ToUint32(&u)) { |
| 391 if (u > LargestFixNum) { |
| 392 return AsmType::Unsigned(); |
| 393 } |
| 394 return AsmType::FixNum(); |
| 395 } |
| 396 int32_t i; |
| 397 if (literal->value()->ToInt32(&i)) { |
| 398 return AsmType::Signed(); |
| 399 } |
| 400 } |
| 401 |
| 402 return AsmType::None(); |
376 } | 403 } |
377 | 404 |
378 AsmTyper::StandardMember AsmTyper::VariableAsStandardMember(Variable* var) { | 405 AsmTyper::StandardMember AsmTyper::VariableAsStandardMember(Variable* var) { |
379 auto* var_info = Lookup(var); | 406 auto* var_info = Lookup(var); |
380 if (var_info == nullptr) { | 407 if (var_info == nullptr) { |
381 return kNone; | 408 return kNone; |
382 } | 409 } |
383 return var_info->standard_member(); | 410 return var_info->standard_member(); |
384 } | 411 } |
385 | 412 |
(...skipping 214 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
600 auto* target_variable = target->AsVariableProxy()->var(); | 627 auto* target_variable = target->AsVariableProxy()->var(); |
601 auto* target_info = Lookup(target_variable); | 628 auto* target_info = Lookup(target_variable); |
602 | 629 |
603 if (target_info != nullptr) { | 630 if (target_info != nullptr) { |
604 FAIL(target, "Redefined global variable."); | 631 FAIL(target, "Redefined global variable."); |
605 } | 632 } |
606 | 633 |
607 auto* value = assign->value(); | 634 auto* value = assign->value(); |
608 // Not all types of assignment are allowed by asm.js. See | 635 // Not all types of assignment are allowed by asm.js. See |
609 // 5.5 Global Variable Type Annotations. | 636 // 5.5 Global Variable Type Annotations. |
| 637 bool global_variable = false; |
610 if (value->IsLiteral() || value->IsCall()) { | 638 if (value->IsLiteral() || value->IsCall()) { |
611 AsmType* type = nullptr; | 639 AsmType* type = nullptr; |
612 RECURSE(type = VariableTypeAnnotations(value)); | 640 RECURSE(type = VariableTypeAnnotations(value)); |
613 target_info = new (zone_) VariableInfo(type); | 641 target_info = new (zone_) VariableInfo(type); |
614 target_info->set_mutability(VariableInfo::kMutableGlobal); | 642 target_info->set_mutability(VariableInfo::kMutableGlobal); |
| 643 global_variable = true; |
615 } else if (value->IsProperty()) { | 644 } else if (value->IsProperty()) { |
616 target_info = ImportLookup(value->AsProperty()); | 645 target_info = ImportLookup(value->AsProperty()); |
617 if (target_info == nullptr) { | 646 if (target_info == nullptr) { |
618 FAIL(assign, "Invalid import."); | 647 FAIL(assign, "Invalid import."); |
619 } | 648 } |
620 CHECK(target_info->mutability() == VariableInfo::kImmutableGlobal); | 649 CHECK(target_info->mutability() == VariableInfo::kImmutableGlobal); |
621 if (!target_info->IsFFI()) { | 650 if (!target_info->IsFFI()) { |
622 target_info = target_info->Clone(zone_); | 651 target_info = target_info->Clone(zone_); |
623 } else { | 652 } else { |
624 // create a new target info that represents a foreign variable. | 653 // create a new target info that represents a foreign variable. |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
682 | 711 |
683 if (!ValidAsmIdentifier(target_variable->name())) { | 712 if (!ValidAsmIdentifier(target_variable->name())) { |
684 FAIL(target, "Invalid asm.js identifier in global variable."); | 713 FAIL(target, "Invalid asm.js identifier in global variable."); |
685 } | 714 } |
686 | 715 |
687 if (!AddGlobal(target_variable, target_info)) { | 716 if (!AddGlobal(target_variable, target_info)) { |
688 FAIL(assign, "Redeclared global identifier."); | 717 FAIL(assign, "Redeclared global identifier."); |
689 } | 718 } |
690 | 719 |
691 DCHECK(target_info->type() != AsmType::None()); | 720 DCHECK(target_info->type() != AsmType::None()); |
| 721 if (!global_variable) { |
| 722 // Global variables have their types set in VariableTypeAnnotations. |
| 723 SetTypeOf(value, target_info->type()); |
| 724 } |
| 725 SetTypeOf(assign, target_info->type()); |
| 726 SetTypeOf(target, target_info->type()); |
692 return target_info->type(); | 727 return target_info->type(); |
693 } | 728 } |
694 | 729 |
695 // 6.2 ValidateExport | 730 // 6.2 ValidateExport |
696 AsmType* AsmTyper::ExportType(VariableProxy* fun_export) { | 731 AsmType* AsmTyper::ExportType(VariableProxy* fun_export) { |
697 auto* fun_info = Lookup(fun_export->var()); | 732 auto* fun_info = Lookup(fun_export->var()); |
698 if (fun_info == nullptr) { | 733 if (fun_info == nullptr) { |
699 FAIL(fun_export, "Undefined identifier in asm.js module export."); | 734 FAIL(fun_export, "Undefined identifier in asm.js module export."); |
700 } | 735 } |
701 | 736 |
(...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
823 target_info = new (zone_) VariableInfo(AsmType::FunctionTableType( | 858 target_info = new (zone_) VariableInfo(AsmType::FunctionTableType( |
824 zone_, pointers->length(), table_element_type)); | 859 zone_, pointers->length(), table_element_type)); |
825 target_info->set_mutability(VariableInfo::kImmutableGlobal); | 860 target_info->set_mutability(VariableInfo::kImmutableGlobal); |
826 if (!ValidAsmIdentifier(target_variable->name())) { | 861 if (!ValidAsmIdentifier(target_variable->name())) { |
827 FAIL(target, "Invalid asm.js identifier in function table name."); | 862 FAIL(target, "Invalid asm.js identifier in function table name."); |
828 } | 863 } |
829 if (!AddGlobal(target_variable, target_info)) { | 864 if (!AddGlobal(target_variable, target_info)) { |
830 DCHECK(false); | 865 DCHECK(false); |
831 FAIL(assign, "Redeclared global identifier in function table name."); | 866 FAIL(assign, "Redeclared global identifier in function table name."); |
832 } | 867 } |
| 868 SetTypeOf(value, target_info->type()); |
833 return target_info->type(); | 869 return target_info->type(); |
834 } | 870 } |
835 | 871 |
836 auto* target_info_table = target_info->type()->AsFunctionTableType(); | 872 auto* target_info_table = target_info->type()->AsFunctionTableType(); |
837 if (target_info_table == nullptr) { | 873 if (target_info_table == nullptr) { |
838 FAIL(assign, "Identifier redefined as function pointer table."); | 874 FAIL(assign, "Identifier redefined as function pointer table."); |
839 } | 875 } |
840 | 876 |
841 if (!target_info->missing_definition()) { | 877 if (!target_info->missing_definition()) { |
842 FAIL(assign, "Identifier redefined (function table name)."); | 878 FAIL(assign, "Identifier redefined (function table name)."); |
843 } | 879 } |
844 | 880 |
845 if (target_info_table->length() != pointers->length()) { | 881 if (target_info_table->length() != pointers->length()) { |
846 FAIL(assign, "Function table size mismatch."); | 882 FAIL(assign, "Function table size mismatch."); |
847 } | 883 } |
848 | 884 |
849 auto* function_type = callable_type->AsFunctionType(); | 885 auto* function_type = callable_type->AsFunctionType(); |
850 if (target_info_table->ValidateCall(function_type->ReturnType(), | 886 if (target_info_table->ValidateCall(function_type->ReturnType(), |
851 function_type->Arguments()) == | 887 function_type->Arguments()) == |
852 AsmType::None()) { | 888 AsmType::None()) { |
853 FAIL(assign, "Function table initializer does not match previous type."); | 889 FAIL(assign, "Function table initializer does not match previous type."); |
854 } | 890 } |
855 | 891 |
856 target_info->MarkDefined(); | 892 target_info->MarkDefined(); |
857 DCHECK(target_info->type() == AsmType::None()); | 893 DCHECK(target_info->type() != AsmType::None()); |
858 SetTypeOf(value, target_info->type()); | 894 SetTypeOf(value, target_info->type()); |
859 | 895 |
860 return target_info->type(); | 896 return target_info->type(); |
861 } | 897 } |
862 | 898 |
863 // 6.4 ValidateFunction | 899 // 6.4 ValidateFunction |
864 AsmType* AsmTyper::ValidateFunction(FunctionDeclaration* fun_decl) { | 900 AsmType* AsmTyper::ValidateFunction(FunctionDeclaration* fun_decl) { |
865 FunctionScope _(this); | 901 FunctionScope _(this); |
866 | 902 |
867 // Extract parameter types. | 903 // Extract parameter types. |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
909 auto* param_info = new (zone_) VariableInfo(type); | 945 auto* param_info = new (zone_) VariableInfo(type); |
910 param_info->set_mutability(VariableInfo::kLocal); | 946 param_info->set_mutability(VariableInfo::kLocal); |
911 if (!ValidAsmIdentifier(proxy->name())) { | 947 if (!ValidAsmIdentifier(proxy->name())) { |
912 FAIL(proxy, "Invalid asm.js identifier in parameter name."); | 948 FAIL(proxy, "Invalid asm.js identifier in parameter name."); |
913 } | 949 } |
914 | 950 |
915 if (!AddLocal(param, param_info)) { | 951 if (!AddLocal(param, param_info)) { |
916 FAIL(proxy, "Redeclared parameter."); | 952 FAIL(proxy, "Redeclared parameter."); |
917 } | 953 } |
918 parameter_types.push_back(type); | 954 parameter_types.push_back(type); |
| 955 SetTypeOf(proxy, type); |
| 956 SetTypeOf(expr, type); |
919 } | 957 } |
920 | 958 |
921 if (annotated_parameters != fun->parameter_count()) { | 959 if (annotated_parameters != fun->parameter_count()) { |
922 FAIL(fun_decl, "Incorrect parameter type annotations."); | 960 FAIL(fun_decl, "Incorrect parameter type annotations."); |
923 } | 961 } |
924 | 962 |
925 // 5.3 Function type annotations | 963 // 5.3 Function type annotations |
926 // * locals | 964 // * locals |
927 for (; current; current = iter.Next()) { | 965 for (; current; current = iter.Next()) { |
928 auto* initializer = ExtractInitializerExpression(current); | 966 auto* initializer = ExtractInitializerExpression(current); |
(...skipping 16 matching lines...) Expand all Loading... |
945 RECURSE(type = VariableTypeAnnotations(initializer->value())); | 983 RECURSE(type = VariableTypeAnnotations(initializer->value())); |
946 auto* local_info = new (zone_) VariableInfo(type); | 984 auto* local_info = new (zone_) VariableInfo(type); |
947 local_info->set_mutability(VariableInfo::kLocal); | 985 local_info->set_mutability(VariableInfo::kLocal); |
948 if (!ValidAsmIdentifier(local->name())) { | 986 if (!ValidAsmIdentifier(local->name())) { |
949 FAIL(local, "Invalid asm.js identifier in local variable."); | 987 FAIL(local, "Invalid asm.js identifier in local variable."); |
950 } | 988 } |
951 | 989 |
952 if (!AddLocal(local->var(), local_info)) { | 990 if (!AddLocal(local->var(), local_info)) { |
953 FAIL(initializer, "Redeclared local."); | 991 FAIL(initializer, "Redeclared local."); |
954 } | 992 } |
| 993 |
| 994 SetTypeOf(local, type); |
| 995 SetTypeOf(initializer, type); |
955 } | 996 } |
956 | 997 |
957 // 5.2 Return Type Annotations | 998 // 5.2 Return Type Annotations |
958 // *VIOLATION* we peel blocks to find the last statement in the asm module | 999 // *VIOLATION* we peel blocks to find the last statement in the asm module |
959 // because the parser may introduce synthetic blocks. | 1000 // because the parser may introduce synthetic blocks. |
960 ZoneList<Statement*>* statements = fun->body(); | 1001 ZoneList<Statement*>* statements = fun->body(); |
961 | 1002 |
962 do { | 1003 do { |
963 if (statements->length() == 0) { | 1004 if (statements->length() == 0) { |
964 return_type_ = AsmType::Void(); | 1005 return_type_ = AsmType::Void(); |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1011 fun_info->set_mutability(VariableInfo::kImmutableGlobal); | 1052 fun_info->set_mutability(VariableInfo::kImmutableGlobal); |
1012 auto* old_fun_type = Lookup(fun_var); | 1053 auto* old_fun_type = Lookup(fun_var); |
1013 if (old_fun_type == nullptr) { | 1054 if (old_fun_type == nullptr) { |
1014 if (!ValidAsmIdentifier(fun_var->name())) { | 1055 if (!ValidAsmIdentifier(fun_var->name())) { |
1015 FAIL(fun_decl_proxy, "Invalid asm.js identifier in function name."); | 1056 FAIL(fun_decl_proxy, "Invalid asm.js identifier in function name."); |
1016 } | 1057 } |
1017 if (!AddGlobal(fun_var, fun_info)) { | 1058 if (!AddGlobal(fun_var, fun_info)) { |
1018 DCHECK(false); | 1059 DCHECK(false); |
1019 FAIL(fun_decl, "Redeclared global identifier."); | 1060 FAIL(fun_decl, "Redeclared global identifier."); |
1020 } | 1061 } |
| 1062 |
| 1063 SetTypeOf(fun, fun_type); |
1021 return fun_type; | 1064 return fun_type; |
1022 } | 1065 } |
1023 | 1066 |
1024 // Not necessarily an error -- fun_decl might have been used before being | 1067 // Not necessarily an error -- fun_decl might have been used before being |
1025 // defined. If that's the case, then the type in the global environment must | 1068 // defined. If that's the case, then the type in the global environment must |
1026 // be the same as the type inferred by the parameter/return type annotations. | 1069 // be the same as the type inferred by the parameter/return type annotations. |
1027 auto* old_fun_callable = old_fun_type->type()->AsCallableType(); | 1070 auto* old_fun_callable = old_fun_type->type()->AsCallableType(); |
1028 if (old_fun_callable == nullptr) { | 1071 if (old_fun_callable == nullptr) { |
1029 FAIL(fun_decl, "Identifier redefined as function."); | 1072 FAIL(fun_decl, "Identifier redefined as function."); |
1030 } | 1073 } |
(...skipping 183 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1214 } | 1257 } |
1215 | 1258 |
1216 bool has_default = false; | 1259 bool has_default = false; |
1217 | 1260 |
1218 ZoneSet<int32_t> cases_seen(zone_); | 1261 ZoneSet<int32_t> cases_seen(zone_); |
1219 for (auto* a_case : *stmt->cases()) { | 1262 for (auto* a_case : *stmt->cases()) { |
1220 if (a_case->is_default()) { | 1263 if (a_case->is_default()) { |
1221 CHECK(!has_default); | 1264 CHECK(!has_default); |
1222 RECURSE(ValidateDefault(a_case)); | 1265 RECURSE(ValidateDefault(a_case)); |
1223 has_default = true; | 1266 has_default = true; |
| 1267 continue; |
1224 } | 1268 } |
1225 | 1269 |
1226 int32_t case_lbl; | 1270 int32_t case_lbl; |
1227 RECURSE(ValidateCase(a_case, &case_lbl)); | 1271 RECURSE(ValidateCase(a_case, &case_lbl)); |
1228 auto case_lbl_pos = cases_seen.find(case_lbl); | 1272 auto case_lbl_pos = cases_seen.find(case_lbl); |
1229 if (case_lbl_pos != cases_seen.end() && *case_lbl_pos == case_lbl) { | 1273 if (case_lbl_pos != cases_seen.end() && *case_lbl_pos == case_lbl) { |
1230 FAIL(a_case, "Duplicated case label."); | 1274 FAIL(a_case, "Duplicated case label."); |
1231 } | 1275 } |
1232 cases_seen.insert(case_lbl); | 1276 cases_seen.insert(case_lbl); |
1233 } | 1277 } |
(...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1357 // *VIOLATION* The parser replaces uses of +x with x*1.0. | 1401 // *VIOLATION* The parser replaces uses of +x with x*1.0. |
1358 if (binop->op() != Token::MUL) { | 1402 if (binop->op() != Token::MUL) { |
1359 return false; | 1403 return false; |
1360 } | 1404 } |
1361 | 1405 |
1362 auto* right_as_literal = binop->right()->AsLiteral(); | 1406 auto* right_as_literal = binop->right()->AsLiteral(); |
1363 if (right_as_literal == nullptr) { | 1407 if (right_as_literal == nullptr) { |
1364 return false; | 1408 return false; |
1365 } | 1409 } |
1366 | 1410 |
1367 return right_as_literal->raw_value()->ContainsDot() && | 1411 return !right_as_literal->raw_value()->ContainsDot() && |
1368 right_as_literal->raw_value()->AsNumber() == -1.0; | 1412 right_as_literal->raw_value()->AsNumber() == -1.0; |
1369 } | 1413 } |
1370 } // namespace | 1414 } // namespace |
1371 | 1415 |
1372 AsmType* AsmTyper::ValidateBinaryOperation(BinaryOperation* expr) { | 1416 AsmType* AsmTyper::ValidateBinaryOperation(BinaryOperation* expr) { |
1373 #define UNOP_OVERLOAD(Src, Dest) \ | 1417 #define UNOP_OVERLOAD(Src, Dest) \ |
1374 do { \ | 1418 do { \ |
1375 if (left_type->IsA(AsmType::Src())) { \ | 1419 if (left_type->IsA(AsmType::Src())) { \ |
1376 return AsmType::Dest(); \ | 1420 return AsmType::Dest(); \ |
1377 } \ | 1421 } \ |
1378 } while (0) | 1422 } while (0) |
1379 | 1423 |
1380 switch (expr->op()) { | 1424 switch (expr->op()) { |
1381 default: | 1425 default: |
1382 FAIL(expr, "Invalid asm.js binary expression."); | 1426 FAIL(expr, "Invalid asm.js binary expression."); |
1383 case Token::COMMA: | 1427 case Token::COMMA: |
1384 return ValidateCommaExpression(expr); | 1428 return ValidateCommaExpression(expr); |
1385 case Token::MUL: | 1429 case Token::MUL: |
1386 if (IsDoubleAnnotation(expr)) { | 1430 if (IsDoubleAnnotation(expr)) { |
1387 // *VIOLATION* We can't be 100% sure this really IS a unary + in the asm | 1431 // *VIOLATION* We can't be 100% sure this really IS a unary + in the asm |
1388 // source so we have to be lenient, and treat this as a unary +. | 1432 // source so we have to be lenient, and treat this as a unary +. |
1389 if (auto* Call = expr->left()->AsCall()) { | 1433 if (auto* Call = expr->left()->AsCall()) { |
1390 return ValidateCall(AsmType::Double(), Call); | 1434 return ValidateCall(AsmType::Double(), Call); |
1391 } | 1435 } |
1392 AsmType* left_type; | 1436 AsmType* left_type; |
1393 RECURSE(left_type = ValidateExpression(expr->left())); | 1437 RECURSE(left_type = ValidateExpression(expr->left())); |
| 1438 SetTypeOf(expr->right(), AsmType::Double()); |
1394 UNOP_OVERLOAD(Signed, Double); | 1439 UNOP_OVERLOAD(Signed, Double); |
1395 UNOP_OVERLOAD(Unsigned, Double); | 1440 UNOP_OVERLOAD(Unsigned, Double); |
1396 UNOP_OVERLOAD(DoubleQ, Double); | 1441 UNOP_OVERLOAD(DoubleQ, Double); |
1397 UNOP_OVERLOAD(FloatQ, Double); | 1442 UNOP_OVERLOAD(FloatQ, Double); |
1398 FAIL(expr, "Invalid type for conversion to double."); | 1443 FAIL(expr, "Invalid type for conversion to double."); |
1399 } | 1444 } |
1400 | 1445 |
1401 if (IsUnaryMinus(expr)) { | 1446 if (IsUnaryMinus(expr)) { |
1402 // *VIOLATION* the parser converts -x to x * -1.0. | 1447 // *VIOLATION* the parser converts -x to x * -1.0. |
1403 AsmType* left_type; | 1448 AsmType* left_type; |
1404 RECURSE(left_type = ValidateExpression(expr->left())); | 1449 RECURSE(left_type = ValidateExpression(expr->left())); |
| 1450 SetTypeOf(expr->right(), left_type); |
1405 UNOP_OVERLOAD(Int, Intish); | 1451 UNOP_OVERLOAD(Int, Intish); |
1406 UNOP_OVERLOAD(DoubleQ, Double); | 1452 UNOP_OVERLOAD(DoubleQ, Double); |
1407 UNOP_OVERLOAD(FloatQ, Floatish); | 1453 UNOP_OVERLOAD(FloatQ, Floatish); |
1408 FAIL(expr, "Invalid type for unary -."); | 1454 FAIL(expr, "Invalid type for unary -."); |
1409 } | 1455 } |
1410 // FALTHROUGH | 1456 // FALTHROUGH |
1411 case Token::DIV: | 1457 case Token::DIV: |
1412 case Token::MOD: | 1458 case Token::MOD: |
1413 return ValidateMultiplicativeExpression(expr); | 1459 return ValidateMultiplicativeExpression(expr); |
1414 case Token::ADD: | 1460 case Token::ADD: |
1415 case Token::SUB: { | 1461 case Token::SUB: { |
1416 static const uint32_t kInitialIntishCount = 0; | 1462 static const uint32_t kInitialIntishCount = 0; |
1417 return ValidateAdditiveExpression(expr, kInitialIntishCount); | 1463 return ValidateAdditiveExpression(expr, kInitialIntishCount); |
1418 } | 1464 } |
1419 case Token::SAR: | 1465 case Token::SAR: |
1420 case Token::SHL: | 1466 case Token::SHL: |
1421 case Token::SHR: | 1467 case Token::SHR: |
1422 return ValidateShiftExpression(expr); | 1468 return ValidateShiftExpression(expr); |
1423 case Token::BIT_AND: | 1469 case Token::BIT_AND: |
1424 return ValidateBitwiseANDExpression(expr); | 1470 return ValidateBitwiseANDExpression(expr); |
1425 case Token::BIT_XOR: | 1471 case Token::BIT_XOR: |
1426 if (IsNegate(expr)) { | 1472 if (IsNegate(expr)) { |
1427 auto* left = expr->left(); | 1473 auto* left = expr->left(); |
1428 auto* left_as_binop = left->AsBinaryOperation(); | 1474 auto* left_as_binop = left->AsBinaryOperation(); |
1429 | 1475 |
1430 if (left_as_binop != nullptr && IsNegate(left_as_binop)) { | 1476 if (left_as_binop != nullptr && IsNegate(left_as_binop)) { |
1431 // This is the special ~~ operator. | 1477 // This is the special ~~ operator. |
1432 AsmType* left_type; | 1478 AsmType* left_type; |
1433 RECURSE(left_type = ValidateExpression(left_as_binop->left())); | 1479 RECURSE(left_type = ValidateExpression(left_as_binop->left())); |
| 1480 SetTypeOf(left_as_binop->right(), AsmType::FixNum()); |
| 1481 SetTypeOf(left_as_binop, AsmType::Signed()); |
| 1482 SetTypeOf(expr->right(), AsmType::FixNum()); |
1434 UNOP_OVERLOAD(Double, Signed); | 1483 UNOP_OVERLOAD(Double, Signed); |
1435 UNOP_OVERLOAD(FloatQ, Signed); | 1484 UNOP_OVERLOAD(FloatQ, Signed); |
1436 FAIL(left_as_binop, "Invalid type for conversion to signed."); | 1485 FAIL(left_as_binop, "Invalid type for conversion to signed."); |
1437 } | 1486 } |
1438 | 1487 |
1439 AsmType* left_type; | 1488 AsmType* left_type; |
1440 RECURSE(left_type = ValidateExpression(left)); | 1489 RECURSE(left_type = ValidateExpression(left)); |
1441 UNOP_OVERLOAD(Intish, Signed); | 1490 UNOP_OVERLOAD(Intish, Signed); |
1442 FAIL(left, "Invalid type for ~."); | 1491 FAIL(left, "Invalid type for ~."); |
1443 } | 1492 } |
1444 | 1493 |
1445 return ValidateBitwiseXORExpression(expr); | 1494 return ValidateBitwiseXORExpression(expr); |
1446 case Token::BIT_OR: | 1495 case Token::BIT_OR: |
1447 return ValidateBitwiseORExpression(expr); | 1496 return ValidateBitwiseORExpression(expr); |
1448 } | 1497 } |
1449 #undef UNOP_OVERLOAD | 1498 #undef UNOP_OVERLOAD |
1450 UNREACHABLE(); | 1499 UNREACHABLE(); |
1451 } | 1500 } |
1452 | 1501 |
1453 // 6.8.1 Expression | 1502 // 6.8.1 Expression |
1454 AsmType* AsmTyper::ValidateCommaExpression(BinaryOperation* comma) { | 1503 AsmType* AsmTyper::ValidateCommaExpression(BinaryOperation* comma) { |
1455 // The AST looks like: | 1504 // The AST looks like: |
1456 // (expr COMMA (expr COMMA (expr COMMA (... )))) | 1505 // (expr COMMA (expr COMMA (expr COMMA (... )))) |
1457 | 1506 |
1458 auto* left = comma->left(); | 1507 auto* left = comma->left(); |
1459 auto* left_as_binop = left->AsBinaryOperation(); | 1508 if (auto* left_as_call = left->AsCall()) { |
1460 if (left_as_binop && left_as_binop->op() == Token::COMMA) { | 1509 RECURSE(ValidateCall(AsmType::Void(), left_as_call)); |
1461 ValidateCommaExpression(left_as_binop); | |
1462 } else if (auto* left_as_call = left->AsCall()) { | |
1463 ValidateCall(AsmType::Void(), left_as_call); | |
1464 } else { | 1510 } else { |
1465 ValidateExpression(left); | 1511 RECURSE(ValidateExpression(left)); |
1466 } | 1512 } |
1467 | 1513 |
1468 auto* right = comma->right(); | 1514 auto* right = comma->right(); |
1469 auto* right_as_binop = right->AsBinaryOperation(); | 1515 AsmType* right_type = nullptr; |
1470 if (right_as_binop && right_as_binop->op() == Token::COMMA) { | 1516 if (auto* right_as_call = right->AsCall()) { |
1471 return ValidateCommaExpression(right_as_binop); | 1517 RECURSE(right_type = ValidateCall(AsmType::Void(), right_as_call)); |
1472 } else { | 1518 } else { |
1473 return ValidateExpression(right); | 1519 RECURSE(right_type = ValidateExpression(right)); |
1474 } | 1520 } |
1475 | 1521 |
1476 UNREACHABLE(); | 1522 return right_type; |
1477 } | 1523 } |
1478 | 1524 |
1479 // 6.8.2 NumericLiteral | 1525 // 6.8.2 NumericLiteral |
1480 AsmType* AsmTyper::ValidateNumericLiteral(Literal* literal) { | 1526 AsmType* AsmTyper::ValidateNumericLiteral(Literal* literal) { |
1481 // *VIOLATION* asm.js does not allow the use of undefined, but our parser | 1527 // *VIOLATION* asm.js does not allow the use of undefined, but our parser |
1482 // inserts them, so we have to handle them. | 1528 // inserts them, so we have to handle them. |
1483 if (literal->IsUndefinedLiteral()) { | 1529 if (literal->IsUndefinedLiteral()) { |
1484 return AsmType::Void(); | 1530 return AsmType::Void(); |
1485 } | 1531 } |
1486 | 1532 |
1487 if (literal->raw_value()->ContainsDot()) { | 1533 if (literal->raw_value()->ContainsDot()) { |
1488 return AsmType::Double(); | 1534 return AsmType::Double(); |
1489 } | 1535 } |
1490 | 1536 |
1491 uint32_t value; | 1537 uint32_t value; |
1492 if (!literal->value()->ToUint32(&value)) { | 1538 if (!literal->value()->ToUint32(&value)) { |
1493 int32_t value; | 1539 int32_t value; |
1494 if (!literal->value()->ToInt32(&value)) { | 1540 if (!literal->value()->ToInt32(&value)) { |
1495 FAIL(literal, "Integer literal is out of range."); | 1541 FAIL(literal, "Integer literal is out of range."); |
1496 } | 1542 } |
1497 // *VIOLATION* Not really a violation, but rather a different in the | 1543 // *VIOLATION* Not really a violation, but rather a different in the |
1498 // validation. The spec handles -NumericLiteral in ValidateUnaryExpression, | 1544 // validation. The spec handles -NumericLiteral in ValidateUnaryExpression, |
1499 // but V8's AST represents the negative literals as Literals. | 1545 // but V8's AST represents the negative literals as Literals. |
1500 return AsmType::Signed(); | 1546 return AsmType::Signed(); |
1501 } | 1547 } |
1502 | 1548 |
1503 static const uint32_t LargestFixNum = std::numeric_limits<int32_t>::max(); | |
1504 if (value <= LargestFixNum) { | 1549 if (value <= LargestFixNum) { |
1505 return AsmType::FixNum(); | 1550 return AsmType::FixNum(); |
1506 } | 1551 } |
1507 | 1552 |
1508 return AsmType::Unsigned(); | 1553 return AsmType::Unsigned(); |
1509 } | 1554 } |
1510 | 1555 |
1511 // 6.8.3 Identifier | 1556 // 6.8.3 Identifier |
1512 AsmType* AsmTyper::ValidateIdentifier(VariableProxy* proxy) { | 1557 AsmType* AsmTyper::ValidateIdentifier(VariableProxy* proxy) { |
1513 auto* proxy_info = Lookup(proxy->var()); | 1558 auto* proxy_info = Lookup(proxy->var()); |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1580 | 1625 |
1581 return value_type; | 1626 return value_type; |
1582 } | 1627 } |
1583 | 1628 |
1584 if (auto* target_as_property = assignment->target()->AsProperty()) { | 1629 if (auto* target_as_property = assignment->target()->AsProperty()) { |
1585 AsmType* allowed_store_types; | 1630 AsmType* allowed_store_types; |
1586 RECURSE(allowed_store_types = | 1631 RECURSE(allowed_store_types = |
1587 ValidateHeapAccess(target_as_property, StoreToHeap)); | 1632 ValidateHeapAccess(target_as_property, StoreToHeap)); |
1588 | 1633 |
1589 // TODO(jpp): Change FloatishDoubleQ and FloatQDoubleQ so that they are base | 1634 // TODO(jpp): Change FloatishDoubleQ and FloatQDoubleQ so that they are base |
1590 // classes for Floatish, DoubleQ, and FloatQ, and then invert this if so | 1635 // classes for Floatish, DoubleQ, and FloatQ. |
1591 // that it reads more naturally as | 1636 if (allowed_store_types == AsmType::FloatishDoubleQ()) { |
1592 // | 1637 if (!value_type->IsA(AsmType::Floatish()) && |
1593 // if (!value_type->IsA(allowed_store_types)) | 1638 !value_type->IsA(AsmType::DoubleQ())) { |
1594 if (allowed_store_types == AsmType::FloatishDoubleQ() || | 1639 FAIL(assignment, "Type mismatch in heap assignment."); |
1595 allowed_store_types == AsmType::FloatQDoubleQ()) { | 1640 } |
1596 if (!allowed_store_types->IsA(value_type)) { | 1641 } else if (allowed_store_types == AsmType::FloatQDoubleQ()) { |
| 1642 if (!value_type->IsA(AsmType::FloatQ()) && |
| 1643 !value_type->IsA(AsmType::DoubleQ())) { |
1597 FAIL(assignment, "Type mismatch in heap assignment."); | 1644 FAIL(assignment, "Type mismatch in heap assignment."); |
1598 } | 1645 } |
1599 } else { | 1646 } else { |
1600 if (!value_type->IsA(allowed_store_types)) { | 1647 if (!value_type->IsA(allowed_store_types)) { |
1601 FAIL(assignment, "Type mismatch in heap assignment."); | 1648 FAIL(assignment, "Type mismatch in heap assignment."); |
1602 } | 1649 } |
1603 } | 1650 } |
1604 | 1651 |
1605 return value_type; | 1652 return value_type; |
1606 } | 1653 } |
(...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1771 auto* left = binop->left(); | 1818 auto* left = binop->left(); |
1772 auto* left_as_binop = left->AsBinaryOperation(); | 1819 auto* left_as_binop = left->AsBinaryOperation(); |
1773 AsmType* left_type; | 1820 AsmType* left_type; |
1774 | 1821 |
1775 // TODO(jpp): maybe use an iterative approach instead of the recursion to | 1822 // TODO(jpp): maybe use an iterative approach instead of the recursion to |
1776 // ValidateAdditiveExpression. | 1823 // ValidateAdditiveExpression. |
1777 if (left_as_binop != nullptr && (left_as_binop->op() == Token::ADD || | 1824 if (left_as_binop != nullptr && (left_as_binop->op() == Token::ADD || |
1778 left_as_binop->op() == Token::SUB)) { | 1825 left_as_binop->op() == Token::SUB)) { |
1779 RECURSE(left_type = | 1826 RECURSE(left_type = |
1780 ValidateAdditiveExpression(left_as_binop, intish_count + 1)); | 1827 ValidateAdditiveExpression(left_as_binop, intish_count + 1)); |
| 1828 SetTypeOf(left_as_binop, left_type); |
1781 } else { | 1829 } else { |
1782 RECURSE(left_type = ValidateExpression(left)); | 1830 RECURSE(left_type = ValidateExpression(left)); |
1783 } | 1831 } |
1784 | 1832 |
1785 auto* right = binop->right(); | 1833 auto* right = binop->right(); |
1786 auto* right_as_binop = right->AsBinaryOperation(); | 1834 auto* right_as_binop = right->AsBinaryOperation(); |
1787 AsmType* right_type; | 1835 AsmType* right_type; |
1788 | 1836 |
1789 if (right_as_binop != nullptr && (right_as_binop->op() == Token::ADD || | 1837 if (right_as_binop != nullptr && (right_as_binop->op() == Token::ADD || |
1790 right_as_binop->op() == Token::SUB)) { | 1838 right_as_binop->op() == Token::SUB)) { |
1791 RECURSE(right_type = | 1839 RECURSE(right_type = |
1792 ValidateAdditiveExpression(right_as_binop, intish_count + 1)); | 1840 ValidateAdditiveExpression(right_as_binop, intish_count + 1)); |
| 1841 SetTypeOf(right_as_binop, right_type); |
1793 } else { | 1842 } else { |
1794 RECURSE(right_type = ValidateExpression(right)); | 1843 RECURSE(right_type = ValidateExpression(right)); |
1795 } | 1844 } |
1796 | 1845 |
1797 if (left_type->IsA(AsmType::FloatQ()) && right_type->IsA(AsmType::FloatQ())) { | 1846 if (left_type->IsA(AsmType::FloatQ()) && right_type->IsA(AsmType::FloatQ())) { |
1798 return AsmType::Floatish(); | 1847 return AsmType::Floatish(); |
1799 } | 1848 } |
1800 | 1849 |
1801 if (left_type->IsA(AsmType::Int()) && right_type->IsA(AsmType::Int())) { | 1850 if (left_type->IsA(AsmType::Int()) && right_type->IsA(AsmType::Int())) { |
1802 if (intish_count == 0) { | 1851 if (intish_count == 0) { |
(...skipping 274 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2077 if (as_literal->raw_value()->ContainsDot()) { | 2126 if (as_literal->raw_value()->ContainsDot()) { |
2078 return false; | 2127 return false; |
2079 } | 2128 } |
2080 | 2129 |
2081 if (!as_literal->value()->ToUint32(value)) { | 2130 if (!as_literal->value()->ToUint32(value)) { |
2082 return false; | 2131 return false; |
2083 } | 2132 } |
2084 | 2133 |
2085 return base::bits::IsPowerOfTwo32(1 + *value); | 2134 return base::bits::IsPowerOfTwo32(1 + *value); |
2086 } | 2135 } |
2087 | |
2088 // TODO(jpp): Add a AsmType::ValidateCall is poorly designed. It can only handle | |
2089 // function declarations, not invocations. CheckInvocationOf temporarily works | |
2090 // around this limitation by converting each actual in actuals to a parameter | |
2091 // type before invoking prototype->ValidateCall. This is the wrong behavior for | |
2092 // FFIs (we need to pass Signed integers to FFIs, not Ints), so that case is | |
2093 // handled separately. | |
2094 bool CheckInvocationOf(AsmCallableType* prototype, AsmType* return_type, | |
2095 ZoneVector<AsmType*>* actuals) { | |
2096 if (auto* ffi = prototype->AsFFIType()) { | |
2097 return ffi->ValidateCall(return_type, *actuals) != AsmType::None(); | |
2098 } | |
2099 | |
2100 for (size_t ii = 0; ii < actuals->size(); ++ii) { | |
2101 (*actuals)[ii] = (*actuals)[ii]->ToParameterType(); | |
2102 } | |
2103 return prototype->ValidateCall(return_type, *actuals) != AsmType::None(); | |
2104 } | |
2105 | |
2106 } // namespace | 2136 } // namespace |
2107 | 2137 |
2108 AsmType* AsmTyper::ValidateCall(AsmType* return_type, Call* call) { | 2138 AsmType* AsmTyper::ValidateCall(AsmType* return_type, Call* call) { |
2109 AsmType* float_coercion_type; | 2139 AsmType* float_coercion_type; |
2110 RECURSE(float_coercion_type = ValidateFloatCoercion(call)); | 2140 RECURSE(float_coercion_type = ValidateFloatCoercion(call)); |
2111 if (float_coercion_type == AsmType::Float()) { | 2141 if (float_coercion_type == AsmType::Float()) { |
2112 return AsmType::Float(); | 2142 SetTypeOf(call, AsmType::Float()); |
| 2143 return return_type; |
2113 } | 2144 } |
2114 | 2145 |
2115 // TODO(jpp): we should be able to reuse the args vector's storage space. | 2146 // TODO(jpp): we should be able to reuse the args vector's storage space. |
2116 ZoneVector<AsmType*> args(zone_); | 2147 ZoneVector<AsmType*> args(zone_); |
2117 args.reserve(call->arguments()->length()); | 2148 args.reserve(call->arguments()->length()); |
2118 | 2149 |
2119 for (auto* arg : *call->arguments()) { | 2150 for (auto* arg : *call->arguments()) { |
2120 AsmType* arg_type; | 2151 AsmType* arg_type; |
2121 RECURSE(arg_type = ValidateExpression(arg)); | 2152 RECURSE(arg_type = ValidateExpression(arg)); |
2122 args.emplace_back(arg_type); | 2153 args.emplace_back(arg_type); |
(...skipping 18 matching lines...) Expand all Loading... |
2141 fun_info->set_mutability(VariableInfo::kImmutableGlobal); | 2172 fun_info->set_mutability(VariableInfo::kImmutableGlobal); |
2142 AddForwardReference(call_var_proxy, fun_info); | 2173 AddForwardReference(call_var_proxy, fun_info); |
2143 if (!ValidAsmIdentifier(call_var_proxy->name())) { | 2174 if (!ValidAsmIdentifier(call_var_proxy->name())) { |
2144 FAIL(call_var_proxy, | 2175 FAIL(call_var_proxy, |
2145 "Invalid asm.js identifier in (forward) function name."); | 2176 "Invalid asm.js identifier in (forward) function name."); |
2146 } | 2177 } |
2147 if (!AddGlobal(call_var_proxy->var(), fun_info)) { | 2178 if (!AddGlobal(call_var_proxy->var(), fun_info)) { |
2148 DCHECK(false); | 2179 DCHECK(false); |
2149 FAIL(call, "Redeclared global identifier."); | 2180 FAIL(call, "Redeclared global identifier."); |
2150 } | 2181 } |
| 2182 SetTypeOf(call_var_proxy, reinterpret_cast<AsmType*>(call_type)); |
| 2183 SetTypeOf(call, return_type); |
2151 return return_type; | 2184 return return_type; |
2152 } | 2185 } |
2153 | 2186 |
2154 auto* callee_type = call_var_info->type()->AsCallableType(); | 2187 auto* callee_type = call_var_info->type()->AsCallableType(); |
2155 if (callee_type == nullptr) { | 2188 if (callee_type == nullptr) { |
2156 FAIL(call, "Calling something that's not a function."); | 2189 FAIL(call, "Calling something that's not a function."); |
2157 } | 2190 } |
2158 | 2191 |
2159 if (callee_type->AsFFIType() != nullptr && | 2192 if (callee_type->AsFFIType() != nullptr && |
2160 return_type == AsmType::Float()) { | 2193 return_type == AsmType::Float()) { |
2161 FAIL(call, "Foreign functions can't return float."); | 2194 FAIL(call, "Foreign functions can't return float."); |
2162 } | 2195 } |
2163 | 2196 |
2164 if (!CheckInvocationOf(callee_type, return_type, &args)) { | 2197 if (!callee_type->CanBeInvokedWith(return_type, args)) { |
2165 FAIL(call, "Function invocation does not match function type."); | 2198 FAIL(call, "Function invocation does not match function type."); |
2166 } | 2199 } |
2167 | 2200 |
| 2201 SetTypeOf(call_var_proxy, call_var_info->type()); |
| 2202 SetTypeOf(call, return_type); |
2168 return return_type; | 2203 return return_type; |
2169 } | 2204 } |
2170 | 2205 |
2171 // identifier[expr & n](Expression...) | 2206 // identifier[expr & n](Expression...) |
2172 if (auto* call_property = call_expr->AsProperty()) { | 2207 if (auto* call_property = call_expr->AsProperty()) { |
2173 auto* index = call_property->key()->AsBinaryOperation(); | 2208 auto* index = call_property->key()->AsBinaryOperation(); |
2174 if (index == nullptr || index->op() != Token::BIT_AND) { | 2209 if (index == nullptr || index->op() != Token::BIT_AND) { |
2175 FAIL(call_property->key(), | 2210 FAIL(call_property->key(), |
2176 "Indirect call index must be in the expr & mask form."); | 2211 "Indirect call index must be in the expr & mask form."); |
2177 } | 2212 } |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2214 fun_info->set_mutability(VariableInfo::kImmutableGlobal); | 2249 fun_info->set_mutability(VariableInfo::kImmutableGlobal); |
2215 AddForwardReference(name_var, fun_info); | 2250 AddForwardReference(name_var, fun_info); |
2216 if (!ValidAsmIdentifier(name_var->name())) { | 2251 if (!ValidAsmIdentifier(name_var->name())) { |
2217 FAIL(name_var, | 2252 FAIL(name_var, |
2218 "Invalid asm.js identifier in (forward) function table name."); | 2253 "Invalid asm.js identifier in (forward) function table name."); |
2219 } | 2254 } |
2220 if (!AddGlobal(name_var->var(), fun_info)) { | 2255 if (!AddGlobal(name_var->var(), fun_info)) { |
2221 DCHECK(false); | 2256 DCHECK(false); |
2222 FAIL(call, "Redeclared global identifier."); | 2257 FAIL(call, "Redeclared global identifier."); |
2223 } | 2258 } |
| 2259 SetTypeOf(call_property, reinterpret_cast<AsmType*>(call_type)); |
| 2260 SetTypeOf(call, return_type); |
2224 return return_type; | 2261 return return_type; |
2225 } | 2262 } |
2226 | 2263 |
2227 auto* previous_type = name_info->type()->AsFunctionTableType(); | 2264 auto* previous_type = name_info->type()->AsFunctionTableType(); |
2228 if (previous_type == nullptr) { | 2265 if (previous_type == nullptr) { |
2229 FAIL(call, "Identifier does not name a function table."); | 2266 FAIL(call, "Identifier does not name a function table."); |
2230 } | 2267 } |
2231 | 2268 |
2232 if (table_length != previous_type->length()) { | 2269 if (table_length != previous_type->length()) { |
2233 FAIL(call, "Function table size does not match expected size."); | 2270 FAIL(call, "Function table size does not match expected size."); |
2234 } | 2271 } |
2235 | 2272 |
2236 auto* previous_type_signature = | 2273 auto* previous_type_signature = |
2237 previous_type->signature()->AsFunctionType(); | 2274 previous_type->signature()->AsFunctionType(); |
2238 DCHECK(previous_type_signature != nullptr); | 2275 DCHECK(previous_type_signature != nullptr); |
2239 if (!CheckInvocationOf(previous_type_signature, return_type, &args)) { | 2276 if (!previous_type_signature->CanBeInvokedWith(return_type, args)) { |
| 2277 // TODO(jpp): better error messages. |
2240 FAIL(call, | 2278 FAIL(call, |
2241 "Function pointer table signature does not match previous " | 2279 "Function pointer table signature does not match previous " |
2242 "signature."); | 2280 "signature."); |
2243 } | 2281 } |
2244 | 2282 |
| 2283 SetTypeOf(call_property, previous_type->signature()); |
| 2284 SetTypeOf(call, return_type); |
2245 return return_type; | 2285 return return_type; |
2246 } | 2286 } |
2247 | 2287 |
2248 FAIL(call, "Invalid call."); | 2288 FAIL(call, "Invalid call."); |
2249 } | 2289 } |
2250 | 2290 |
2251 // 6.10 ValidateHeapAccess | 2291 // 6.10 ValidateHeapAccess |
2252 namespace { | 2292 namespace { |
2253 bool ExtractHeapAccessShift(Expression* expr, uint32_t* value) { | 2293 bool ExtractHeapAccessShift(Expression* expr, uint32_t* value) { |
2254 auto* as_literal = expr->AsLiteral(); | 2294 auto* as_literal = expr->AsLiteral(); |
(...skipping 18 matching lines...) Expand all Loading... |
2273 | 2313 |
2274 auto* obj_info = Lookup(obj->var()); | 2314 auto* obj_info = Lookup(obj->var()); |
2275 if (obj_info == nullptr) { | 2315 if (obj_info == nullptr) { |
2276 FAIL(heap, "Undeclared identifier in heap access."); | 2316 FAIL(heap, "Undeclared identifier in heap access."); |
2277 } | 2317 } |
2278 | 2318 |
2279 auto* obj_type = obj_info->type(); | 2319 auto* obj_type = obj_info->type(); |
2280 if (!obj_type->IsA(AsmType::Heap())) { | 2320 if (!obj_type->IsA(AsmType::Heap())) { |
2281 FAIL(heap, "Identifier does not represent a heap view."); | 2321 FAIL(heap, "Identifier does not represent a heap view."); |
2282 } | 2322 } |
| 2323 SetTypeOf(obj, obj_type); |
2283 | 2324 |
2284 if (auto* key_as_literal = heap->key()->AsLiteral()) { | 2325 if (auto* key_as_literal = heap->key()->AsLiteral()) { |
2285 if (key_as_literal->raw_value()->ContainsDot()) { | 2326 if (key_as_literal->raw_value()->ContainsDot()) { |
2286 FAIL(key_as_literal, "Heap access index must be intish."); | 2327 FAIL(key_as_literal, "Heap access index must be intish."); |
2287 } | 2328 } |
2288 | 2329 |
2289 uint32_t _; | 2330 uint32_t _; |
2290 if (!key_as_literal->value()->ToUint32(&_)) { | 2331 if (!key_as_literal->value()->ToUint32(&_)) { |
2291 FAIL(key_as_literal, | 2332 FAIL(key_as_literal, |
2292 "Heap access index must be a 32-bit unsigned integer."); | 2333 "Heap access index must be a 32-bit unsigned integer."); |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2364 if (auto* arg_as_call = arg->AsCall()) { | 2405 if (auto* arg_as_call = arg->AsCall()) { |
2365 RECURSE(ValidateCall(AsmType::Float(), arg_as_call)); | 2406 RECURSE(ValidateCall(AsmType::Float(), arg_as_call)); |
2366 return AsmType::Float(); | 2407 return AsmType::Float(); |
2367 } | 2408 } |
2368 | 2409 |
2369 // 2. fround is used for converting to float. | 2410 // 2. fround is used for converting to float. |
2370 AsmType* arg_type; | 2411 AsmType* arg_type; |
2371 RECURSE(arg_type = ValidateExpression(arg)); | 2412 RECURSE(arg_type = ValidateExpression(arg)); |
2372 if (arg_type->IsA(AsmType::Floatish()) || arg_type->IsA(AsmType::DoubleQ()) || | 2413 if (arg_type->IsA(AsmType::Floatish()) || arg_type->IsA(AsmType::DoubleQ()) || |
2373 arg_type->IsA(AsmType::Signed()) || arg_type->IsA(AsmType::Unsigned())) { | 2414 arg_type->IsA(AsmType::Signed()) || arg_type->IsA(AsmType::Unsigned())) { |
| 2415 SetTypeOf(call->expression(), fround_type_); |
2374 return AsmType::Float(); | 2416 return AsmType::Float(); |
2375 } | 2417 } |
2376 | 2418 |
2377 FAIL(call, "Invalid argument type to fround."); | 2419 FAIL(call, "Invalid argument type to fround."); |
2378 } | 2420 } |
2379 | 2421 |
2380 // 5.1 ParameterTypeAnnotations | 2422 // 5.1 ParameterTypeAnnotations |
2381 AsmType* AsmTyper::ParameterTypeAnnotations(Variable* parameter, | 2423 AsmType* AsmTyper::ParameterTypeAnnotations(Variable* parameter, |
2382 Expression* annotation) { | 2424 Expression* annotation) { |
2383 if (auto* binop = annotation->AsBinaryOperation()) { | 2425 if (auto* binop = annotation->AsBinaryOperation()) { |
2384 // Must be: | 2426 // Must be: |
2385 // * x|0 | 2427 // * x|0 |
2386 // * x*1 (*VIOLATION* i.e.,, +x) | 2428 // * x*1 (*VIOLATION* i.e.,, +x) |
2387 auto* left = binop->left()->AsVariableProxy(); | 2429 auto* left = binop->left()->AsVariableProxy(); |
2388 if (left == nullptr) { | 2430 if (left == nullptr) { |
2389 FAIL( | 2431 FAIL( |
2390 binop->left(), | 2432 binop->left(), |
2391 "Invalid parameter type annotation - should annotate an identifier."); | 2433 "Invalid parameter type annotation - should annotate an identifier."); |
2392 } | 2434 } |
2393 if (left->var() != parameter) { | 2435 if (left->var() != parameter) { |
2394 FAIL(binop->left(), | 2436 FAIL(binop->left(), |
2395 "Invalid parameter type annotation - should annotate a parameter."); | 2437 "Invalid parameter type annotation - should annotate a parameter."); |
2396 } | 2438 } |
2397 if (IsDoubleAnnotation(binop)) { | 2439 if (IsDoubleAnnotation(binop)) { |
| 2440 SetTypeOf(left, AsmType::Double()); |
2398 return AsmType::Double(); | 2441 return AsmType::Double(); |
2399 } | 2442 } |
2400 if (IsIntAnnotation(binop)) { | 2443 if (IsIntAnnotation(binop)) { |
| 2444 SetTypeOf(left, AsmType::Int()); |
2401 return AsmType::Int(); | 2445 return AsmType::Int(); |
2402 } | 2446 } |
2403 FAIL(binop, "Invalid parameter type annotation."); | 2447 FAIL(binop, "Invalid parameter type annotation."); |
2404 } | 2448 } |
2405 | 2449 |
2406 auto* call = annotation->AsCall(); | 2450 auto* call = annotation->AsCall(); |
2407 if (call == nullptr) { | 2451 if (call == nullptr) { |
2408 FAIL( | 2452 FAIL( |
2409 annotation, | 2453 annotation, |
2410 "Invalid float parameter type annotation - must be fround(parameter)."); | 2454 "Invalid float parameter type annotation - must be fround(parameter)."); |
(...skipping 10 matching lines...) Expand all Loading... |
2421 "Invalid float parameter type annotation - argument to fround is not " | 2465 "Invalid float parameter type annotation - argument to fround is not " |
2422 "an identifier."); | 2466 "an identifier."); |
2423 } | 2467 } |
2424 | 2468 |
2425 if (src_expr->var() != parameter) { | 2469 if (src_expr->var() != parameter) { |
2426 FAIL(annotation, | 2470 FAIL(annotation, |
2427 "Invalid float parameter type annotation - argument to fround is not " | 2471 "Invalid float parameter type annotation - argument to fround is not " |
2428 "a parameter."); | 2472 "a parameter."); |
2429 } | 2473 } |
2430 | 2474 |
| 2475 SetTypeOf(src_expr, AsmType::Float()); |
2431 return AsmType::Float(); | 2476 return AsmType::Float(); |
2432 } | 2477 } |
2433 | 2478 |
2434 // 5.2 ReturnTypeAnnotations | 2479 // 5.2 ReturnTypeAnnotations |
2435 AsmType* AsmTyper::ReturnTypeAnnotations(ReturnStatement* statement) { | 2480 AsmType* AsmTyper::ReturnTypeAnnotations(ReturnStatement* statement) { |
2436 if (statement == nullptr) { | 2481 if (statement == nullptr) { |
2437 return AsmType::Void(); | 2482 return AsmType::Void(); |
2438 } | 2483 } |
2439 | 2484 |
2440 auto* ret_expr = statement->expression(); | 2485 auto* ret_expr = statement->expression(); |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2478 } | 2523 } |
2479 | 2524 |
2480 FAIL(statement, "Invalid return type expression."); | 2525 FAIL(statement, "Invalid return type expression."); |
2481 } | 2526 } |
2482 | 2527 |
2483 // 5.4 VariableTypeAnnotations | 2528 // 5.4 VariableTypeAnnotations |
2484 // Also used for 5.5 GlobalVariableTypeAnnotations | 2529 // Also used for 5.5 GlobalVariableTypeAnnotations |
2485 AsmType* AsmTyper::VariableTypeAnnotations(Expression* initializer) { | 2530 AsmType* AsmTyper::VariableTypeAnnotations(Expression* initializer) { |
2486 if (auto* literal = initializer->AsLiteral()) { | 2531 if (auto* literal = initializer->AsLiteral()) { |
2487 if (literal->raw_value()->ContainsDot()) { | 2532 if (literal->raw_value()->ContainsDot()) { |
| 2533 SetTypeOf(initializer, AsmType::Double()); |
2488 return AsmType::Double(); | 2534 return AsmType::Double(); |
2489 } | 2535 } |
2490 int32_t i32; | 2536 int32_t i32; |
2491 uint32_t u32; | 2537 uint32_t u32; |
2492 if (literal->value()->ToInt32(&i32) || literal->value()->ToUint32(&u32)) { | 2538 if (literal->value()->ToUint32(&u32)) { |
2493 return AsmType::Int(); | 2539 if (u32 > LargestFixNum) { |
| 2540 SetTypeOf(initializer, AsmType::Unsigned()); |
| 2541 } else { |
| 2542 SetTypeOf(initializer, AsmType::FixNum()); |
| 2543 } |
| 2544 } else if (literal->value()->ToInt32(&i32)) { |
| 2545 SetTypeOf(initializer, AsmType::Signed()); |
| 2546 } else { |
| 2547 FAIL(initializer, "Invalid type annotation - forbidden literal."); |
2494 } | 2548 } |
2495 FAIL(initializer, "Invalid type annotation - forbidden literal."); | 2549 return AsmType::Int(); |
2496 } | 2550 } |
2497 | 2551 |
2498 auto* call = initializer->AsCall(); | 2552 auto* call = initializer->AsCall(); |
2499 DCHECK(call != nullptr); | |
2500 if (call == nullptr) { | 2553 if (call == nullptr) { |
2501 FAIL(initializer, | 2554 FAIL(initializer, |
2502 "Invalid variable initialization - it should be a literal, or " | 2555 "Invalid variable initialization - it should be a literal, or " |
2503 "fround(literal)."); | 2556 "fround(literal)."); |
2504 } | 2557 } |
2505 | 2558 |
2506 if (!IsCallToFround(call)) { | 2559 if (!IsCallToFround(call)) { |
2507 FAIL(initializer, | 2560 FAIL(initializer, |
2508 "Invalid float coercion - expected call fround(literal)."); | 2561 "Invalid float coercion - expected call fround(literal)."); |
2509 } | 2562 } |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2576 return true; | 2629 return true; |
2577 } | 2630 } |
2578 | 2631 |
2579 *error_message = typer.error_message(); | 2632 *error_message = typer.error_message(); |
2580 return false; | 2633 return false; |
2581 } | 2634 } |
2582 | 2635 |
2583 } // namespace wasm | 2636 } // namespace wasm |
2584 } // namespace internal | 2637 } // namespace internal |
2585 } // namespace v8 | 2638 } // namespace v8 |
OLD | NEW |