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 3 // found in the LICENSE file. 4 5 #include "src/asmjs/asm-typer.h" 6 7 #include <algorithm> 8 #include <limits> 9 #include <memory> 10 #include <string> 11 12 #include "src/v8.h" 13 14 #include "src/asmjs/asm-types.h" 15 #include "src/ast/ast.h" 16 #include "src/ast/scopes.h" 17 #include "src/base/bits.h" 18 #include "src/codegen.h" 19 #include "src/globals.h" 20 #include "src/utils.h" 21 22 #define FAIL(node, msg) \ 23 do { \ 24 int line = node->position() == kNoSourcePosition \ 25 ? -1 \ 26 : script_->GetLineNumber(node->position()); \ 27 base::OS::SNPrintF(error_message_, sizeof(error_message_), \ 28 "asm: line %d: %s\n", line + 1, msg); \ 29 return AsmType::None(); \ 30 } while (false) 31 32 #define RECURSE(call) \ 33 do { \ 34 if (GetCurrentStackPosition() < stack_limit_) { \ 35 stack_overflow_ = true; \ 36 FAIL(root_, "Stack overflow while parsing asm.js module."); \ 37 } \ 38 \ 39 AsmType* result = (call); \ 40 if (stack_overflow_) { \ 41 return AsmType::None(); \ 42 } \ 43 \ 44 if (result == AsmType::None()) { \ 45 return AsmType::None(); \ 46 } \ 47 } while (false) 48 49 namespace v8 { 50 namespace internal { 51 namespace wasm { 52 namespace { 53 static const uint32_t LargestFixNum = std::numeric_limits<int32_t>::max(); 54 } // namespace 55 56 using v8::internal::AstNode; 57 using v8::internal::GetCurrentStackPosition; 58 59 // ---------------------------------------------------------------------------- 60 // Implementation of AsmTyper::FlattenedStatements 61 62 AsmTyper::FlattenedStatements::FlattenedStatements(Zone* zone, 63 ZoneList<Statement*>* s) 64 : context_stack_(zone) { 65 context_stack_.emplace_back(Context(s)); 66 } 67 68 Statement* AsmTyper::FlattenedStatements::Next() { 69 for (;;) { 70 if (context_stack_.empty()) { 71 return nullptr; 72 } 73 74 Context* current = &context_stack_.back(); 75 76 if (current->statements_->length() <= current->next_index_) { 77 context_stack_.pop_back(); 78 continue; 79 } 80 81 Statement* current_statement = 82 current->statements_->at(current->next_index_++); 83 if (current_statement->IsBlock()) { 84 context_stack_.emplace_back( 85 Context(current_statement->AsBlock()->statements())); 86 continue; 87 } 88 89 return current_statement; 90 } 91 } 92 93 // ---------------------------------------------------------------------------- 94 // Implementation of AsmTyper::VariableInfo 95 96 AsmTyper::VariableInfo* AsmTyper::VariableInfo::ForSpecialSymbol( 97 Zone* zone, StandardMember standard_member) { 98 DCHECK(standard_member == kStdlib || standard_member == kFFI || 99 standard_member == kHeap || standard_member == kModule); 100 auto* new_var_info = new (zone) VariableInfo(AsmType::None()); 101 new_var_info->standard_member_ = standard_member; 102 new_var_info->mutability_ = kImmutableGlobal; 103 return new_var_info; 104 } 105 106 AsmTyper::VariableInfo* AsmTyper::VariableInfo::Clone(Zone* zone) const { 107 CHECK(standard_member_ != kNone); 108 CHECK(!type_->IsA(AsmType::None())); 109 auto* new_var_info = new (zone) VariableInfo(type_); 110 new_var_info->standard_member_ = standard_member_; 111 new_var_info->mutability_ = mutability_; 112 return new_var_info; 113 } 114 115 void AsmTyper::VariableInfo::FirstForwardUseIs(VariableProxy* var) { 116 DCHECK(first_forward_use_ == nullptr); 117 missing_definition_ = true; 118 first_forward_use_ = var; 119 } 120 121 // ---------------------------------------------------------------------------- 122 // Implementation of AsmTyper 123 124 AsmTyper::AsmTyper(Isolate* isolate, Zone* zone, Script* script, 125 FunctionLiteral* root) 126 : isolate_(isolate), 127 zone_(zone), 128 script_(script), 129 root_(root), 130 forward_definitions_(zone), 131 ffi_use_signatures_(zone), 132 stdlib_types_(zone), 133 stdlib_math_types_(zone), 134 module_info_(VariableInfo::ForSpecialSymbol(zone_, kModule)), 135 global_scope_(ZoneHashMap::kDefaultHashMapCapacity, 136 ZoneAllocationPolicy(zone)), 137 local_scope_(ZoneHashMap::kDefaultHashMapCapacity, 138 ZoneAllocationPolicy(zone)), 139 stack_limit_(isolate->stack_guard()->real_climit()), 140 node_types_(zone_), 141 fround_type_(AsmType::FroundType(zone_)), 142 ffi_type_(AsmType::FFIType(zone_)) { 143 InitializeStdlib(); 144 } 145 146 namespace { 147 bool ValidAsmIdentifier(Handle<String> name) { 148 static const char* kInvalidAsmNames[] = {"eval", "arguments"}; 149 150 for (size_t ii = 0; ii < arraysize(kInvalidAsmNames); ++ii) { 151 if (strcmp(name->ToCString().get(), kInvalidAsmNames[ii]) == 0) { 152 return false; 153 } 154 } 155 return true; 156 } 157 } // namespace 158 159 void AsmTyper::InitializeStdlib() { 160 auto* d = AsmType::Double(); 161 auto* dq = AsmType::DoubleQ(); 162 auto* dq2d = AsmType::Function(zone_, d); 163 dq2d->AsFunctionType()->AddArgument(dq); 164 165 auto* dqdq2d = AsmType::Function(zone_, d); 166 dqdq2d->AsFunctionType()->AddArgument(dq); 167 dqdq2d->AsFunctionType()->AddArgument(dq); 168 169 auto* f = AsmType::Float(); 170 auto* fq = AsmType::FloatQ(); 171 auto* fq2f = AsmType::Function(zone_, f); 172 fq2f->AsFunctionType()->AddArgument(fq); 173 174 auto* s = AsmType::Signed(); 175 auto* s2s = AsmType::Function(zone_, s); 176 s2s->AsFunctionType()->AddArgument(s); 177 178 auto* i = AsmType::Int(); 179 auto* i2s = AsmType::Function(zone_, s); 180 i2s->AsFunctionType()->AddArgument(i); 181 182 auto* ii2s = AsmType::Function(zone_, s); 183 ii2s->AsFunctionType()->AddArgument(i); 184 ii2s->AsFunctionType()->AddArgument(i); 185 186 auto* minmax_d = AsmType::MinMaxType(zone_, d, d); 187 // *VIOLATION* The float variant is not part of the spec, but firefox accepts 188 // it. 189 auto* minmax_f = AsmType::MinMaxType(zone_, f, f); 190 auto* minmax_i = AsmType::MinMaxType(zone_, s, i); 191 auto* minmax = AsmType::OverloadedFunction(zone_); 192 minmax->AsOverloadedFunctionType()->AddOverload(minmax_i); 193 minmax->AsOverloadedFunctionType()->AddOverload(minmax_f); 194 minmax->AsOverloadedFunctionType()->AddOverload(minmax_d); 195 196 auto* fround = fround_type_; 197 198 auto* abs = AsmType::OverloadedFunction(zone_); 199 abs->AsOverloadedFunctionType()->AddOverload(s2s); 200 abs->AsOverloadedFunctionType()->AddOverload(dq2d); 201 abs->AsOverloadedFunctionType()->AddOverload(fq2f); 202 203 auto* ceil = AsmType::OverloadedFunction(zone_); 204 ceil->AsOverloadedFunctionType()->AddOverload(dq2d); 205 ceil->AsOverloadedFunctionType()->AddOverload(fq2f); 206 207 auto* floor = ceil; 208 auto* sqrt = ceil; 209 210 struct StandardMemberInitializer { 211 const char* name; 212 StandardMember standard_member; 213 AsmType* type; 214 }; 215 216 const StandardMemberInitializer stdlib[] = {{"Infinity", kInfinity, d}, 217 {"NaN", kNaN, d}, 218 #define ASM_TYPED_ARRAYS(V) \ 219 V(Uint8) \ 220 V(Int8) \ 221 V(Uint16) \ 222 V(Int16) \ 223 V(Uint32) \ 224 V(Int32) \ 225 V(Float32) \ 226 V(Float64) 227 228 #define ASM_TYPED_ARRAY(TypeName) \ 229 {#TypeName "Array", kNone, AsmType::TypeName##Array()}, 230 ASM_TYPED_ARRAYS(ASM_TYPED_ARRAY) 231 #undef ASM_TYPED_ARRAY 232 }; 233 for (size_t ii = 0; ii < arraysize(stdlib); ++ii) { 234 stdlib_types_[stdlib[ii].name] = new (zone_) VariableInfo(stdlib[ii].type); 235 stdlib_types_[stdlib[ii].name]->set_standard_member( 236 stdlib[ii].standard_member); 237 stdlib_types_[stdlib[ii].name]->set_mutability( 238 VariableInfo::kImmutableGlobal); 239 } 240 241 const StandardMemberInitializer math[] = { 242 {"PI", kMathPI, d}, 243 {"E", kMathE, d}, 244 {"LN2", kMathLN2, d}, 245 {"LN10", kMathLN10, d}, 246 {"LOG2E", kMathLOG2E, d}, 247 {"LOG10E", kMathLOG10E, d}, 248 {"SQRT2", kMathSQRT2, d}, 249 {"SQRT1_2", kMathSQRT1_2, d}, 250 {"imul", kMathImul, ii2s}, 251 {"abs", kMathAbs, abs}, 252 // NOTE: clz32 should return fixnum. The current typer can only return 253 // Signed, Float, or Double, so it returns Signed in our version of 254 // asm.js. 255 {"clz32", kMathClz32, i2s}, 256 {"ceil", kMathCeil, ceil}, 257 {"floor", kMathFloor, floor}, 258 {"fround", kMathFround, fround}, 259 {"pow", kMathPow, dqdq2d}, 260 {"exp", kMathExp, dq2d}, 261 {"log", kMathLog, dq2d}, 262 {"min", kMathMin, minmax}, 263 {"max", kMathMax, minmax}, 264 {"sqrt", kMathSqrt, sqrt}, 265 {"cos", kMathCos, dq2d}, 266 {"sin", kMathSin, dq2d}, 267 {"tan", kMathTan, dq2d}, 268 {"acos", kMathAcos, dq2d}, 269 {"asin", kMathAsin, dq2d}, 270 {"atan", kMathAtan, dq2d}, 271 {"atan2", kMathAtan2, dqdq2d}, 272 }; 273 for (size_t ii = 0; ii < arraysize(math); ++ii) { 274 stdlib_math_types_[math[ii].name] = new (zone_) VariableInfo(math[ii].type); 275 stdlib_math_types_[math[ii].name]->set_standard_member( 276 math[ii].standard_member); 277 stdlib_math_types_[math[ii].name]->set_mutability( 278 VariableInfo::kImmutableGlobal); 279 } 280 } 281 282 // Used for 5.5 GlobalVariableTypeAnnotations 283 AsmTyper::VariableInfo* AsmTyper::ImportLookup(Property* import) { 284 auto* obj = import->obj(); 285 auto* key = import->key()->AsLiteral(); 286 287 ObjectTypeMap* stdlib = &stdlib_types_; 288 if (auto* obj_as_property = obj->AsProperty()) { 289 // This can only be stdlib.Math 290 auto* math_name = obj_as_property->key()->AsLiteral(); 291 if (math_name == nullptr || !math_name->IsPropertyName()) { 292 return nullptr; 293 } 294 295 if (!math_name->AsPropertyName()->IsUtf8EqualTo(CStrVector("Math"))) { 296 return nullptr; 297 } 298 299 auto* stdlib_var_proxy = obj_as_property->obj()->AsVariableProxy(); 300 if (stdlib_var_proxy == nullptr) { 301 return nullptr; 302 } 303 obj = stdlib_var_proxy; 304 stdlib = &stdlib_math_types_; 305 } 306 307 auto* obj_as_var_proxy = obj->AsVariableProxy(); 308 if (obj_as_var_proxy == nullptr) { 309 return nullptr; 310 } 311 312 auto* obj_info = Lookup(obj_as_var_proxy->var()); 313 if (obj_info == nullptr) { 314 return nullptr; 315 } 316 317 if (obj_info->IsFFI()) { 318 // For FFI we can't validate import->key, so assume this is OK. 319 return obj_info; 320 } 321 322 std::unique_ptr<char[]> aname = key->AsPropertyName()->ToCString(); 323 ObjectTypeMap::iterator i = stdlib->find(std::string(aname.get())); 324 if (i == stdlib->end()) { 325 return nullptr; 326 } 327 stdlib_uses_.insert(i->second->standard_member()); 328 return i->second; 329 } 330 331 AsmTyper::VariableInfo* AsmTyper::Lookup(Variable* variable) const { 332 const ZoneHashMap* scope = in_function_ ? &local_scope_ : &global_scope_; 333 ZoneHashMap::Entry* entry = 334 scope->Lookup(variable, ComputePointerHash(variable)); 335 if (entry == nullptr && in_function_) { 336 entry = global_scope_.Lookup(variable, ComputePointerHash(variable)); 337 } 338 339 if (entry == nullptr && !module_name_.is_null() && 340 module_name_->Equals(*variable->name())) { 341 return module_info_; 342 } 343 344 return entry ? reinterpret_cast<VariableInfo*>(entry->value) : nullptr; 345 } 346 347 void AsmTyper::AddForwardReference(VariableProxy* proxy, VariableInfo* info) { 348 info->FirstForwardUseIs(proxy); 349 forward_definitions_.push_back(info); 350 } 351 352 bool AsmTyper::AddGlobal(Variable* variable, VariableInfo* info) { 353 // We can't DCHECK(!in_function_) because function may actually install global 354 // names (forward defined functions and function tables.) 355 DCHECK(info->mutability() != VariableInfo::kInvalidMutability); 356 DCHECK(info->IsGlobal()); 357 DCHECK(ValidAsmIdentifier(variable->name())); 358 359 if (!module_name_.is_null() && module_name_->Equals(*variable->name())) { 360 return false; 361 } 362 363 ZoneHashMap::Entry* entry = global_scope_.LookupOrInsert( 364 variable, ComputePointerHash(variable), ZoneAllocationPolicy(zone_)); 365 366 if (entry->value != nullptr) { 367 return false; 368 } 369 370 entry->value = info; 371 return true; 372 } 373 374 bool AsmTyper::AddLocal(Variable* variable, VariableInfo* info) { 375 DCHECK(in_function_); 376 DCHECK(info->mutability() != VariableInfo::kInvalidMutability); 377 DCHECK(!info->IsGlobal()); 378 DCHECK(ValidAsmIdentifier(variable->name())); 379 380 ZoneHashMap::Entry* entry = local_scope_.LookupOrInsert( 381 variable, ComputePointerHash(variable), ZoneAllocationPolicy(zone_)); 382 383 if (entry->value != nullptr) { 384 return false; 385 } 386 387 entry->value = info; 388 return true; 389 } 390 391 void AsmTyper::SetTypeOf(AstNode* node, AsmType* type) { 392 DCHECK_NE(type, AsmType::None()); 393 DCHECK(node_types_.find(node) == node_types_.end()); 394 node_types_.insert(std::make_pair(node, type)); 395 } 396 397 AsmType* AsmTyper::TypeOf(AstNode* node) const { 398 auto node_type_iter = node_types_.find(node); 399 if (node_type_iter != node_types_.end()) { 400 return node_type_iter->second; 401 } 402 403 // Sometimes literal nodes are not added to the node_type_ map simply because 404 // their are not visited with ValidateExpression(). 405 if (auto* literal = node->AsLiteral()) { 406 if (literal->raw_value()->ContainsDot()) { 407 return AsmType::Double(); 408 } 409 uint32_t u; 410 if (literal->value()->ToUint32(&u)) { 411 if (u > LargestFixNum) { 412 return AsmType::Unsigned(); 413 } 414 return AsmType::FixNum(); 415 } 416 int32_t i; 417 if (literal->value()->ToInt32(&i)) { 418 return AsmType::Signed(); 419 } 420 } 421 422 return AsmType::None(); 423 } 424 425 AsmType* AsmTyper::TypeOf(Variable* v) const { return Lookup(v)->type(); } 426 427 AsmTyper::StandardMember AsmTyper::VariableAsStandardMember(Variable* var) { 428 auto* var_info = Lookup(var); 429 if (var_info == nullptr) { 430 return kNone; 431 } 432 StandardMember member = var_info->standard_member(); 433 return member; 434 } 435 436 bool AsmTyper::Validate() { 437 if (!AsmType::None()->IsExactly(ValidateModule(root_))) { 438 return true; 439 } 440 return false; 441 } 442 443 namespace { 444 bool IsUseAsmDirective(Statement* first_statement) { 445 ExpressionStatement* use_asm = first_statement->AsExpressionStatement(); 446 if (use_asm == nullptr) { 447 return false; 448 } 449 450 Literal* use_asm_literal = use_asm->expression()->AsLiteral(); 451 452 if (use_asm_literal == nullptr) { 453 return false; 454 } 455 456 return use_asm_literal->raw_value()->AsString()->IsOneByteEqualTo("use asm"); 457 } 458 459 Assignment* ExtractInitializerExpression(Statement* statement) { 460 auto* expr_stmt = statement->AsExpressionStatement(); 461 if (expr_stmt == nullptr) { 462 // Done with initializers. 463 return nullptr; 464 } 465 auto* assign = expr_stmt->expression()->AsAssignment(); 466 if (assign == nullptr) { 467 // Done with initializers. 468 return nullptr; 469 } 470 if (assign->op() != Token::INIT) { 471 // Done with initializers. 472 return nullptr; 473 } 474 return assign; 475 } 476 477 } // namespace 478 479 // 6.1 ValidateModule 480 namespace { 481 // SourceLayoutTracker keeps track of the start and end positions of each 482 // section in the asm.js source. The sections should not overlap, otherwise the 483 // asm.js source is invalid. 484 class SourceLayoutTracker { 485 public: 486 SourceLayoutTracker() = default; 487 488 bool IsValid() const { 489 const Section* kAllSections[] = {&use_asm_, &globals_, &functions_, 490 &tables_, &exports_}; 491 for (size_t ii = 0; ii < arraysize(kAllSections); ++ii) { 492 const auto& curr_section = *kAllSections[ii]; 493 for (size_t jj = ii + 1; jj < arraysize(kAllSections); ++jj) { 494 if (curr_section.OverlapsWith(*kAllSections[jj])) { 495 return false; 496 } 497 } 498 } 499 return true; 500 } 501 502 void AddUseAsm(const AstNode& node) { use_asm_.AddNewElement(node); } 503 504 void AddGlobal(const AstNode& node) { globals_.AddNewElement(node); } 505 506 void AddFunction(const AstNode& node) { functions_.AddNewElement(node); } 507 508 void AddTable(const AstNode& node) { tables_.AddNewElement(node); } 509 510 void AddExport(const AstNode& node) { exports_.AddNewElement(node); } 511 512 private: 513 class Section { 514 public: 515 Section() = default; 516 Section(const Section&) = default; 517 Section& operator=(const Section&) = default; 518 519 void AddNewElement(const AstNode& node) { 520 const int node_pos = node.position(); 521 if (start_ == kNoSourcePosition) { 522 start_ = node_pos; 523 } else { 524 start_ = std::max(start_, node_pos); 525 } 526 if (end_ == kNoSourcePosition) { 527 end_ = node_pos; 528 } else { 529 end_ = std::max(end_, node_pos); 530 } 531 } 532 533 bool OverlapsWith(const Section& other) const { 534 if (start_ == kNoSourcePosition) { 535 DCHECK_EQ(end_, kNoSourcePosition); 536 return false; 537 } 538 if (other.start_ == kNoSourcePosition) { 539 DCHECK_EQ(other.end_, kNoSourcePosition); 540 return false; 541 } 542 return other.start_ < end_ || other.end_ < start_; 543 } 544 545 private: 546 int start_ = kNoSourcePosition; 547 int end_ = kNoSourcePosition; 548 }; 549 550 Section use_asm_; 551 Section globals_; 552 Section functions_; 553 Section tables_; 554 Section exports_; 555 556 DISALLOW_COPY_AND_ASSIGN(SourceLayoutTracker); 557 }; 558 } // namespace 559 560 AsmType* AsmTyper::ValidateModule(FunctionLiteral* fun) { 561 SourceLayoutTracker source_layout; 562 563 DeclarationScope* scope = fun->scope(); 564 if (!scope->is_function_scope()) FAIL(fun, "Not at function scope."); 565 if (!ValidAsmIdentifier(fun->name())) 566 FAIL(fun, "Invalid asm.js identifier in module name."); 567 module_name_ = fun->name(); 568 569 // Allowed parameters: Stdlib, FFI, Mem 570 static const int MaxModuleParameters = 3; 571 if (scope->num_parameters() > MaxModuleParameters) { 572 FAIL(fun, "asm.js modules may not have more than three parameters."); 573 } 574 575 struct { 576 StandardMember standard_member; 577 } kModuleParamInfo[3] = { 578 {kStdlib}, {kFFI}, {kHeap}, 579 }; 580 581 for (int ii = 0; ii < scope->num_parameters(); ++ii) { 582 Variable* param = scope->parameter(ii); 583 DCHECK(param); 584 585 if (!ValidAsmIdentifier(param->name())) { 586 FAIL(fun, "Invalid asm.js identifier in module parameter."); 587 } 588 589 auto* param_info = VariableInfo::ForSpecialSymbol( 590 zone_, kModuleParamInfo[ii].standard_member); 591 592 if (!AddGlobal(param, param_info)) { 593 FAIL(fun, "Redeclared identifier in module parameter."); 594 } 595 } 596 597 ZoneVector<Assignment*> function_pointer_tables(zone_); 598 FlattenedStatements iter(zone_, fun->body()); 599 auto* use_asm_directive = iter.Next(); 600 if (use_asm_directive == nullptr) { 601 FAIL(fun, "Missing \"use asm\"."); 602 } 603 // Check for extra assignment inserted by the parser when in this form: 604 // (function Module(a, b, c) {... }) 605 ExpressionStatement* estatement = use_asm_directive->AsExpressionStatement(); 606 if (estatement != nullptr) { 607 Assignment* assignment = estatement->expression()->AsAssignment(); 608 if (assignment != nullptr && assignment->target()->IsVariableProxy() && 609 assignment->target() 610 ->AsVariableProxy() 611 ->var() 612 ->is_sloppy_function_name()) { 613 use_asm_directive = iter.Next(); 614 } 615 } 616 if (!IsUseAsmDirective(use_asm_directive)) { 617 FAIL(fun, "Missing \"use asm\"."); 618 } 619 source_layout.AddUseAsm(*use_asm_directive); 620 ReturnStatement* module_return = nullptr; 621 622 // *VIOLATION* The spec states that globals should be followed by function 623 // declarations, which should be followed by function pointer tables, followed 624 // by the module export (return) statement. Our AST might be rearraged by the 625 // parser, so we can't rely on it being in source code order. 626 while (Statement* current = iter.Next()) { 627 if (auto* assign = ExtractInitializerExpression(current)) { 628 if (assign->value()->IsArrayLiteral()) { 629 // Save function tables for later validation. 630 function_pointer_tables.push_back(assign); 631 } else { 632 RECURSE(ValidateGlobalDeclaration(assign)); 633 source_layout.AddGlobal(*assign); 634 } 635 continue; 636 } 637 638 if (auto* current_as_return = current->AsReturnStatement()) { 639 if (module_return != nullptr) { 640 FAIL(fun, "Multiple export statements."); 641 } 642 module_return = current_as_return; 643 source_layout.AddExport(*module_return); 644 continue; 645 } 646 647 FAIL(current, "Invalid top-level statement in asm.js module."); 648 } 649 650 Declaration::List* decls = scope->declarations(); 651 for (Declaration* decl : *decls) { 652 if (FunctionDeclaration* fun_decl = decl->AsFunctionDeclaration()) { 653 RECURSE(ValidateFunction(fun_decl)); 654 source_layout.AddFunction(*fun_decl); 655 continue; 656 } 657 } 658 659 for (auto* function_table : function_pointer_tables) { 660 RECURSE(ValidateFunctionTable(function_table)); 661 source_layout.AddTable(*function_table); 662 } 663 664 for (Declaration* decl : *decls) { 665 if (decl->IsFunctionDeclaration()) { 666 continue; 667 } 668 669 VariableDeclaration* var_decl = decl->AsVariableDeclaration(); 670 if (var_decl == nullptr) { 671 FAIL(decl, "Invalid asm.js declaration."); 672 } 673 674 auto* var_proxy = var_decl->proxy(); 675 if (var_proxy == nullptr) { 676 FAIL(decl, "Invalid asm.js declaration."); 677 } 678 679 if (Lookup(var_proxy->var()) == nullptr) { 680 FAIL(decl, "Global variable missing initializer in asm.js module."); 681 } 682 } 683 684 // 6.2 ValidateExport 685 if (module_return == nullptr) { 686 FAIL(fun, "Missing asm.js module export."); 687 } 688 689 for (auto* forward_def : forward_definitions_) { 690 if (forward_def->missing_definition()) { 691 FAIL(forward_def->first_forward_use(), 692 "Missing definition for forward declared identifier."); 693 } 694 } 695 696 RECURSE(ValidateExport(module_return)); 697 698 if (!source_layout.IsValid()) { 699 FAIL(fun, "Invalid asm.js source code layout."); 700 } 701 702 return AsmType::Int(); // Any type that is not AsmType::None(); 703 } 704 705 namespace { 706 bool IsDoubleAnnotation(BinaryOperation* binop) { 707 // *VIOLATION* The parser replaces uses of +x with x*1.0. 708 if (binop->op() != Token::MUL) { 709 return false; 710 } 711 712 auto* right_as_literal = binop->right()->AsLiteral(); 713 if (right_as_literal == nullptr) { 714 return false; 715 } 716 717 return right_as_literal->raw_value()->ContainsDot() && 718 right_as_literal->raw_value()->AsNumber() == 1.0; 719 } 720 721 bool IsIntAnnotation(BinaryOperation* binop) { 722 if (binop->op() != Token::BIT_OR) { 723 return false; 724 } 725 726 auto* right_as_literal = binop->right()->AsLiteral(); 727 if (right_as_literal == nullptr) { 728 return false; 729 } 730 731 return !right_as_literal->raw_value()->ContainsDot() && 732 right_as_literal->raw_value()->AsNumber() == 0.0; 733 } 734 } // namespace 735 736 AsmType* AsmTyper::ValidateGlobalDeclaration(Assignment* assign) { 737 DCHECK(!assign->is_compound()); 738 if (assign->is_compound()) { 739 FAIL(assign, 740 "Compound assignment not supported when declaring global variables."); 741 } 742 743 auto* target = assign->target(); 744 if (!target->IsVariableProxy()) { 745 FAIL(target, "Module assignments may only assign to globals."); 746 } 747 auto* target_variable = target->AsVariableProxy()->var(); 748 auto* target_info = Lookup(target_variable); 749 750 if (target_info != nullptr) { 751 FAIL(target, "Redefined global variable."); 752 } 753 754 auto* value = assign->value(); 755 // Not all types of assignment are allowed by asm.js. See 756 // 5.5 Global Variable Type Annotations. 757 bool global_variable = false; 758 if (value->IsLiteral() || value->IsCall()) { 759 AsmType* type = nullptr; 760 VariableInfo::Mutability mutability; 761 if (target_variable->mode() == CONST) { 762 mutability = VariableInfo::kConstGlobal; 763 } else { 764 mutability = VariableInfo::kMutableGlobal; 765 } 766 RECURSE(type = VariableTypeAnnotations(value, mutability)); 767 target_info = new (zone_) VariableInfo(type); 768 target_info->set_mutability(mutability); 769 global_variable = true; 770 } else if (value->IsProperty()) { 771 target_info = ImportLookup(value->AsProperty()); 772 if (target_info == nullptr) { 773 FAIL(assign, "Invalid import."); 774 } 775 CHECK(target_info->mutability() == VariableInfo::kImmutableGlobal); 776 if (target_info->IsFFI()) { 777 // create a new target info that represents a foreign variable. 778 target_info = new (zone_) VariableInfo(ffi_type_); 779 target_info->set_mutability(VariableInfo::kImmutableGlobal); 780 } else if (target_info->type()->IsA(AsmType::Heap())) { 781 FAIL(assign, "Heap view types can not be aliased."); 782 } else { 783 target_info = target_info->Clone(zone_); 784 } 785 } else if (value->IsBinaryOperation()) { 786 // This should either be: 787 // 788 // var <> = ffi.<>|0 789 // 790 // or 791 // 792 // var <> = +ffi.<> 793 auto* value_binop = value->AsBinaryOperation(); 794 auto* left = value_binop->left(); 795 AsmType* import_type = nullptr; 796 797 if (IsDoubleAnnotation(value_binop)) { 798 import_type = AsmType::Double(); 799 } else if (IsIntAnnotation(value_binop)) { 800 import_type = AsmType::Int(); 801 } else { 802 FAIL(value, 803 "Invalid initializer for foreign import - unrecognized annotation."); 804 } 805 806 if (!left->IsProperty()) { 807 FAIL(value, 808 "Invalid initializer for foreign import - must import member."); 809 } 810 target_info = ImportLookup(left->AsProperty()); 811 if (target_info == nullptr) { 812 // TODO(jpp): this error message is innacurate: this may fail if the 813 // object lookup fails, or if the property lookup fails, or even if the 814 // import is bogus like a().c. 815 FAIL(value, 816 "Invalid initializer for foreign import - object lookup failed."); 817 } 818 CHECK(target_info->mutability() == VariableInfo::kImmutableGlobal); 819 if (!target_info->IsFFI()) { 820 FAIL(value, 821 "Invalid initializer for foreign import - object is not the ffi."); 822 } 823 824 // Create a new target info that represents the foreign import. 825 target_info = new (zone_) VariableInfo(import_type); 826 target_info->set_mutability(VariableInfo::kMutableGlobal); 827 } else if (value->IsCallNew()) { 828 AsmType* type = nullptr; 829 RECURSE(type = NewHeapView(value->AsCallNew())); 830 target_info = new (zone_) VariableInfo(type); 831 target_info->set_mutability(VariableInfo::kImmutableGlobal); 832 } else if (auto* proxy = value->AsVariableProxy()) { 833 auto* var_info = Lookup(proxy->var()); 834 835 if (var_info == nullptr) { 836 FAIL(value, "Undeclared identifier in global initializer"); 837 } 838 839 if (var_info->mutability() != VariableInfo::kConstGlobal) { 840 FAIL(value, "Identifier used to initialize a global must be a const"); 841 } 842 843 target_info = new (zone_) VariableInfo(var_info->type()); 844 if (target_variable->mode() == CONST) { 845 target_info->set_mutability(VariableInfo::kConstGlobal); 846 } else { 847 target_info->set_mutability(VariableInfo::kMutableGlobal); 848 } 849 } 850 851 if (target_info == nullptr) { 852 FAIL(assign, "Invalid global variable initializer."); 853 } 854 855 if (!ValidAsmIdentifier(target_variable->name())) { 856 FAIL(target, "Invalid asm.js identifier in global variable."); 857 } 858 859 if (!AddGlobal(target_variable, target_info)) { 860 FAIL(assign, "Redeclared global identifier."); 861 } 862 863 DCHECK(target_info->type() != AsmType::None()); 864 if (!global_variable) { 865 // Global variables have their types set in VariableTypeAnnotations. 866 SetTypeOf(value, target_info->type()); 867 } 868 SetTypeOf(assign, target_info->type()); 869 SetTypeOf(target, target_info->type()); 870 return target_info->type(); 871 } 872 873 // 6.2 ValidateExport 874 AsmType* AsmTyper::ExportType(VariableProxy* fun_export) { 875 auto* fun_info = Lookup(fun_export->var()); 876 if (fun_info == nullptr) { 877 FAIL(fun_export, "Undefined identifier in asm.js module export."); 878 } 879 880 if (fun_info->standard_member() != kNone) { 881 FAIL(fun_export, "Module cannot export standard library functions."); 882 } 883 884 auto* type = fun_info->type(); 885 if (type->AsFFIType() != nullptr) { 886 FAIL(fun_export, "Module cannot export foreign functions."); 887 } 888 889 if (type->AsFunctionTableType() != nullptr) { 890 FAIL(fun_export, "Module cannot export function tables."); 891 } 892 893 if (fun_info->type()->AsFunctionType() == nullptr) { 894 FAIL(fun_export, "Module export is not an asm.js function."); 895 } 896 897 return type; 898 } 899 900 AsmType* AsmTyper::ValidateExport(ReturnStatement* exports) { 901 // asm.js modules can export single functions, or multiple functions in an 902 // object literal. 903 if (auto* fun_export = exports->expression()->AsVariableProxy()) { 904 // Exporting single function. 905 AsmType* export_type; 906 RECURSE(export_type = ExportType(fun_export)); 907 return export_type; 908 } 909 910 if (auto* obj_export = exports->expression()->AsObjectLiteral()) { 911 // Exporting object literal. 912 for (auto* prop : *obj_export->properties()) { 913 if (!prop->key()->IsLiteral()) { 914 FAIL(prop->key(), 915 "Only normal object properties may be used in the export object " 916 "literal."); 917 } 918 919 auto* export_obj = prop->value()->AsVariableProxy(); 920 if (export_obj == nullptr) { 921 FAIL(prop->value(), "Exported value must be an asm.js function name."); 922 } 923 924 RECURSE(ExportType(export_obj)); 925 } 926 927 return AsmType::Int(); 928 } 929 930 FAIL(exports, "Unrecognized expression in asm.js module export expression."); 931 } 932 933 // 6.3 ValidateFunctionTable 934 AsmType* AsmTyper::ValidateFunctionTable(Assignment* assign) { 935 if (assign->is_compound()) { 936 FAIL(assign, 937 "Compound assignment not supported when declaring global variables."); 938 } 939 940 auto* target = assign->target(); 941 if (!target->IsVariableProxy()) { 942 FAIL(target, "Module assignments may only assign to globals."); 943 } 944 auto* target_variable = target->AsVariableProxy()->var(); 945 946 auto* value = assign->value()->AsArrayLiteral(); 947 CHECK(value != nullptr); 948 ZoneList<Expression*>* pointers = value->values(); 949 950 // The function table size must be n = 2 ** m, for m >= 0; 951 // TODO(jpp): should this be capped? 952 if (!base::bits::IsPowerOfTwo32(pointers->length())) { 953 FAIL(assign, "Invalid length for function pointer table."); 954 } 955 956 AsmType* table_element_type = nullptr; 957 for (auto* initializer : *pointers) { 958 auto* var_proxy = initializer->AsVariableProxy(); 959 if (var_proxy == nullptr) { 960 FAIL(initializer, 961 "Function pointer table initializer must be a function name."); 962 } 963 964 auto* var_info = Lookup(var_proxy->var()); 965 if (var_info == nullptr) { 966 FAIL(var_proxy, 967 "Undefined identifier in function pointer table initializer."); 968 } 969 970 if (var_info->standard_member() != kNone) { 971 FAIL(initializer, 972 "Function pointer table must not be a member of the standard " 973 "library."); 974 } 975 976 auto* initializer_type = var_info->type(); 977 if (initializer_type->AsFunctionType() == nullptr) { 978 FAIL(initializer, 979 "Function pointer table initializer must be an asm.js function."); 980 } 981 982 DCHECK(var_info->type()->AsFFIType() == nullptr); 983 DCHECK(var_info->type()->AsFunctionTableType() == nullptr); 984 985 if (table_element_type == nullptr) { 986 table_element_type = initializer_type; 987 } else if (!initializer_type->IsA(table_element_type)) { 988 FAIL(initializer, "Type mismatch in function pointer table initializer."); 989 } 990 } 991 992 auto* target_info = Lookup(target_variable); 993 if (target_info == nullptr) { 994 // Function pointer tables are the last entities to be validates, so this is 995 // unlikely to happen: only unreferenced function tables will not already 996 // have an entry in the global scope. 997 target_info = new (zone_) VariableInfo(AsmType::FunctionTableType( 998 zone_, pointers->length(), table_element_type)); 999 target_info->set_mutability(VariableInfo::kImmutableGlobal); 1000 if (!ValidAsmIdentifier(target_variable->name())) { 1001 FAIL(target, "Invalid asm.js identifier in function table name."); 1002 } 1003 if (!AddGlobal(target_variable, target_info)) { 1004 DCHECK(false); 1005 FAIL(assign, "Redeclared global identifier in function table name."); 1006 } 1007 SetTypeOf(value, target_info->type()); 1008 return target_info->type(); 1009 } 1010 1011 auto* target_info_table = target_info->type()->AsFunctionTableType(); 1012 if (target_info_table == nullptr) { 1013 FAIL(assign, "Identifier redefined as function pointer table."); 1014 } 1015 1016 if (!target_info->missing_definition()) { 1017 FAIL(assign, "Identifier redefined (function table name)."); 1018 } 1019 1020 if (static_cast<int>(target_info_table->length()) != pointers->length()) { 1021 FAIL(assign, "Function table size mismatch."); 1022 } 1023 1024 DCHECK(target_info_table->signature()->AsFunctionType()); 1025 if (!table_element_type->IsA(target_info_table->signature())) { 1026 FAIL(assign, "Function table initializer does not match previous type."); 1027 } 1028 1029 target_info->MarkDefined(); 1030 DCHECK(target_info->type() != AsmType::None()); 1031 SetTypeOf(value, target_info->type()); 1032 1033 return target_info->type(); 1034 } 1035 1036 // 6.4 ValidateFunction 1037 AsmType* AsmTyper::ValidateFunction(FunctionDeclaration* fun_decl) { 1038 FunctionScope _(this); 1039 1040 // Extract parameter types. 1041 auto* fun = fun_decl->fun(); 1042 1043 auto* fun_decl_proxy = fun_decl->proxy(); 1044 if (fun_decl_proxy == nullptr) { 1045 FAIL(fun_decl, "Anonymous functions are not support in asm.js."); 1046 } 1047 1048 Statement* current; 1049 FlattenedStatements iter(zone_, fun->body()); 1050 1051 size_t annotated_parameters = 0; 1052 1053 // 5.3 Function type annotations 1054 // * parameters 1055 ZoneVector<AsmType*> parameter_types(zone_); 1056 for (; (current = iter.Next()) != nullptr; ++annotated_parameters) { 1057 auto* stmt = current->AsExpressionStatement(); 1058 if (stmt == nullptr) { 1059 // Done with parameters. 1060 break; 1061 } 1062 auto* expr = stmt->expression()->AsAssignment(); 1063 if (expr == nullptr || expr->is_compound()) { 1064 // Done with parameters. 1065 break; 1066 } 1067 auto* proxy = expr->target()->AsVariableProxy(); 1068 if (proxy == nullptr) { 1069 // Done with parameters. 1070 break; 1071 } 1072 auto* param = proxy->var(); 1073 if (param->location() != VariableLocation::PARAMETER || 1074 param->index() != static_cast<int>(annotated_parameters)) { 1075 // Done with parameters. 1076 break; 1077 } 1078 1079 AsmType* type; 1080 RECURSE(type = ParameterTypeAnnotations(param, expr->value())); 1081 DCHECK(type->IsParameterType()); 1082 auto* param_info = new (zone_) VariableInfo(type); 1083 param_info->set_mutability(VariableInfo::kLocal); 1084 if (!ValidAsmIdentifier(proxy->name())) { 1085 FAIL(proxy, "Invalid asm.js identifier in parameter name."); 1086 } 1087 1088 if (!AddLocal(param, param_info)) { 1089 FAIL(proxy, "Redeclared parameter."); 1090 } 1091 parameter_types.push_back(type); 1092 SetTypeOf(proxy, type); 1093 SetTypeOf(expr, type); 1094 } 1095 1096 if (static_cast<int>(annotated_parameters) != fun->parameter_count()) { 1097 FAIL(fun_decl, "Incorrect parameter type annotations."); 1098 } 1099 1100 // 5.3 Function type annotations 1101 // * locals 1102 for (; current; current = iter.Next()) { 1103 auto* initializer = ExtractInitializerExpression(current); 1104 if (initializer == nullptr) { 1105 // Done with locals. 1106 break; 1107 } 1108 1109 auto* local = initializer->target()->AsVariableProxy(); 1110 if (local == nullptr) { 1111 // Done with locals. It should never happen. Even if it does, the asm.js 1112 // code should not declare any other locals after this point, so we assume 1113 // this is OK. If any other variable declaration is found we report a 1114 // validation error. 1115 DCHECK(false); 1116 break; 1117 } 1118 1119 AsmType* type; 1120 RECURSE(type = VariableTypeAnnotations(initializer->value())); 1121 auto* local_info = new (zone_) VariableInfo(type); 1122 local_info->set_mutability(VariableInfo::kLocal); 1123 if (!ValidAsmIdentifier(local->name())) { 1124 FAIL(local, "Invalid asm.js identifier in local variable."); 1125 } 1126 1127 if (!AddLocal(local->var(), local_info)) { 1128 FAIL(initializer, "Redeclared local."); 1129 } 1130 1131 SetTypeOf(local, type); 1132 SetTypeOf(initializer, type); 1133 } 1134 1135 // 5.2 Return Type Annotations 1136 // *VIOLATION* we peel blocks to find the last statement in the asm module 1137 // because the parser may introduce synthetic blocks. 1138 ZoneList<Statement*>* statements = fun->body(); 1139 1140 do { 1141 if (statements->length() == 0) { 1142 return_type_ = AsmType::Void(); 1143 } else { 1144 auto* last_statement = statements->last(); 1145 auto* as_block = last_statement->AsBlock(); 1146 if (as_block != nullptr) { 1147 statements = as_block->statements(); 1148 } else { 1149 // We don't check whether AsReturnStatement() below returns non-null -- 1150 // we leave that to the ReturnTypeAnnotations method. 1151 RECURSE(return_type_ = 1152 ReturnTypeAnnotations(last_statement->AsReturnStatement())); 1153 } 1154 } 1155 } while (return_type_ == AsmType::None()); 1156 1157 DCHECK(return_type_->IsReturnType()); 1158 1159 for (Declaration* decl : *fun->scope()->declarations()) { 1160 auto* var_decl = decl->AsVariableDeclaration(); 1161 if (var_decl == nullptr) { 1162 FAIL(decl, "Functions may only define inner variables."); 1163 } 1164 1165 auto* var_proxy = var_decl->proxy(); 1166 if (var_proxy == nullptr) { 1167 FAIL(decl, "Invalid local declaration declaration."); 1168 } 1169 1170 auto* var_info = Lookup(var_proxy->var()); 1171 if (var_info == nullptr || var_info->IsGlobal()) { 1172 FAIL(decl, "Local variable missing initializer in asm.js module."); 1173 } 1174 } 1175 1176 for (; current; current = iter.Next()) { 1177 AsmType* current_type; 1178 RECURSE(current_type = ValidateStatement(current)); 1179 } 1180 1181 auto* fun_type = AsmType::Function(zone_, return_type_); 1182 auto* fun_type_as_function = fun_type->AsFunctionType(); 1183 for (auto* param_type : parameter_types) { 1184 fun_type_as_function->AddArgument(param_type); 1185 } 1186 1187 auto* fun_var = fun_decl_proxy->var(); 1188 auto* fun_info = new (zone_) VariableInfo(fun_type); 1189 fun_info->set_mutability(VariableInfo::kImmutableGlobal); 1190 auto* old_fun_info = Lookup(fun_var); 1191 if (old_fun_info == nullptr) { 1192 if (!ValidAsmIdentifier(fun_var->name())) { 1193 FAIL(fun_decl_proxy, "Invalid asm.js identifier in function name."); 1194 } 1195 if (!AddGlobal(fun_var, fun_info)) { 1196 DCHECK(false); 1197 FAIL(fun_decl, "Redeclared global identifier."); 1198 } 1199 1200 SetTypeOf(fun, fun_type); 1201 return fun_type; 1202 } 1203 1204 // Not necessarily an error -- fun_decl might have been used before being 1205 // defined. If that's the case, then the type in the global environment must 1206 // be the same as the type inferred by the parameter/return type annotations. 1207 auto* old_fun_type = old_fun_info->type(); 1208 if (old_fun_type->AsFunctionType() == nullptr) { 1209 FAIL(fun_decl, "Identifier redefined as function."); 1210 } 1211 1212 if (!old_fun_info->missing_definition()) { 1213 FAIL(fun_decl, "Identifier redefined (function name)."); 1214 } 1215 1216 if (!fun_type->IsA(old_fun_type)) { 1217 FAIL(fun_decl, "Signature mismatch when defining function."); 1218 } 1219 1220 old_fun_info->MarkDefined(); 1221 SetTypeOf(fun, fun_type); 1222 1223 return fun_type; 1224 } 1225 1226 // 6.5 ValidateStatement 1227 AsmType* AsmTyper::ValidateStatement(Statement* statement) { 1228 switch (statement->node_type()) { 1229 default: 1230 FAIL(statement, "Statement type invalid for asm.js."); 1231 case AstNode::kBlock: 1232 return ValidateBlockStatement(statement->AsBlock()); 1233 case AstNode::kExpressionStatement: 1234 return ValidateExpressionStatement(statement->AsExpressionStatement()); 1235 case AstNode::kEmptyStatement: 1236 return ValidateEmptyStatement(statement->AsEmptyStatement()); 1237 case AstNode::kIfStatement: 1238 return ValidateIfStatement(statement->AsIfStatement()); 1239 case AstNode::kReturnStatement: 1240 return ValidateReturnStatement(statement->AsReturnStatement()); 1241 case AstNode::kWhileStatement: 1242 return ValidateWhileStatement(statement->AsWhileStatement()); 1243 case AstNode::kDoWhileStatement: 1244 return ValidateDoWhileStatement(statement->AsDoWhileStatement()); 1245 case AstNode::kForStatement: 1246 return ValidateForStatement(statement->AsForStatement()); 1247 case AstNode::kBreakStatement: 1248 return ValidateBreakStatement(statement->AsBreakStatement()); 1249 case AstNode::kContinueStatement: 1250 return ValidateContinueStatement(statement->AsContinueStatement()); 1251 case AstNode::kSwitchStatement: 1252 return ValidateSwitchStatement(statement->AsSwitchStatement()); 1253 } 1254 1255 return AsmType::Void(); 1256 } 1257 1258 // 6.5.1 BlockStatement 1259 AsmType* AsmTyper::ValidateBlockStatement(Block* block) { 1260 FlattenedStatements iter(zone_, block->statements()); 1261 1262 while (auto* current = iter.Next()) { 1263 RECURSE(ValidateStatement(current)); 1264 } 1265 1266 return AsmType::Void(); 1267 } 1268 1269 // 6.5.2 ExpressionStatement 1270 AsmType* AsmTyper::ValidateExpressionStatement(ExpressionStatement* expr) { 1271 auto* expression = expr->expression(); 1272 if (auto* call = expression->AsCall()) { 1273 RECURSE(ValidateCall(AsmType::Void(), call)); 1274 } else { 1275 RECURSE(ValidateExpression(expression)); 1276 } 1277 1278 return AsmType::Void(); 1279 } 1280 1281 // 6.5.3 EmptyStatement 1282 AsmType* AsmTyper::ValidateEmptyStatement(EmptyStatement* empty) { 1283 return AsmType::Void(); 1284 } 1285 1286 // 6.5.4 IfStatement 1287 AsmType* AsmTyper::ValidateIfStatement(IfStatement* if_stmt) { 1288 AsmType* cond_type; 1289 RECURSE(cond_type = ValidateExpression(if_stmt->condition())); 1290 if (!cond_type->IsA(AsmType::Int())) { 1291 FAIL(if_stmt->condition(), "If condition must be type int."); 1292 } 1293 RECURSE(ValidateStatement(if_stmt->then_statement())); 1294 RECURSE(ValidateStatement(if_stmt->else_statement())); 1295 return AsmType::Void(); 1296 } 1297 1298 // 6.5.5 ReturnStatement 1299 AsmType* AsmTyper::ValidateReturnStatement(ReturnStatement* ret_stmt) { 1300 AsmType* ret_expr_type = AsmType::Void(); 1301 if (auto* ret_expr = ret_stmt->expression()) { 1302 RECURSE(ret_expr_type = ValidateExpression(ret_expr)); 1303 if (ret_expr_type == AsmType::Void()) { 1304 // *VIOLATION* The parser modifies the source code so that expressionless 1305 // returns will return undefined, so we need to allow that. 1306 if (!ret_expr->IsUndefinedLiteral()) { 1307 FAIL(ret_stmt, "Return statement expression can't be void."); 1308 } 1309 } 1310 } 1311 1312 if (!ret_expr_type->IsA(return_type_)) { 1313 FAIL(ret_stmt, "Type mismatch in return statement."); 1314 } 1315 1316 return ret_expr_type; 1317 } 1318 1319 // 6.5.6 IterationStatement 1320 // 6.5.6.a WhileStatement 1321 AsmType* AsmTyper::ValidateWhileStatement(WhileStatement* while_stmt) { 1322 AsmType* cond_type; 1323 RECURSE(cond_type = ValidateExpression(while_stmt->cond())); 1324 if (!cond_type->IsA(AsmType::Int())) { 1325 FAIL(while_stmt->cond(), "While condition must be type int."); 1326 } 1327 1328 if (auto* body = while_stmt->body()) { 1329 RECURSE(ValidateStatement(body)); 1330 } 1331 return AsmType::Void(); 1332 } 1333 1334 // 6.5.6.b DoWhileStatement 1335 AsmType* AsmTyper::ValidateDoWhileStatement(DoWhileStatement* do_while) { 1336 AsmType* cond_type; 1337 RECURSE(cond_type = ValidateExpression(do_while->cond())); 1338 if (!cond_type->IsA(AsmType::Int())) { 1339 FAIL(do_while->cond(), "Do {} While condition must be type int."); 1340 } 1341 1342 if (auto* body = do_while->body()) { 1343 RECURSE(ValidateStatement(body)); 1344 } 1345 return AsmType::Void(); 1346 } 1347 1348 // 6.5.6.c ForStatement 1349 AsmType* AsmTyper::ValidateForStatement(ForStatement* for_stmt) { 1350 if (auto* init = for_stmt->init()) { 1351 RECURSE(ValidateStatement(init)); 1352 } 1353 1354 if (auto* cond = for_stmt->cond()) { 1355 AsmType* cond_type; 1356 RECURSE(cond_type = ValidateExpression(cond)); 1357 if (!cond_type->IsA(AsmType::Int())) { 1358 FAIL(cond, "For condition must be type int."); 1359 } 1360 } 1361 1362 if (auto* next = for_stmt->next()) { 1363 RECURSE(ValidateStatement(next)); 1364 } 1365 1366 if (auto* body = for_stmt->body()) { 1367 RECURSE(ValidateStatement(body)); 1368 } 1369 1370 return AsmType::Void(); 1371 } 1372 1373 // 6.5.7 BreakStatement 1374 AsmType* AsmTyper::ValidateBreakStatement(BreakStatement* brk_stmt) { 1375 return AsmType::Void(); 1376 } 1377 1378 // 6.5.8 ContinueStatement 1379 AsmType* AsmTyper::ValidateContinueStatement(ContinueStatement* cont_stmt) { 1380 return AsmType::Void(); 1381 } 1382 1383 // 6.5.9 LabelledStatement 1384 // No need to handle these here -- see the AsmTyper's definition. 1385 1386 // 6.5.10 SwitchStatement 1387 AsmType* AsmTyper::ValidateSwitchStatement(SwitchStatement* stmt) { 1388 AsmType* cond_type; 1389 RECURSE(cond_type = ValidateExpression(stmt->tag())); 1390 if (!cond_type->IsA(AsmType::Signed())) { 1391 FAIL(stmt, "Switch tag must be signed."); 1392 } 1393 1394 int default_pos = kNoSourcePosition; 1395 int last_case_pos = kNoSourcePosition; 1396 ZoneSet<int32_t> cases_seen(zone_); 1397 for (auto* a_case : *stmt->cases()) { 1398 if (a_case->is_default()) { 1399 CHECK(default_pos == kNoSourcePosition); 1400 RECURSE(ValidateDefault(a_case)); 1401 default_pos = a_case->position(); 1402 continue; 1403 } 1404 1405 if (last_case_pos == kNoSourcePosition) { 1406 last_case_pos = a_case->position(); 1407 } else { 1408 last_case_pos = std::max(last_case_pos, a_case->position()); 1409 } 1410 1411 int32_t case_lbl; 1412 RECURSE(ValidateCase(a_case, &case_lbl)); 1413 auto case_lbl_pos = cases_seen.find(case_lbl); 1414 if (case_lbl_pos != cases_seen.end() && *case_lbl_pos == case_lbl) { 1415 FAIL(a_case, "Duplicated case label."); 1416 } 1417 cases_seen.insert(case_lbl); 1418 } 1419 1420 if (!cases_seen.empty()) { 1421 const int64_t max_lbl = *cases_seen.rbegin(); 1422 const int64_t min_lbl = *cases_seen.begin(); 1423 if (max_lbl - min_lbl > std::numeric_limits<int32_t>::max()) { 1424 FAIL(stmt, "Out-of-bounds case label range."); 1425 } 1426 } 1427 1428 if (last_case_pos != kNoSourcePosition && default_pos != kNoSourcePosition && 1429 default_pos < last_case_pos) { 1430 FAIL(stmt, "Switch default must appear last."); 1431 } 1432 1433 return AsmType::Void(); 1434 } 1435 1436 // 6.6 ValidateCase 1437 namespace { 1438 bool ExtractInt32CaseLabel(CaseClause* clause, int32_t* lbl) { 1439 auto* lbl_expr = clause->label()->AsLiteral(); 1440 1441 if (lbl_expr == nullptr) { 1442 return false; 1443 } 1444 1445 if (lbl_expr->raw_value()->ContainsDot()) { 1446 return false; 1447 } 1448 1449 return lbl_expr->value()->ToInt32(lbl); 1450 } 1451 } // namespace 1452 1453 AsmType* AsmTyper::ValidateCase(CaseClause* label, int32_t* case_lbl) { 1454 if (!ExtractInt32CaseLabel(label, case_lbl)) { 1455 FAIL(label, "Case label must be a 32-bit signed integer."); 1456 } 1457 1458 FlattenedStatements iter(zone_, label->statements()); 1459 while (auto* current = iter.Next()) { 1460 RECURSE(ValidateStatement(current)); 1461 } 1462 return AsmType::Void(); 1463 } 1464 1465 // 6.7 ValidateDefault 1466 AsmType* AsmTyper::ValidateDefault(CaseClause* label) { 1467 FlattenedStatements iter(zone_, label->statements()); 1468 while (auto* current = iter.Next()) { 1469 RECURSE(ValidateStatement(current)); 1470 } 1471 return AsmType::Void(); 1472 } 1473 1474 // 6.8 ValidateExpression 1475 AsmType* AsmTyper::ValidateExpression(Expression* expr) { 1476 AsmType* expr_ty = AsmType::None(); 1477 1478 switch (expr->node_type()) { 1479 default: 1480 FAIL(expr, "Invalid asm.js expression."); 1481 case AstNode::kLiteral: 1482 RECURSE(expr_ty = ValidateNumericLiteral(expr->AsLiteral())); 1483 break; 1484 case AstNode::kVariableProxy: 1485 RECURSE(expr_ty = ValidateIdentifier(expr->AsVariableProxy())); 1486 break; 1487 case AstNode::kCall: 1488 RECURSE(expr_ty = ValidateCallExpression(expr->AsCall())); 1489 break; 1490 case AstNode::kProperty: 1491 RECURSE(expr_ty = ValidateMemberExpression(expr->AsProperty())); 1492 break; 1493 case AstNode::kAssignment: 1494 RECURSE(expr_ty = ValidateAssignmentExpression(expr->AsAssignment())); 1495 break; 1496 case AstNode::kUnaryOperation: 1497 RECURSE(expr_ty = ValidateUnaryExpression(expr->AsUnaryOperation())); 1498 break; 1499 case AstNode::kConditional: 1500 RECURSE(expr_ty = ValidateConditionalExpression(expr->AsConditional())); 1501 break; 1502 case AstNode::kCompareOperation: 1503 RECURSE(expr_ty = ValidateCompareOperation(expr->AsCompareOperation())); 1504 break; 1505 case AstNode::kBinaryOperation: 1506 RECURSE(expr_ty = ValidateBinaryOperation(expr->AsBinaryOperation())); 1507 break; 1508 } 1509 1510 SetTypeOf(expr, expr_ty); 1511 return expr_ty; 1512 } 1513 1514 AsmType* AsmTyper::ValidateCompareOperation(CompareOperation* cmp) { 1515 switch (cmp->op()) { 1516 default: 1517 FAIL(cmp, "Invalid asm.js comparison operator."); 1518 case Token::LT: 1519 case Token::LTE: 1520 case Token::GT: 1521 case Token::GTE: 1522 return ValidateRelationalExpression(cmp); 1523 case Token::EQ: 1524 case Token::NE: 1525 return ValidateEqualityExpression(cmp); 1526 } 1527 1528 UNREACHABLE(); 1529 } 1530 1531 namespace { 1532 bool IsInvert(BinaryOperation* binop) { 1533 if (binop->op() != Token::BIT_XOR) { 1534 return false; 1535 } 1536 1537 auto* right_as_literal = binop->right()->AsLiteral(); 1538 if (right_as_literal == nullptr) { 1539 return false; 1540 } 1541 1542 return !right_as_literal->raw_value()->ContainsDot() && 1543 right_as_literal->raw_value()->AsNumber() == -1.0; 1544 } 1545 1546 bool IsUnaryMinus(BinaryOperation* binop) { 1547 // *VIOLATION* The parser replaces uses of -x with x*-1. 1548 if (binop->op() != Token::MUL) { 1549 return false; 1550 } 1551 1552 auto* right_as_literal = binop->right()->AsLiteral(); 1553 if (right_as_literal == nullptr) { 1554 return false; 1555 } 1556 1557 return !right_as_literal->raw_value()->ContainsDot() && 1558 right_as_literal->raw_value()->AsNumber() == -1.0; 1559 } 1560 } // namespace 1561 1562 AsmType* AsmTyper::ValidateBinaryOperation(BinaryOperation* expr) { 1563 #define UNOP_OVERLOAD(Src, Dest) \ 1564 do { \ 1565 if (left_type->IsA(AsmType::Src())) { \ 1566 return AsmType::Dest(); \ 1567 } \ 1568 } while (0) 1569 1570 switch (expr->op()) { 1571 default: 1572 FAIL(expr, "Invalid asm.js binary expression."); 1573 case Token::COMMA: 1574 return ValidateCommaExpression(expr); 1575 case Token::MUL: 1576 if (IsDoubleAnnotation(expr)) { 1577 // *VIOLATION* We can't be 100% sure this really IS a unary + in the asm 1578 // source so we have to be lenient, and treat this as a unary +. 1579 if (auto* Call = expr->left()->AsCall()) { 1580 return ValidateCall(AsmType::Double(), Call); 1581 } 1582 AsmType* left_type; 1583 RECURSE(left_type = ValidateExpression(expr->left())); 1584 SetTypeOf(expr->right(), AsmType::Double()); 1585 UNOP_OVERLOAD(Signed, Double); 1586 UNOP_OVERLOAD(Unsigned, Double); 1587 UNOP_OVERLOAD(DoubleQ, Double); 1588 UNOP_OVERLOAD(FloatQ, Double); 1589 FAIL(expr, "Invalid type for conversion to double."); 1590 } 1591 1592 if (IsUnaryMinus(expr)) { 1593 // *VIOLATION* the parser converts -x to x * -1. 1594 AsmType* left_type; 1595 RECURSE(left_type = ValidateExpression(expr->left())); 1596 SetTypeOf(expr->right(), left_type); 1597 UNOP_OVERLOAD(Int, Intish); 1598 UNOP_OVERLOAD(DoubleQ, Double); 1599 UNOP_OVERLOAD(FloatQ, Floatish); 1600 FAIL(expr, "Invalid type for unary -."); 1601 } 1602 // FALTHROUGH 1603 case Token::DIV: 1604 case Token::MOD: 1605 return ValidateMultiplicativeExpression(expr); 1606 case Token::ADD: 1607 case Token::SUB: { 1608 static const uint32_t kInitialIntishCount = 0; 1609 return ValidateAdditiveExpression(expr, kInitialIntishCount); 1610 } 1611 case Token::SAR: 1612 case Token::SHL: 1613 case Token::SHR: 1614 return ValidateShiftExpression(expr); 1615 case Token::BIT_AND: 1616 return ValidateBitwiseANDExpression(expr); 1617 case Token::BIT_XOR: 1618 if (IsInvert(expr)) { 1619 auto* left = expr->left(); 1620 auto* left_as_binop = left->AsBinaryOperation(); 1621 1622 if (left_as_binop != nullptr && IsInvert(left_as_binop)) { 1623 // This is the special ~~ operator. 1624 AsmType* left_type; 1625 RECURSE(left_type = ValidateExpression(left_as_binop->left())); 1626 SetTypeOf(left_as_binop->right(), AsmType::FixNum()); 1627 SetTypeOf(left_as_binop, AsmType::Signed()); 1628 SetTypeOf(expr->right(), AsmType::FixNum()); 1629 UNOP_OVERLOAD(Double, Signed); 1630 UNOP_OVERLOAD(FloatQ, Signed); 1631 FAIL(left_as_binop, "Invalid type for conversion to signed."); 1632 } 1633 1634 AsmType* left_type; 1635 RECURSE(left_type = ValidateExpression(left)); 1636 UNOP_OVERLOAD(Intish, Signed); 1637 FAIL(left, "Invalid type for ~."); 1638 } 1639 1640 return ValidateBitwiseXORExpression(expr); 1641 case Token::BIT_OR: 1642 return ValidateBitwiseORExpression(expr); 1643 } 1644 #undef UNOP_OVERLOAD 1645 UNREACHABLE(); 1646 } 1647 1648 // 6.8.1 Expression 1649 AsmType* AsmTyper::ValidateCommaExpression(BinaryOperation* comma) { 1650 // The AST looks like: 1651 // (expr COMMA (expr COMMA (expr COMMA (... )))) 1652 1653 auto* left = comma->left(); 1654 if (auto* left_as_call = left->AsCall()) { 1655 RECURSE(ValidateCall(AsmType::Void(), left_as_call)); 1656 } else { 1657 RECURSE(ValidateExpression(left)); 1658 } 1659 1660 auto* right = comma->right(); 1661 AsmType* right_type = nullptr; 1662 if (auto* right_as_call = right->AsCall()) { 1663 RECURSE(right_type = ValidateFloatCoercion(right_as_call)); 1664 if (right_type != AsmType::Float()) { 1665 // right_type == nullptr <-> right_as_call is not a call to fround. 1666 DCHECK(right_type == nullptr); 1667 RECURSE(right_type = ValidateCall(AsmType::Void(), right_as_call)); 1668 // Unnanotated function call to something that's not fround must be a call 1669 // to a void function. 1670 DCHECK_EQ(right_type, AsmType::Void()); 1671 } 1672 } else { 1673 RECURSE(right_type = ValidateExpression(right)); 1674 } 1675 1676 return right_type; 1677 } 1678 1679 // 6.8.2 NumericLiteral 1680 AsmType* AsmTyper::ValidateNumericLiteral(Literal* literal) { 1681 // *VIOLATION* asm.js does not allow the use of undefined, but our parser 1682 // inserts them, so we have to handle them. 1683 if (literal->IsUndefinedLiteral()) { 1684 return AsmType::Void(); 1685 } 1686 1687 if (literal->raw_value()->ContainsDot()) { 1688 return AsmType::Double(); 1689 } 1690 1691 // The parser collapses expressions like !0 and !123 to true/false. 1692 // We therefore need to permit these as alternate versions of 0 / 1. 1693 if (literal->raw_value()->IsTrue() || literal->raw_value()->IsFalse()) { 1694 return AsmType::Int(); 1695 } 1696 1697 uint32_t value; 1698 if (!literal->value()->ToUint32(&value)) { 1699 int32_t value; 1700 if (!literal->value()->ToInt32(&value)) { 1701 FAIL(literal, "Integer literal is out of range."); 1702 } 1703 // *VIOLATION* Not really a violation, but rather a difference in 1704 // validation. The spec handles -NumericLiteral in ValidateUnaryExpression, 1705 // but V8's AST represents the negative literals as Literals. 1706 return AsmType::Signed(); 1707 } 1708 1709 if (value <= LargestFixNum) { 1710 return AsmType::FixNum(); 1711 } 1712 1713 return AsmType::Unsigned(); 1714 } 1715 1716 // 6.8.3 Identifier 1717 AsmType* AsmTyper::ValidateIdentifier(VariableProxy* proxy) { 1718 auto* proxy_info = Lookup(proxy->var()); 1719 if (proxy_info == nullptr) { 1720 FAIL(proxy, "Undeclared identifier."); 1721 } 1722 auto* type = proxy_info->type(); 1723 if (type->IsA(AsmType::None()) || type->AsCallableType() != nullptr) { 1724 FAIL(proxy, "Identifier may not be accessed by ordinary expressions."); 1725 } 1726 return type; 1727 } 1728 1729 // 6.8.4 CallExpression 1730 AsmType* AsmTyper::ValidateCallExpression(Call* call) { 1731 AsmType* return_type; 1732 RECURSE(return_type = ValidateFloatCoercion(call)); 1733 if (return_type == nullptr) { 1734 FAIL(call, "Unanotated call to a function must be a call to fround."); 1735 } 1736 return return_type; 1737 } 1738 1739 // 6.8.5 MemberExpression 1740 AsmType* AsmTyper::ValidateMemberExpression(Property* prop) { 1741 AsmType* return_type; 1742 RECURSE(return_type = ValidateHeapAccess(prop, LoadFromHeap)); 1743 return return_type; 1744 } 1745 1746 // 6.8.6 AssignmentExpression 1747 AsmType* AsmTyper::ValidateAssignmentExpression(Assignment* assignment) { 1748 AsmType* value_type; 1749 RECURSE(value_type = ValidateExpression(assignment->value())); 1750 1751 if (assignment->op() == Token::INIT) { 1752 FAIL(assignment, 1753 "Local variable declaration must be at the top of the function."); 1754 } 1755 1756 if (auto* target_as_proxy = assignment->target()->AsVariableProxy()) { 1757 auto* var = target_as_proxy->var(); 1758 auto* target_info = Lookup(var); 1759 1760 if (target_info == nullptr) { 1761 if (var->mode() != TEMPORARY) { 1762 FAIL(target_as_proxy, "Undeclared identifier."); 1763 } 1764 // Temporary variables are special: we add them to the local symbol table 1765 // as we see them, with the exact type of the variable's initializer. This 1766 // means that temporary variables might have nonsensical types (i.e., 1767 // intish, float?, fixnum, and not just the "canonical" types.) 1768 auto* var_info = new (zone_) VariableInfo(value_type); 1769 var_info->set_mutability(VariableInfo::kLocal); 1770 if (!ValidAsmIdentifier(target_as_proxy->name())) { 1771 FAIL(target_as_proxy, 1772 "Invalid asm.js identifier in temporary variable."); 1773 } 1774 1775 if (!AddLocal(var, var_info)) { 1776 FAIL(assignment, "Failed to add temporary variable to symbol table."); 1777 } 1778 return value_type; 1779 } 1780 1781 if (!target_info->IsMutable()) { 1782 FAIL(assignment, "Can't assign to immutable symbol."); 1783 } 1784 1785 DCHECK_NE(AsmType::None(), target_info->type()); 1786 if (!value_type->IsA(target_info->type())) { 1787 FAIL(assignment, "Type mismatch in assignment."); 1788 } 1789 1790 return value_type; 1791 } 1792 1793 if (auto* target_as_property = assignment->target()->AsProperty()) { 1794 AsmType* allowed_store_types; 1795 RECURSE(allowed_store_types = 1796 ValidateHeapAccess(target_as_property, StoreToHeap)); 1797 1798 if (!value_type->IsA(allowed_store_types)) { 1799 FAIL(assignment, "Type mismatch in heap assignment."); 1800 } 1801 1802 return value_type; 1803 } 1804 1805 FAIL(assignment, "Invalid asm.js assignment."); 1806 } 1807 1808 // 6.8.7 UnaryExpression 1809 AsmType* AsmTyper::ValidateUnaryExpression(UnaryOperation* unop) { 1810 // *VIOLATION* -NumericLiteral is validated in ValidateLiteral. 1811 // *VIOLATION* +UnaryExpression is validated in ValidateBinaryOperation. 1812 // *VIOLATION* ~UnaryOperation is validated in ValidateBinaryOperation. 1813 // *VIOLATION* ~~UnaryOperation is validated in ValidateBinaryOperation. 1814 DCHECK(unop->op() != Token::BIT_NOT); 1815 DCHECK(unop->op() != Token::ADD); 1816 AsmType* exp_type; 1817 RECURSE(exp_type = ValidateExpression(unop->expression())); 1818 #define UNOP_OVERLOAD(Src, Dest) \ 1819 do { \ 1820 if (exp_type->IsA(AsmType::Src())) { \ 1821 return AsmType::Dest(); \ 1822 } \ 1823 } while (0) 1824 1825 // 8.1 Unary Operators 1826 switch (unop->op()) { 1827 default: 1828 FAIL(unop, "Invalid unary operator."); 1829 case Token::ADD: 1830 // We can't test this because of the +x -> x * 1.0 transformation. 1831 DCHECK(false); 1832 UNOP_OVERLOAD(Signed, Double); 1833 UNOP_OVERLOAD(Unsigned, Double); 1834 UNOP_OVERLOAD(DoubleQ, Double); 1835 UNOP_OVERLOAD(FloatQ, Double); 1836 FAIL(unop, "Invalid type for unary +."); 1837 case Token::SUB: 1838 // We can't test this because of the -x -> x * -1.0 transformation. 1839 DCHECK(false); 1840 UNOP_OVERLOAD(Int, Intish); 1841 UNOP_OVERLOAD(DoubleQ, Double); 1842 UNOP_OVERLOAD(FloatQ, Floatish); 1843 FAIL(unop, "Invalid type for unary -."); 1844 case Token::BIT_NOT: 1845 // We can't test this because of the ~x -> x ^ -1 transformation. 1846 DCHECK(false); 1847 UNOP_OVERLOAD(Intish, Signed); 1848 FAIL(unop, "Invalid type for ~."); 1849 case Token::NOT: 1850 UNOP_OVERLOAD(Int, Int); 1851 FAIL(unop, "Invalid type for !."); 1852 } 1853 1854 #undef UNOP_OVERLOAD 1855 1856 UNREACHABLE(); 1857 } 1858 1859 // 6.8.8 MultiplicativeExpression 1860 namespace { 1861 bool IsIntishLiteralFactor(Expression* expr, int32_t* factor) { 1862 auto* literal = expr->AsLiteral(); 1863 if (literal == nullptr) { 1864 return false; 1865 } 1866 1867 if (literal->raw_value()->ContainsDot()) { 1868 return false; 1869 } 1870 1871 if (!literal->value()->ToInt32(factor)) { 1872 return false; 1873 } 1874 static const int32_t kIntishBound = 1 << 20; 1875 return -kIntishBound < *factor && *factor < kIntishBound; 1876 } 1877 } // namespace 1878 1879 AsmType* AsmTyper::ValidateMultiplicativeExpression(BinaryOperation* binop) { 1880 DCHECK(!IsDoubleAnnotation(binop)); 1881 1882 auto* left = binop->left(); 1883 auto* right = binop->right(); 1884 1885 bool intish_mul_failed = false; 1886 if (binop->op() == Token::MUL) { 1887 int32_t factor; 1888 if (IsIntishLiteralFactor(left, &factor)) { 1889 AsmType* right_type; 1890 RECURSE(right_type = ValidateExpression(right)); 1891 if (right_type->IsA(AsmType::Int())) { 1892 return AsmType::Intish(); 1893 } 1894 // Can't fail here, because the rhs might contain a valid intish factor. 1895 // 1896 // The solution is to flag that there was an error, and later on -- when 1897 // both lhs and rhs are evaluated -- complain. 1898 intish_mul_failed = true; 1899 } 1900 1901 if (IsIntishLiteralFactor(right, &factor)) { 1902 AsmType* left_type; 1903 RECURSE(left_type = ValidateExpression(left)); 1904 if (left_type->IsA(AsmType::Int())) { 1905 // *VIOLATION* This will also (and correctly) handle -X, when X is an 1906 // integer. Therefore, we don't need to handle this case within the if 1907 // block below. 1908 return AsmType::Intish(); 1909 } 1910 intish_mul_failed = true; 1911 1912 if (factor == -1) { 1913 // *VIOLATION* The frontend transforms -x into x * -1 (not -1.0, because 1914 // consistency is overrated.) 1915 if (left_type->IsA(AsmType::DoubleQ())) { 1916 return AsmType::Double(); 1917 } else if (left_type->IsA(AsmType::FloatQ())) { 1918 return AsmType::Floatish(); 1919 } 1920 } 1921 } 1922 } 1923 1924 if (intish_mul_failed) { 1925 FAIL(binop, "Invalid types for intish * (or unary -)."); 1926 } 1927 1928 AsmType* left_type; 1929 AsmType* right_type; 1930 RECURSE(left_type = ValidateExpression(left)); 1931 RECURSE(right_type = ValidateExpression(right)); 1932 1933 #define BINOP_OVERLOAD(Src0, Src1, Dest) \ 1934 do { \ 1935 if (left_type->IsA(AsmType::Src0()) && right_type->IsA(AsmType::Src1())) { \ 1936 return AsmType::Dest(); \ 1937 } \ 1938 } while (0) 1939 switch (binop->op()) { 1940 default: 1941 FAIL(binop, "Invalid multiplicative expression."); 1942 case Token::MUL: 1943 BINOP_OVERLOAD(DoubleQ, DoubleQ, Double); 1944 BINOP_OVERLOAD(FloatQ, FloatQ, Floatish); 1945 FAIL(binop, "Invalid operands for *."); 1946 case Token::DIV: 1947 BINOP_OVERLOAD(Signed, Signed, Intish); 1948 BINOP_OVERLOAD(Unsigned, Unsigned, Intish); 1949 BINOP_OVERLOAD(DoubleQ, DoubleQ, Double); 1950 BINOP_OVERLOAD(FloatQ, FloatQ, Floatish); 1951 FAIL(binop, "Invalid operands for /."); 1952 case Token::MOD: 1953 BINOP_OVERLOAD(Signed, Signed, Intish); 1954 BINOP_OVERLOAD(Unsigned, Unsigned, Intish); 1955 BINOP_OVERLOAD(DoubleQ, DoubleQ, Double); 1956 FAIL(binop, "Invalid operands for %."); 1957 } 1958 #undef BINOP_OVERLOAD 1959 1960 UNREACHABLE(); 1961 } 1962 1963 // 6.8.9 AdditiveExpression 1964 AsmType* AsmTyper::ValidateAdditiveExpression(BinaryOperation* binop, 1965 uint32_t intish_count) { 1966 static const uint32_t kMaxIntish = 1 << 20; 1967 1968 auto* left = binop->left(); 1969 auto* left_as_binop = left->AsBinaryOperation(); 1970 AsmType* left_type; 1971 1972 // TODO(jpp): maybe use an iterative approach instead of the recursion to 1973 // ValidateAdditiveExpression. 1974 if (left_as_binop != nullptr && (left_as_binop->op() == Token::ADD || 1975 left_as_binop->op() == Token::SUB)) { 1976 RECURSE(left_type = 1977 ValidateAdditiveExpression(left_as_binop, intish_count + 1)); 1978 SetTypeOf(left_as_binop, left_type); 1979 } else { 1980 RECURSE(left_type = ValidateExpression(left)); 1981 } 1982 1983 auto* right = binop->right(); 1984 auto* right_as_binop = right->AsBinaryOperation(); 1985 AsmType* right_type; 1986 1987 if (right_as_binop != nullptr && (right_as_binop->op() == Token::ADD || 1988 right_as_binop->op() == Token::SUB)) { 1989 RECURSE(right_type = 1990 ValidateAdditiveExpression(right_as_binop, intish_count + 1)); 1991 SetTypeOf(right_as_binop, right_type); 1992 } else { 1993 RECURSE(right_type = ValidateExpression(right)); 1994 } 1995 1996 if (left_type->IsA(AsmType::FloatQ()) && right_type->IsA(AsmType::FloatQ())) { 1997 return AsmType::Floatish(); 1998 } 1999 2000 if (left_type->IsA(AsmType::Int()) && right_type->IsA(AsmType::Int())) { 2001 if (intish_count == 0) { 2002 return AsmType::Intish(); 2003 } 2004 if (intish_count < kMaxIntish) { 2005 return AsmType::Int(); 2006 } 2007 FAIL(binop, "Too many uncoerced integer additive expressions."); 2008 } 2009 2010 if (left_type->IsA(AsmType::Double()) && right_type->IsA(AsmType::Double())) { 2011 return AsmType::Double(); 2012 } 2013 2014 if (binop->op() == Token::SUB) { 2015 if (left_type->IsA(AsmType::DoubleQ()) && 2016 right_type->IsA(AsmType::DoubleQ())) { 2017 return AsmType::Double(); 2018 } 2019 } 2020 2021 FAIL(binop, "Invalid operands for additive expression."); 2022 } 2023 2024 // 6.8.10 ShiftExpression 2025 AsmType* AsmTyper::ValidateShiftExpression(BinaryOperation* binop) { 2026 auto* left = binop->left(); 2027 auto* right = binop->right(); 2028 2029 AsmType* left_type; 2030 AsmType* right_type; 2031 RECURSE(left_type = ValidateExpression(left)); 2032 RECURSE(right_type = ValidateExpression(right)); 2033 2034 #define BINOP_OVERLOAD(Src0, Src1, Dest) \ 2035 do { \ 2036 if (left_type->IsA(AsmType::Src0()) && right_type->IsA(AsmType::Src1())) { \ 2037 return AsmType::Dest(); \ 2038 } \ 2039 } while (0) 2040 switch (binop->op()) { 2041 default: 2042 FAIL(binop, "Invalid shift expression."); 2043 case Token::SHL: 2044 BINOP_OVERLOAD(Intish, Intish, Signed); 2045 FAIL(binop, "Invalid operands for <<."); 2046 case Token::SAR: 2047 BINOP_OVERLOAD(Intish, Intish, Signed); 2048 FAIL(binop, "Invalid operands for >>."); 2049 case Token::SHR: 2050 BINOP_OVERLOAD(Intish, Intish, Unsigned); 2051 FAIL(binop, "Invalid operands for >>>."); 2052 } 2053 #undef BINOP_OVERLOAD 2054 2055 UNREACHABLE(); 2056 } 2057 2058 // 6.8.11 RelationalExpression 2059 AsmType* AsmTyper::ValidateRelationalExpression(CompareOperation* cmpop) { 2060 auto* left = cmpop->left(); 2061 auto* right = cmpop->right(); 2062 2063 AsmType* left_type; 2064 AsmType* right_type; 2065 RECURSE(left_type = ValidateExpression(left)); 2066 RECURSE(right_type = ValidateExpression(right)); 2067 2068 #define CMPOP_OVERLOAD(Src0, Src1, Dest) \ 2069 do { \ 2070 if (left_type->IsA(AsmType::Src0()) && right_type->IsA(AsmType::Src1())) { \ 2071 return AsmType::Dest(); \ 2072 } \ 2073 } while (0) 2074 switch (cmpop->op()) { 2075 default: 2076 FAIL(cmpop, "Invalid relational expression."); 2077 case Token::LT: 2078 CMPOP_OVERLOAD(Signed, Signed, Int); 2079 CMPOP_OVERLOAD(Unsigned, Unsigned, Int); 2080 CMPOP_OVERLOAD(Float, Float, Int); 2081 CMPOP_OVERLOAD(Double, Double, Int); 2082 FAIL(cmpop, "Invalid operands for <."); 2083 case Token::GT: 2084 CMPOP_OVERLOAD(Signed, Signed, Int); 2085 CMPOP_OVERLOAD(Unsigned, Unsigned, Int); 2086 CMPOP_OVERLOAD(Float, Float, Int); 2087 CMPOP_OVERLOAD(Double, Double, Int); 2088 FAIL(cmpop, "Invalid operands for >."); 2089 case Token::LTE: 2090 CMPOP_OVERLOAD(Signed, Signed, Int); 2091 CMPOP_OVERLOAD(Unsigned, Unsigned, Int); 2092 CMPOP_OVERLOAD(Float, Float, Int); 2093 CMPOP_OVERLOAD(Double, Double, Int); 2094 FAIL(cmpop, "Invalid operands for <=."); 2095 case Token::GTE: 2096 CMPOP_OVERLOAD(Signed, Signed, Int); 2097 CMPOP_OVERLOAD(Unsigned, Unsigned, Int); 2098 CMPOP_OVERLOAD(Float, Float, Int); 2099 CMPOP_OVERLOAD(Double, Double, Int); 2100 FAIL(cmpop, "Invalid operands for >=."); 2101 } 2102 #undef CMPOP_OVERLOAD 2103 2104 UNREACHABLE(); 2105 } 2106 2107 // 6.8.12 EqualityExpression 2108 AsmType* AsmTyper::ValidateEqualityExpression(CompareOperation* cmpop) { 2109 auto* left = cmpop->left(); 2110 auto* right = cmpop->right(); 2111 2112 AsmType* left_type; 2113 AsmType* right_type; 2114 RECURSE(left_type = ValidateExpression(left)); 2115 RECURSE(right_type = ValidateExpression(right)); 2116 2117 #define CMPOP_OVERLOAD(Src0, Src1, Dest) \ 2118 do { \ 2119 if (left_type->IsA(AsmType::Src0()) && right_type->IsA(AsmType::Src1())) { \ 2120 return AsmType::Dest(); \ 2121 } \ 2122 } while (0) 2123 switch (cmpop->op()) { 2124 default: 2125 FAIL(cmpop, "Invalid equality expression."); 2126 case Token::EQ: 2127 CMPOP_OVERLOAD(Signed, Signed, Int); 2128 CMPOP_OVERLOAD(Unsigned, Unsigned, Int); 2129 CMPOP_OVERLOAD(Float, Float, Int); 2130 CMPOP_OVERLOAD(Double, Double, Int); 2131 FAIL(cmpop, "Invalid operands for ==."); 2132 case Token::NE: 2133 CMPOP_OVERLOAD(Signed, Signed, Int); 2134 CMPOP_OVERLOAD(Unsigned, Unsigned, Int); 2135 CMPOP_OVERLOAD(Float, Float, Int); 2136 CMPOP_OVERLOAD(Double, Double, Int); 2137 FAIL(cmpop, "Invalid operands for !=."); 2138 } 2139 #undef CMPOP_OVERLOAD 2140 2141 UNREACHABLE(); 2142 } 2143 2144 // 6.8.13 BitwiseANDExpression 2145 AsmType* AsmTyper::ValidateBitwiseANDExpression(BinaryOperation* binop) { 2146 auto* left = binop->left(); 2147 auto* right = binop->right(); 2148 2149 AsmType* left_type; 2150 AsmType* right_type; 2151 RECURSE(left_type = ValidateExpression(left)); 2152 RECURSE(right_type = ValidateExpression(right)); 2153 2154 if (binop->op() != Token::BIT_AND) { 2155 FAIL(binop, "Invalid & expression."); 2156 } 2157 2158 #define BINOP_OVERLOAD(Src0, Src1, Dest) \ 2159 do { \ 2160 if (left_type->IsA(AsmType::Src0()) && right_type->IsA(AsmType::Src1())) { \ 2161 return AsmType::Dest(); \ 2162 } \ 2163 } while (0) 2164 BINOP_OVERLOAD(Intish, Intish, Signed); 2165 FAIL(binop, "Invalid operands for &."); 2166 #undef BINOP_OVERLOAD 2167 2168 UNREACHABLE(); 2169 } 2170 2171 // 6.8.14 BitwiseXORExpression 2172 AsmType* AsmTyper::ValidateBitwiseXORExpression(BinaryOperation* binop) { 2173 auto* left = binop->left(); 2174 auto* right = binop->right(); 2175 2176 AsmType* left_type; 2177 AsmType* right_type; 2178 RECURSE(left_type = ValidateExpression(left)); 2179 RECURSE(right_type = ValidateExpression(right)); 2180 2181 if (binop->op() != Token::BIT_XOR) { 2182 FAIL(binop, "Invalid ^ expression."); 2183 } 2184 2185 #define BINOP_OVERLOAD(Src0, Src1, Dest) \ 2186 do { \ 2187 if (left_type->IsA(AsmType::Src0()) && right_type->IsA(AsmType::Src1())) { \ 2188 return AsmType::Dest(); \ 2189 } \ 2190 } while (0) 2191 BINOP_OVERLOAD(Intish, Intish, Signed); 2192 FAIL(binop, "Invalid operands for ^."); 2193 #undef BINOP_OVERLOAD 2194 2195 UNREACHABLE(); 2196 } 2197 2198 // 6.8.15 BitwiseORExpression 2199 AsmType* AsmTyper::ValidateBitwiseORExpression(BinaryOperation* binop) { 2200 auto* left = binop->left(); 2201 if (IsIntAnnotation(binop)) { 2202 if (auto* left_as_call = left->AsCall()) { 2203 AsmType* type; 2204 RECURSE(type = ValidateCall(AsmType::Signed(), left_as_call)); 2205 return type; 2206 } 2207 2208 // TODO(jpp): at this point we know that binop is expr|0. We could sinply 2209 // 2210 // RECURSE(t = ValidateExpression(left)); 2211 // FAIL_IF(t->IsNotA(Intish)); 2212 // return Signed; 2213 } 2214 2215 auto* right = binop->right(); 2216 AsmType* left_type; 2217 AsmType* right_type; 2218 RECURSE(left_type = ValidateExpression(left)); 2219 RECURSE(right_type = ValidateExpression(right)); 2220 2221 if (binop->op() != Token::BIT_OR) { 2222 FAIL(binop, "Invalid | expression."); 2223 } 2224 2225 #define BINOP_OVERLOAD(Src0, Src1, Dest) \ 2226 do { \ 2227 if (left_type->IsA(AsmType::Src0()) && right_type->IsA(AsmType::Src1())) { \ 2228 return AsmType::Dest(); \ 2229 } \ 2230 } while (0) 2231 BINOP_OVERLOAD(Intish, Intish, Signed); 2232 FAIL(binop, "Invalid operands for |."); 2233 #undef BINOP_OVERLOAD 2234 2235 UNREACHABLE(); 2236 } 2237 2238 // 6.8.16 ConditionalExpression 2239 AsmType* AsmTyper::ValidateConditionalExpression(Conditional* cond) { 2240 AsmType* cond_type; 2241 RECURSE(cond_type = ValidateExpression(cond->condition())); 2242 if (!cond_type->IsA(AsmType::Int())) { 2243 FAIL(cond, "Ternary operation condition should be int."); 2244 } 2245 2246 AsmType* then_type; 2247 RECURSE(then_type = ValidateExpression(cond->then_expression())); 2248 AsmType* else_type; 2249 RECURSE(else_type = ValidateExpression(cond->else_expression())); 2250 2251 #define SUCCEED_IF_BOTH_ARE(type) \ 2252 do { \ 2253 if (then_type->IsA(AsmType::type())) { \ 2254 if (!else_type->IsA(AsmType::type())) { \ 2255 FAIL(cond, "Type mismatch for ternary operation result type."); \ 2256 } \ 2257 return AsmType::type(); \ 2258 } \ 2259 } while (0) 2260 SUCCEED_IF_BOTH_ARE(Int); 2261 SUCCEED_IF_BOTH_ARE(Float); 2262 SUCCEED_IF_BOTH_ARE(Double); 2263 #undef SUCCEED_IF_BOTH_ARE 2264 2265 FAIL(cond, "Ternary operator must return int, float, or double."); 2266 } 2267 2268 // 6.9 ValidateCall 2269 namespace { 2270 bool ExtractIndirectCallMask(Expression* expr, uint32_t* value) { 2271 auto* as_literal = expr->AsLiteral(); 2272 if (as_literal == nullptr) { 2273 return false; 2274 } 2275 2276 if (as_literal->raw_value()->ContainsDot()) { 2277 return false; 2278 } 2279 2280 if (!as_literal->value()->ToUint32(value)) { 2281 return false; 2282 } 2283 2284 return base::bits::IsPowerOfTwo32(1 + *value); 2285 } 2286 } // namespace 2287 2288 AsmType* AsmTyper::ValidateCall(AsmType* return_type, Call* call) { 2289 AsmType* float_coercion_type; 2290 RECURSE(float_coercion_type = ValidateFloatCoercion(call)); 2291 if (float_coercion_type == AsmType::Float()) { 2292 SetTypeOf(call, AsmType::Float()); 2293 return return_type; 2294 } 2295 2296 // TODO(jpp): we should be able to reuse the args vector's storage space. 2297 ZoneVector<AsmType*> args(zone_); 2298 args.reserve(call->arguments()->length()); 2299 2300 for (auto* arg : *call->arguments()) { 2301 AsmType* arg_type; 2302 RECURSE(arg_type = ValidateExpression(arg)); 2303 args.emplace_back(arg_type); 2304 } 2305 2306 auto* call_expr = call->expression(); 2307 2308 // identifier(Expression...) 2309 if (auto* call_var_proxy = call_expr->AsVariableProxy()) { 2310 auto* call_var_info = Lookup(call_var_proxy->var()); 2311 2312 if (call_var_info == nullptr) { 2313 // We can't fail here: the validator performs a single pass over the AST, 2314 // so it is possible for some calls to be currently unresolved. We eagerly 2315 // add the function to the table of globals. 2316 auto* call_type = AsmType::Function(zone_, return_type)->AsFunctionType(); 2317 for (auto* arg : args) { 2318 call_type->AddArgument(arg->ToParameterType()); 2319 } 2320 auto* fun_info = 2321 new (zone_) VariableInfo(reinterpret_cast<AsmType*>(call_type)); 2322 fun_info->set_mutability(VariableInfo::kImmutableGlobal); 2323 AddForwardReference(call_var_proxy, fun_info); 2324 if (!ValidAsmIdentifier(call_var_proxy->name())) { 2325 FAIL(call_var_proxy, 2326 "Invalid asm.js identifier in (forward) function name."); 2327 } 2328 if (!AddGlobal(call_var_proxy->var(), fun_info)) { 2329 DCHECK(false); 2330 FAIL(call, "Redeclared global identifier."); 2331 } 2332 SetTypeOf(call_var_proxy, reinterpret_cast<AsmType*>(call_type)); 2333 SetTypeOf(call, return_type); 2334 return return_type; 2335 } 2336 2337 auto* callee_type = call_var_info->type()->AsCallableType(); 2338 if (callee_type == nullptr) { 2339 FAIL(call, "Calling something that's not a function."); 2340 } 2341 2342 if (callee_type->AsFFIType() != nullptr) { 2343 if (return_type == AsmType::Float()) { 2344 FAIL(call, "Foreign functions can't return float."); 2345 } 2346 // Record FFI use signature, since the asm->wasm translator must know 2347 // all uses up-front. 2348 ffi_use_signatures_.emplace_back( 2349 FFIUseSignature(call_var_proxy->var(), zone_)); 2350 FFIUseSignature* sig = &ffi_use_signatures_.back(); 2351 sig->return_type_ = return_type; 2352 sig->arg_types_.reserve(args.size()); 2353 for (size_t i = 0; i < args.size(); ++i) { 2354 sig->arg_types_.emplace_back(args[i]); 2355 } 2356 } 2357 2358 if (!callee_type->CanBeInvokedWith(return_type, args)) { 2359 FAIL(call, "Function invocation does not match function type."); 2360 } 2361 2362 SetTypeOf(call_var_proxy, call_var_info->type()); 2363 SetTypeOf(call, return_type); 2364 return return_type; 2365 } 2366 2367 // identifier[expr & n](Expression...) 2368 if (auto* call_property = call_expr->AsProperty()) { 2369 auto* index = call_property->key()->AsBinaryOperation(); 2370 if (index == nullptr || index->op() != Token::BIT_AND) { 2371 FAIL(call_property->key(), 2372 "Indirect call index must be in the expr & mask form."); 2373 } 2374 2375 auto* left = index->left(); 2376 auto* right = index->right(); 2377 uint32_t mask; 2378 if (!ExtractIndirectCallMask(right, &mask)) { 2379 if (!ExtractIndirectCallMask(left, &mask)) { 2380 FAIL(right, "Invalid indirect call mask."); 2381 } else { 2382 left = right; 2383 } 2384 } 2385 const uint32_t table_length = mask + 1; 2386 2387 AsmType* left_type; 2388 RECURSE(left_type = ValidateExpression(left)); 2389 if (!left_type->IsA(AsmType::Intish())) { 2390 FAIL(left, "Indirect call index should be an intish."); 2391 } 2392 2393 auto* name_var = call_property->obj()->AsVariableProxy(); 2394 2395 if (name_var == nullptr) { 2396 FAIL(call_property, "Invalid call."); 2397 } 2398 2399 auto* name_info = Lookup(name_var->var()); 2400 if (name_info == nullptr) { 2401 // We can't fail here -- just like above. 2402 auto* call_type = AsmType::Function(zone_, return_type)->AsFunctionType(); 2403 for (auto* arg : args) { 2404 call_type->AddArgument(arg->ToParameterType()); 2405 } 2406 auto* table_type = AsmType::FunctionTableType( 2407 zone_, table_length, reinterpret_cast<AsmType*>(call_type)); 2408 auto* fun_info = 2409 new (zone_) VariableInfo(reinterpret_cast<AsmType*>(table_type)); 2410 fun_info->set_mutability(VariableInfo::kImmutableGlobal); 2411 AddForwardReference(name_var, fun_info); 2412 if (!ValidAsmIdentifier(name_var->name())) { 2413 FAIL(name_var, 2414 "Invalid asm.js identifier in (forward) function table name."); 2415 } 2416 if (!AddGlobal(name_var->var(), fun_info)) { 2417 DCHECK(false); 2418 FAIL(call, "Redeclared global identifier."); 2419 } 2420 SetTypeOf(call_property, reinterpret_cast<AsmType*>(call_type)); 2421 SetTypeOf(call, return_type); 2422 return return_type; 2423 } 2424 2425 auto* previous_type = name_info->type()->AsFunctionTableType(); 2426 if (previous_type == nullptr) { 2427 FAIL(call, "Identifier does not name a function table."); 2428 } 2429 2430 if (table_length != previous_type->length()) { 2431 FAIL(call, "Function table size does not match expected size."); 2432 } 2433 2434 auto* previous_type_signature = 2435 previous_type->signature()->AsFunctionType(); 2436 DCHECK(previous_type_signature != nullptr); 2437 if (!previous_type_signature->CanBeInvokedWith(return_type, args)) { 2438 // TODO(jpp): better error messages. 2439 FAIL(call, 2440 "Function pointer table signature does not match previous " 2441 "signature."); 2442 } 2443 2444 SetTypeOf(call_property, previous_type->signature()); 2445 SetTypeOf(call, return_type); 2446 return return_type; 2447 } 2448 2449 FAIL(call, "Invalid call."); 2450 } 2451 2452 // 6.10 ValidateHeapAccess 2453 namespace { 2454 bool ExtractHeapAccessShift(Expression* expr, uint32_t* value) { 2455 auto* as_literal = expr->AsLiteral(); 2456 if (as_literal == nullptr) { 2457 return false; 2458 } 2459 2460 if (as_literal->raw_value()->ContainsDot()) { 2461 return false; 2462 } 2463 2464 return as_literal->value()->ToUint32(value); 2465 } 2466 2467 // Returns whether index is too large to access a heap with the given type. 2468 bool LiteralIndexOutOfBounds(AsmType* obj_type, uint32_t index) { 2469 switch (obj_type->ElementSizeInBytes()) { 2470 case 1: 2471 return false; 2472 case 2: 2473 return (index & 0x80000000u) != 0; 2474 case 4: 2475 return (index & 0xC0000000u) != 0; 2476 case 8: 2477 return (index & 0xE0000000u) != 0; 2478 } 2479 UNREACHABLE(); 2480 return true; 2481 } 2482 2483 } // namespace 2484 2485 AsmType* AsmTyper::ValidateHeapAccess(Property* heap, 2486 HeapAccessType access_type) { 2487 auto* obj = heap->obj()->AsVariableProxy(); 2488 if (obj == nullptr) { 2489 FAIL(heap, "Invalid heap access."); 2490 } 2491 2492 auto* obj_info = Lookup(obj->var()); 2493 if (obj_info == nullptr) { 2494 FAIL(heap, "Undeclared identifier in heap access."); 2495 } 2496 2497 auto* obj_type = obj_info->type(); 2498 if (!obj_type->IsA(AsmType::Heap())) { 2499 FAIL(heap, "Identifier does not represent a heap view."); 2500 } 2501 SetTypeOf(obj, obj_type); 2502 2503 if (auto* key_as_literal = heap->key()->AsLiteral()) { 2504 if (key_as_literal->raw_value()->ContainsDot()) { 2505 FAIL(key_as_literal, "Heap access index must be int."); 2506 } 2507 2508 uint32_t index; 2509 if (!key_as_literal->value()->ToUint32(&index)) { 2510 FAIL(key_as_literal, 2511 "Heap access index must be a 32-bit unsigned integer."); 2512 } 2513 2514 if (LiteralIndexOutOfBounds(obj_type, index)) { 2515 FAIL(key_as_literal, "Heap access index is out of bounds"); 2516 } 2517 2518 if (access_type == LoadFromHeap) { 2519 return obj_type->LoadType(); 2520 } 2521 return obj_type->StoreType(); 2522 } 2523 2524 if (auto* key_as_binop = heap->key()->AsBinaryOperation()) { 2525 uint32_t shift; 2526 if (key_as_binop->op() == Token::SAR && 2527 ExtractHeapAccessShift(key_as_binop->right(), &shift) && 2528 (1 << shift) == obj_type->ElementSizeInBytes()) { 2529 AsmType* type; 2530 RECURSE(type = ValidateExpression(key_as_binop->left())); 2531 if (type->IsA(AsmType::Intish())) { 2532 if (access_type == LoadFromHeap) { 2533 return obj_type->LoadType(); 2534 } 2535 return obj_type->StoreType(); 2536 } 2537 FAIL(key_as_binop, "Invalid heap access index."); 2538 } 2539 } 2540 2541 if (obj_type->ElementSizeInBytes() == 1) { 2542 // Leniency: if this is a byte array, we don't require the shift operation 2543 // to be present. 2544 AsmType* index_type; 2545 RECURSE(index_type = ValidateExpression(heap->key())); 2546 if (!index_type->IsA(AsmType::Int())) { 2547 FAIL(heap, "Invalid heap access index for byte array."); 2548 } 2549 if (access_type == LoadFromHeap) { 2550 return obj_type->LoadType(); 2551 } 2552 return obj_type->StoreType(); 2553 } 2554 2555 FAIL(heap, "Invalid heap access index."); 2556 } 2557 2558 // 6.11 ValidateFloatCoercion 2559 bool AsmTyper::IsCallToFround(Call* call) { 2560 if (call->arguments()->length() != 1) { 2561 return false; 2562 } 2563 2564 auto* call_var_proxy = call->expression()->AsVariableProxy(); 2565 if (call_var_proxy == nullptr) { 2566 return false; 2567 } 2568 2569 auto* call_var_info = Lookup(call_var_proxy->var()); 2570 if (call_var_info == nullptr) { 2571 return false; 2572 } 2573 2574 return call_var_info->standard_member() == kMathFround; 2575 } 2576 2577 AsmType* AsmTyper::ValidateFloatCoercion(Call* call) { 2578 if (!IsCallToFround(call)) { 2579 return nullptr; 2580 } 2581 2582 auto* arg = call->arguments()->at(0); 2583 // call is a fround() node. From now, there can be two possible outcomes: 2584 // 1. fround is used as a return type annotation. 2585 if (auto* arg_as_call = arg->AsCall()) { 2586 RECURSE(ValidateCall(AsmType::Float(), arg_as_call)); 2587 return AsmType::Float(); 2588 } 2589 2590 // 2. fround is used for converting to float. 2591 AsmType* arg_type; 2592 RECURSE(arg_type = ValidateExpression(arg)); 2593 if (arg_type->IsA(AsmType::Floatish()) || arg_type->IsA(AsmType::DoubleQ()) || 2594 arg_type->IsA(AsmType::Signed()) || arg_type->IsA(AsmType::Unsigned())) { 2595 SetTypeOf(call->expression(), fround_type_); 2596 return AsmType::Float(); 2597 } 2598 2599 FAIL(call, "Invalid argument type to fround."); 2600 } 2601 2602 // 5.1 ParameterTypeAnnotations 2603 AsmType* AsmTyper::ParameterTypeAnnotations(Variable* parameter, 2604 Expression* annotation) { 2605 if (auto* binop = annotation->AsBinaryOperation()) { 2606 // Must be: 2607 // * x|0 2608 // * x*1 (*VIOLATION* i.e.,, +x) 2609 auto* left = binop->left()->AsVariableProxy(); 2610 if (left == nullptr) { 2611 FAIL( 2612 binop->left(), 2613 "Invalid parameter type annotation - should annotate an identifier."); 2614 } 2615 if (left->var() != parameter) { 2616 FAIL(binop->left(), 2617 "Invalid parameter type annotation - should annotate a parameter."); 2618 } 2619 if (IsDoubleAnnotation(binop)) { 2620 SetTypeOf(left, AsmType::Double()); 2621 return AsmType::Double(); 2622 } 2623 if (IsIntAnnotation(binop)) { 2624 SetTypeOf(left, AsmType::Int()); 2625 return AsmType::Int(); 2626 } 2627 FAIL(binop, "Invalid parameter type annotation."); 2628 } 2629 2630 auto* call = annotation->AsCall(); 2631 if (call == nullptr) { 2632 FAIL( 2633 annotation, 2634 "Invalid float parameter type annotation - must be fround(parameter)."); 2635 } 2636 2637 if (!IsCallToFround(call)) { 2638 FAIL(annotation, 2639 "Invalid float parameter type annotation - must be call to fround."); 2640 } 2641 2642 auto* src_expr = call->arguments()->at(0)->AsVariableProxy(); 2643 if (src_expr == nullptr) { 2644 FAIL(annotation, 2645 "Invalid float parameter type annotation - argument to fround is not " 2646 "an identifier."); 2647 } 2648 2649 if (src_expr->var() != parameter) { 2650 FAIL(annotation, 2651 "Invalid float parameter type annotation - argument to fround is not " 2652 "a parameter."); 2653 } 2654 2655 SetTypeOf(src_expr, AsmType::Float()); 2656 return AsmType::Float(); 2657 } 2658 2659 // 5.2 ReturnTypeAnnotations 2660 AsmType* AsmTyper::ReturnTypeAnnotations(ReturnStatement* statement) { 2661 if (statement == nullptr) { 2662 return AsmType::Void(); 2663 } 2664 2665 auto* ret_expr = statement->expression(); 2666 if (ret_expr == nullptr) { 2667 return AsmType::Void(); 2668 } 2669 2670 if (auto* binop = ret_expr->AsBinaryOperation()) { 2671 if (IsDoubleAnnotation(binop)) { 2672 return AsmType::Double(); 2673 } else if (IsIntAnnotation(binop)) { 2674 return AsmType::Signed(); 2675 } 2676 FAIL(statement, "Invalid return type annotation."); 2677 } 2678 2679 if (auto* call = ret_expr->AsCall()) { 2680 if (IsCallToFround(call)) { 2681 return AsmType::Float(); 2682 } 2683 FAIL(statement, "Invalid function call in return statement."); 2684 } 2685 2686 if (auto* literal = ret_expr->AsLiteral()) { 2687 int32_t _; 2688 if (literal->raw_value()->ContainsDot()) { 2689 return AsmType::Double(); 2690 } else if (literal->value()->ToInt32(&_)) { 2691 return AsmType::Signed(); 2692 } else if (literal->IsUndefinedLiteral()) { 2693 // *VIOLATION* The parser changes 2694 // 2695 // return; 2696 // 2697 // into 2698 // 2699 // return undefined 2700 return AsmType::Void(); 2701 } 2702 FAIL(statement, "Invalid literal in return statement."); 2703 } 2704 2705 if (auto* proxy = ret_expr->AsVariableProxy()) { 2706 auto* var_info = Lookup(proxy->var()); 2707 2708 if (var_info == nullptr) { 2709 FAIL(statement, "Undeclared identifier in return statement."); 2710 } 2711 2712 if (var_info->mutability() != VariableInfo::kConstGlobal) { 2713 FAIL(statement, "Identifier in return statement is not const."); 2714 } 2715 2716 if (!var_info->type()->IsReturnType()) { 2717 FAIL(statement, "Constant in return must be signed, float, or double."); 2718 } 2719 2720 return var_info->type(); 2721 } 2722 2723 FAIL(statement, "Invalid return type expression."); 2724 } 2725 2726 // 5.4 VariableTypeAnnotations 2727 // Also used for 5.5 GlobalVariableTypeAnnotations 2728 AsmType* AsmTyper::VariableTypeAnnotations( 2729 Expression* initializer, VariableInfo::Mutability mutability_type) { 2730 if (auto* literal = initializer->AsLiteral()) { 2731 if (literal->raw_value()->ContainsDot()) { 2732 SetTypeOf(initializer, AsmType::Double()); 2733 return AsmType::Double(); 2734 } 2735 int32_t i32; 2736 uint32_t u32; 2737 2738 AsmType* initializer_type = nullptr; 2739 if (literal->value()->ToUint32(&u32)) { 2740 if (u32 > LargestFixNum) { 2741 initializer_type = AsmType::Unsigned(); 2742 SetTypeOf(initializer, initializer_type); 2743 } else { 2744 initializer_type = AsmType::FixNum(); 2745 SetTypeOf(initializer, initializer_type); 2746 initializer_type = AsmType::Signed(); 2747 } 2748 } else if (literal->value()->ToInt32(&i32)) { 2749 initializer_type = AsmType::Signed(); 2750 SetTypeOf(initializer, initializer_type); 2751 } else { 2752 FAIL(initializer, "Invalid type annotation - forbidden literal."); 2753 } 2754 if (mutability_type != VariableInfo::kConstGlobal) { 2755 return AsmType::Int(); 2756 } 2757 return initializer_type; 2758 } 2759 2760 if (auto* proxy = initializer->AsVariableProxy()) { 2761 auto* var_info = Lookup(proxy->var()); 2762 2763 if (var_info == nullptr) { 2764 FAIL(initializer, 2765 "Undeclared identifier in variable declaration initializer."); 2766 } 2767 2768 if (var_info->mutability() != VariableInfo::kConstGlobal) { 2769 FAIL(initializer, 2770 "Identifier in variable declaration initializer must be const."); 2771 } 2772 2773 SetTypeOf(initializer, var_info->type()); 2774 return var_info->type(); 2775 } 2776 2777 auto* call = initializer->AsCall(); 2778 if (call == nullptr) { 2779 FAIL(initializer, 2780 "Invalid variable initialization - it should be a literal, const, or " 2781 "fround(literal)."); 2782 } 2783 2784 if (!IsCallToFround(call)) { 2785 FAIL(initializer, 2786 "Invalid float coercion - expected call fround(literal)."); 2787 } 2788 2789 auto* src_expr = call->arguments()->at(0)->AsLiteral(); 2790 if (src_expr == nullptr) { 2791 FAIL(initializer, 2792 "Invalid float type annotation - expected literal argument for call " 2793 "to fround."); 2794 } 2795 2796 // Float constants must contain dots in local, but not in globals. 2797 if (mutability_type == VariableInfo::kLocal) { 2798 if (!src_expr->raw_value()->ContainsDot()) { 2799 FAIL(initializer, 2800 "Invalid float type annotation - expected literal argument to be a " 2801 "floating point literal."); 2802 } 2803 } 2804 2805 return AsmType::Float(); 2806 } 2807 2808 // 5.5 GlobalVariableTypeAnnotations 2809 AsmType* AsmTyper::NewHeapView(CallNew* new_heap_view) { 2810 auto* heap_type = new_heap_view->expression()->AsProperty(); 2811 if (heap_type == nullptr) { 2812 FAIL(new_heap_view, "Invalid type after new."); 2813 } 2814 auto* heap_view_info = ImportLookup(heap_type); 2815 2816 if (heap_view_info == nullptr) { 2817 FAIL(new_heap_view, "Unknown stdlib member in heap view declaration."); 2818 } 2819 2820 if (!heap_view_info->type()->IsA(AsmType::Heap())) { 2821 FAIL(new_heap_view, "Type is not a heap view type."); 2822 } 2823 2824 if (new_heap_view->arguments()->length() != 1) { 2825 FAIL(new_heap_view, "Invalid number of arguments when creating heap view."); 2826 } 2827 2828 auto* heap = new_heap_view->arguments()->at(0); 2829 auto* heap_var_proxy = heap->AsVariableProxy(); 2830 2831 if (heap_var_proxy == nullptr) { 2832 FAIL(heap, 2833 "Heap view creation parameter should be the module's heap parameter."); 2834 } 2835 2836 auto* heap_var_info = Lookup(heap_var_proxy->var()); 2837 2838 if (heap_var_info == nullptr) { 2839 FAIL(heap, "Undeclared identifier instead of heap parameter."); 2840 } 2841 2842 if (!heap_var_info->IsHeap()) { 2843 FAIL(heap, 2844 "Heap view creation parameter should be the module's heap parameter."); 2845 } 2846 2847 DCHECK(heap_view_info->type()->IsA(AsmType::Heap())); 2848 return heap_view_info->type(); 2849 } 2850 2851 bool IsValidAsm(Isolate* isolate, Zone* zone, Script* script, 2852 FunctionLiteral* root, std::string* error_message) { 2853 error_message->clear(); 2854 2855 AsmTyper typer(isolate, zone, script, root); 2856 if (typer.Validate()) { 2857 return true; 2858 } 2859 2860 *error_message = typer.error_message(); 2861 return false; 2862 } 2863 2864 } // namespace wasm 2865 } // namespace internal 2866 } // namespace v8 2867