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