1// Copyright 2017 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-parser.h" 6 7#include <math.h> 8#include <string.h> 9 10#include <algorithm> 11 12#include "src/asmjs/asm-js.h" 13#include "src/asmjs/asm-types.h" 14#include "src/base/optional.h" 15#include "src/base/overflowing-math.h" 16#include "src/flags/flags.h" 17#include "src/numbers/conversions-inl.h" 18#include "src/parsing/scanner.h" 19#include "src/wasm/wasm-limits.h" 20#include "src/wasm/wasm-opcodes.h" 21 22namespace v8 { 23namespace internal { 24namespace wasm { 25 26#ifdef DEBUG 27#define FAIL_AND_RETURN(ret, msg) \ 28 failed_ = true; \ 29 failure_message_ = msg; \ 30 failure_location_ = static_cast<int>(scanner_.Position()); \ 31 if (FLAG_trace_asm_parser) { \ 32 PrintF("[asm.js failure: %s, token: '%s', see: %s:%d]\n", msg, \ 33 scanner_.Name(scanner_.Token()).c_str(), __FILE__, __LINE__); \ 34 } \ 35 return ret; 36#else 37#define FAIL_AND_RETURN(ret, msg) \ 38 failed_ = true; \ 39 failure_message_ = msg; \ 40 failure_location_ = static_cast<int>(scanner_.Position()); \ 41 return ret; 42#endif 43 44#define FAIL(msg) FAIL_AND_RETURN(, msg) 45#define FAILn(msg) FAIL_AND_RETURN(nullptr, msg) 46 47#define EXPECT_TOKEN_OR_RETURN(ret, token) \ 48 do { \ 49 if (scanner_.Token() != token) { \ 50 FAIL_AND_RETURN(ret, "Unexpected token"); \ 51 } \ 52 scanner_.Next(); \ 53 } while (false) 54 55#define EXPECT_TOKEN(token) EXPECT_TOKEN_OR_RETURN(, token) 56#define EXPECT_TOKENn(token) EXPECT_TOKEN_OR_RETURN(nullptr, token) 57 58#define RECURSE_OR_RETURN(ret, call) \ 59 do { \ 60 DCHECK(!failed_); \ 61 if (GetCurrentStackPosition() < stack_limit_) { \ 62 FAIL_AND_RETURN(ret, "Stack overflow while parsing asm.js module."); \ 63 } \ 64 call; \ 65 if (failed_) return ret; \ 66 } while (false) 67 68#define RECURSE(call) RECURSE_OR_RETURN(, call) 69#define RECURSEn(call) RECURSE_OR_RETURN(nullptr, call) 70 71#define TOK(name) AsmJsScanner::kToken_##name 72 73AsmJsParser::AsmJsParser(Zone* zone, uintptr_t stack_limit, 74 Utf16CharacterStream* stream) 75 : zone_(zone), 76 scanner_(stream), 77 module_builder_(zone->New<WasmModuleBuilder>(zone)), 78 stack_limit_(stack_limit), 79 block_stack_(zone), 80 global_imports_(zone) { 81 module_builder_->SetMinMemorySize(0); 82 InitializeStdlibTypes(); 83} 84 85void AsmJsParser::InitializeStdlibTypes() { 86 auto* d = AsmType::Double(); 87 auto* dq = AsmType::DoubleQ(); 88 stdlib_dq2d_ = AsmType::Function(zone(), d); 89 stdlib_dq2d_->AsFunctionType()->AddArgument(dq); 90 91 stdlib_dqdq2d_ = AsmType::Function(zone(), d); 92 stdlib_dqdq2d_->AsFunctionType()->AddArgument(dq); 93 stdlib_dqdq2d_->AsFunctionType()->AddArgument(dq); 94 95 auto* f = AsmType::Float(); 96 auto* fh = AsmType::Floatish(); 97 auto* fq = AsmType::FloatQ(); 98 auto* fq2fh = AsmType::Function(zone(), fh); 99 fq2fh->AsFunctionType()->AddArgument(fq); 100 101 auto* s = AsmType::Signed(); 102 auto* u = AsmType::Unsigned(); 103 auto* s2u = AsmType::Function(zone(), u); 104 s2u->AsFunctionType()->AddArgument(s); 105 106 auto* i = AsmType::Int(); 107 stdlib_i2s_ = AsmType::Function(zone_, s); 108 stdlib_i2s_->AsFunctionType()->AddArgument(i); 109 110 stdlib_ii2s_ = AsmType::Function(zone(), s); 111 stdlib_ii2s_->AsFunctionType()->AddArgument(i); 112 stdlib_ii2s_->AsFunctionType()->AddArgument(i); 113 114 // The signatures in "9 Standard Library" of the spec draft are outdated and 115 // have been superseded with the following by an errata: 116 // - Math.min/max : (signed, signed...) -> signed 117 // (double, double...) -> double 118 // (float, float...) -> float 119 auto* minmax_d = AsmType::MinMaxType(zone(), d, d); 120 auto* minmax_f = AsmType::MinMaxType(zone(), f, f); 121 auto* minmax_s = AsmType::MinMaxType(zone(), s, s); 122 stdlib_minmax_ = AsmType::OverloadedFunction(zone()); 123 stdlib_minmax_->AsOverloadedFunctionType()->AddOverload(minmax_s); 124 stdlib_minmax_->AsOverloadedFunctionType()->AddOverload(minmax_f); 125 stdlib_minmax_->AsOverloadedFunctionType()->AddOverload(minmax_d); 126 127 // The signatures in "9 Standard Library" of the spec draft are outdated and 128 // have been superseded with the following by an errata: 129 // - Math.abs : (signed) -> unsigned 130 // (double?) -> double 131 // (float?) -> floatish 132 stdlib_abs_ = AsmType::OverloadedFunction(zone()); 133 stdlib_abs_->AsOverloadedFunctionType()->AddOverload(s2u); 134 stdlib_abs_->AsOverloadedFunctionType()->AddOverload(stdlib_dq2d_); 135 stdlib_abs_->AsOverloadedFunctionType()->AddOverload(fq2fh); 136 137 // The signatures in "9 Standard Library" of the spec draft are outdated and 138 // have been superseded with the following by an errata: 139 // - Math.ceil/floor/sqrt : (double?) -> double 140 // (float?) -> floatish 141 stdlib_ceil_like_ = AsmType::OverloadedFunction(zone()); 142 stdlib_ceil_like_->AsOverloadedFunctionType()->AddOverload(stdlib_dq2d_); 143 stdlib_ceil_like_->AsOverloadedFunctionType()->AddOverload(fq2fh); 144 145 stdlib_fround_ = AsmType::FroundType(zone()); 146} 147 148FunctionSig* AsmJsParser::ConvertSignature(AsmType* return_type, 149 const ZoneVector<AsmType*>& params) { 150 FunctionSig::Builder sig_builder( 151 zone(), !return_type->IsA(AsmType::Void()) ? 1 : 0, params.size()); 152 for (auto param : params) { 153 if (param->IsA(AsmType::Double())) { 154 sig_builder.AddParam(kWasmF64); 155 } else if (param->IsA(AsmType::Float())) { 156 sig_builder.AddParam(kWasmF32); 157 } else if (param->IsA(AsmType::Int())) { 158 sig_builder.AddParam(kWasmI32); 159 } else { 160 UNREACHABLE(); 161 } 162 } 163 if (!return_type->IsA(AsmType::Void())) { 164 if (return_type->IsA(AsmType::Double())) { 165 sig_builder.AddReturn(kWasmF64); 166 } else if (return_type->IsA(AsmType::Float())) { 167 sig_builder.AddReturn(kWasmF32); 168 } else if (return_type->IsA(AsmType::Signed())) { 169 sig_builder.AddReturn(kWasmI32); 170 } else { 171 UNREACHABLE(); 172 } 173 } 174 return sig_builder.Build(); 175} 176 177bool AsmJsParser::Run() { 178 ValidateModule(); 179 return !failed_; 180} 181 182class V8_NODISCARD AsmJsParser::TemporaryVariableScope { 183 public: 184 explicit TemporaryVariableScope(AsmJsParser* parser) : parser_(parser) { 185 local_depth_ = parser_->function_temp_locals_depth_; 186 parser_->function_temp_locals_depth_++; 187 } 188 ~TemporaryVariableScope() { 189 DCHECK_EQ(local_depth_, parser_->function_temp_locals_depth_ - 1); 190 parser_->function_temp_locals_depth_--; 191 } 192 uint32_t get() const { return parser_->TempVariable(local_depth_); } 193 194 private: 195 AsmJsParser* parser_; 196 int local_depth_; 197}; 198 199wasm::AsmJsParser::VarInfo* AsmJsParser::GetVarInfo( 200 AsmJsScanner::token_t token) { 201 const bool is_global = AsmJsScanner::IsGlobal(token); 202 DCHECK(is_global || AsmJsScanner::IsLocal(token)); 203 base::Vector<VarInfo>& var_info = 204 is_global ? global_var_info_ : local_var_info_; 205 size_t old_capacity = var_info.size(); 206 size_t index = is_global ? AsmJsScanner::GlobalIndex(token) 207 : AsmJsScanner::LocalIndex(token); 208 if (is_global && index + 1 > num_globals_) num_globals_ = index + 1; 209 if (index + 1 > old_capacity) { 210 size_t new_size = std::max(2 * old_capacity, index + 1); 211 base::Vector<VarInfo> new_info{zone_->NewArray<VarInfo>(new_size), 212 new_size}; 213 std::uninitialized_fill(new_info.begin(), new_info.end(), VarInfo{}); 214 std::copy(var_info.begin(), var_info.end(), new_info.begin()); 215 var_info = new_info; 216 } 217 return &var_info[index]; 218} 219 220uint32_t AsmJsParser::VarIndex(VarInfo* info) { 221 DCHECK_EQ(info->kind, VarKind::kGlobal); 222 return info->index + static_cast<uint32_t>(global_imports_.size()); 223} 224 225void AsmJsParser::AddGlobalImport(base::Vector<const char> name, AsmType* type, 226 ValueType vtype, bool mutable_variable, 227 VarInfo* info) { 228 // Allocate a separate variable for the import. 229 // TODO(asmjs): Consider using the imported global directly instead of 230 // allocating a separate global variable for immutable (i.e. const) imports. 231 DeclareGlobal(info, mutable_variable, type, vtype); 232 233 // Record the need to initialize the global from the import. 234 global_imports_.push_back({name, vtype, info}); 235} 236 237void AsmJsParser::DeclareGlobal(VarInfo* info, bool mutable_variable, 238 AsmType* type, ValueType vtype, 239 WasmInitExpr init) { 240 info->kind = VarKind::kGlobal; 241 info->type = type; 242 info->index = module_builder_->AddGlobal(vtype, true, init); 243 info->mutable_variable = mutable_variable; 244} 245 246void AsmJsParser::DeclareStdlibFunc(VarInfo* info, VarKind kind, 247 AsmType* type) { 248 info->kind = kind; 249 info->type = type; 250 info->index = 0; // unused 251 info->mutable_variable = false; 252} 253 254uint32_t AsmJsParser::TempVariable(int index) { 255 if (index + 1 > function_temp_locals_used_) { 256 function_temp_locals_used_ = index + 1; 257 } 258 return function_temp_locals_offset_ + index; 259} 260 261base::Vector<const char> AsmJsParser::CopyCurrentIdentifierString() { 262 const std::string& str = scanner_.GetIdentifierString(); 263 char* buffer = zone()->NewArray<char>(str.size()); 264 str.copy(buffer, str.size()); 265 return base::Vector<const char>(buffer, static_cast<int>(str.size())); 266} 267 268void AsmJsParser::SkipSemicolon() { 269 if (Check(';')) { 270 // Had a semicolon. 271 } else if (!Peek('}') && !scanner_.IsPrecededByNewline()) { 272 FAIL("Expected ;"); 273 } 274} 275 276void AsmJsParser::Begin(AsmJsScanner::token_t label) { 277 BareBegin(BlockKind::kRegular, label); 278 current_function_builder_->EmitWithU8(kExprBlock, kVoidCode); 279} 280 281void AsmJsParser::Loop(AsmJsScanner::token_t label) { 282 BareBegin(BlockKind::kLoop, label); 283 size_t position = scanner_.Position(); 284 current_function_builder_->AddAsmWasmOffset(position, position); 285 current_function_builder_->EmitWithU8(kExprLoop, kVoidCode); 286} 287 288void AsmJsParser::End() { 289 BareEnd(); 290 current_function_builder_->Emit(kExprEnd); 291} 292 293void AsmJsParser::BareBegin(BlockKind kind, AsmJsScanner::token_t label) { 294 BlockInfo info; 295 info.kind = kind; 296 info.label = label; 297 block_stack_.push_back(info); 298} 299 300void AsmJsParser::BareEnd() { 301 DCHECK_GT(block_stack_.size(), 0); 302 block_stack_.pop_back(); 303} 304 305int AsmJsParser::FindContinueLabelDepth(AsmJsScanner::token_t label) { 306 int count = 0; 307 for (auto it = block_stack_.rbegin(); it != block_stack_.rend(); 308 ++it, ++count) { 309 // A 'continue' statement targets ... 310 // - The innermost {kLoop} block if no label is given. 311 // - The matching {kLoop} block (when a label is provided). 312 if (it->kind == BlockKind::kLoop && 313 (label == kTokenNone || it->label == label)) { 314 return count; 315 } 316 } 317 return -1; 318} 319 320int AsmJsParser::FindBreakLabelDepth(AsmJsScanner::token_t label) { 321 int count = 0; 322 for (auto it = block_stack_.rbegin(); it != block_stack_.rend(); 323 ++it, ++count) { 324 // A 'break' statement targets ... 325 // - The innermost {kRegular} block if no label is given. 326 // - The matching {kRegular} or {kNamed} block (when a label is provided). 327 if ((it->kind == BlockKind::kRegular && 328 (label == kTokenNone || it->label == label)) || 329 (it->kind == BlockKind::kNamed && it->label == label)) { 330 return count; 331 } 332 } 333 return -1; 334} 335 336// 6.1 ValidateModule 337void AsmJsParser::ValidateModule() { 338 RECURSE(ValidateModuleParameters()); 339 EXPECT_TOKEN('{'); 340 EXPECT_TOKEN(TOK(UseAsm)); 341 RECURSE(SkipSemicolon()); 342 RECURSE(ValidateModuleVars()); 343 while (Peek(TOK(function))) { 344 RECURSE(ValidateFunction()); 345 } 346 while (Peek(TOK(var))) { 347 RECURSE(ValidateFunctionTable()); 348 } 349 RECURSE(ValidateExport()); 350 RECURSE(SkipSemicolon()); 351 EXPECT_TOKEN('}'); 352 353 // Check that all functions were eventually defined. 354 for (auto& info : global_var_info_.SubVector(0, num_globals_)) { 355 if (info.kind == VarKind::kFunction && !info.function_defined) { 356 FAIL("Undefined function"); 357 } 358 if (info.kind == VarKind::kTable && !info.function_defined) { 359 FAIL("Undefined function table"); 360 } 361 if (info.kind == VarKind::kImportedFunction && !info.function_defined) { 362 // For imported functions without a single call site, we insert a dummy 363 // import here to preserve the fact that there actually was an import. 364 FunctionSig* void_void_sig = FunctionSig::Builder(zone(), 0, 0).Build(); 365 module_builder_->AddImport(info.import->function_name, void_void_sig); 366 } 367 } 368 369 // Add start function to initialize things. 370 WasmFunctionBuilder* start = module_builder_->AddFunction(); 371 module_builder_->MarkStartFunction(start); 372 for (auto& global_import : global_imports_) { 373 uint32_t import_index = module_builder_->AddGlobalImport( 374 global_import.import_name, global_import.value_type, 375 false /* mutability */); 376 start->EmitWithI32V(kExprGlobalGet, import_index); 377 start->EmitWithI32V(kExprGlobalSet, VarIndex(global_import.var_info)); 378 } 379 start->Emit(kExprEnd); 380 FunctionSig::Builder b(zone(), 0, 0); 381 start->SetSignature(b.Build()); 382} 383 384// 6.1 ValidateModule - parameters 385void AsmJsParser::ValidateModuleParameters() { 386 EXPECT_TOKEN('('); 387 stdlib_name_ = 0; 388 foreign_name_ = 0; 389 heap_name_ = 0; 390 if (!Peek(')')) { 391 if (!scanner_.IsGlobal()) { 392 FAIL("Expected stdlib parameter"); 393 } 394 stdlib_name_ = Consume(); 395 if (!Peek(')')) { 396 EXPECT_TOKEN(','); 397 if (!scanner_.IsGlobal()) { 398 FAIL("Expected foreign parameter"); 399 } 400 foreign_name_ = Consume(); 401 if (stdlib_name_ == foreign_name_) { 402 FAIL("Duplicate parameter name"); 403 } 404 if (!Peek(')')) { 405 EXPECT_TOKEN(','); 406 if (!scanner_.IsGlobal()) { 407 FAIL("Expected heap parameter"); 408 } 409 heap_name_ = Consume(); 410 if (heap_name_ == stdlib_name_ || heap_name_ == foreign_name_) { 411 FAIL("Duplicate parameter name"); 412 } 413 } 414 } 415 } 416 EXPECT_TOKEN(')'); 417} 418 419// 6.1 ValidateModule - variables 420void AsmJsParser::ValidateModuleVars() { 421 while (Peek(TOK(var)) || Peek(TOK(const))) { 422 bool mutable_variable = true; 423 if (Check(TOK(var))) { 424 // Had a var. 425 } else { 426 EXPECT_TOKEN(TOK(const)); 427 mutable_variable = false; 428 } 429 for (;;) { 430 RECURSE(ValidateModuleVar(mutable_variable)); 431 if (Check(',')) { 432 continue; 433 } 434 break; 435 } 436 SkipSemicolon(); 437 } 438} 439 440// 6.1 ValidateModule - one variable 441void AsmJsParser::ValidateModuleVar(bool mutable_variable) { 442 if (!scanner_.IsGlobal()) { 443 FAIL("Expected identifier"); 444 } 445 VarInfo* info = GetVarInfo(Consume()); 446 if (info->kind != VarKind::kUnused) { 447 FAIL("Redefinition of variable"); 448 } 449 EXPECT_TOKEN('='); 450 double dvalue = 0.0; 451 uint32_t uvalue = 0; 452 if (CheckForDouble(&dvalue)) { 453 DeclareGlobal(info, mutable_variable, AsmType::Double(), kWasmF64, 454 WasmInitExpr(dvalue)); 455 } else if (CheckForUnsigned(&uvalue)) { 456 if (uvalue > 0x7FFFFFFF) { 457 FAIL("Numeric literal out of range"); 458 } 459 DeclareGlobal(info, mutable_variable, 460 mutable_variable ? AsmType::Int() : AsmType::Signed(), 461 kWasmI32, WasmInitExpr(static_cast<int32_t>(uvalue))); 462 } else if (Check('-')) { 463 if (CheckForDouble(&dvalue)) { 464 DeclareGlobal(info, mutable_variable, AsmType::Double(), kWasmF64, 465 WasmInitExpr(-dvalue)); 466 } else if (CheckForUnsigned(&uvalue)) { 467 if (uvalue > 0x7FFFFFFF) { 468 FAIL("Numeric literal out of range"); 469 } 470 if (uvalue == 0) { 471 // '-0' is treated as float. 472 DeclareGlobal(info, mutable_variable, AsmType::Float(), kWasmF32, 473 WasmInitExpr(-0.f)); 474 } else { 475 DeclareGlobal(info, mutable_variable, 476 mutable_variable ? AsmType::Int() : AsmType::Signed(), 477 kWasmI32, WasmInitExpr(-static_cast<int32_t>(uvalue))); 478 } 479 } else { 480 FAIL("Expected numeric literal"); 481 } 482 } else if (Check(TOK(new))) { 483 RECURSE(ValidateModuleVarNewStdlib(info)); 484 } else if (Check(stdlib_name_)) { 485 EXPECT_TOKEN('.'); 486 RECURSE(ValidateModuleVarStdlib(info)); 487 } else if (Peek(foreign_name_) || Peek('+')) { 488 RECURSE(ValidateModuleVarImport(info, mutable_variable)); 489 } else if (scanner_.IsGlobal()) { 490 RECURSE(ValidateModuleVarFromGlobal(info, mutable_variable)); 491 } else { 492 FAIL("Bad variable declaration"); 493 } 494} 495 496// 6.1 ValidateModule - global float declaration 497void AsmJsParser::ValidateModuleVarFromGlobal(VarInfo* info, 498 bool mutable_variable) { 499 VarInfo* src_info = GetVarInfo(Consume()); 500 if (!src_info->type->IsA(stdlib_fround_)) { 501 if (src_info->mutable_variable) { 502 FAIL("Can only use immutable variables in global definition"); 503 } 504 if (mutable_variable) { 505 FAIL("Can only define immutable variables with other immutables"); 506 } 507 if (!src_info->type->IsA(AsmType::Int()) && 508 !src_info->type->IsA(AsmType::Float()) && 509 !src_info->type->IsA(AsmType::Double())) { 510 FAIL("Expected int, float, double, or fround for global definition"); 511 } 512 info->kind = VarKind::kGlobal; 513 info->type = src_info->type; 514 info->index = src_info->index; 515 info->mutable_variable = false; 516 return; 517 } 518 EXPECT_TOKEN('('); 519 bool negate = false; 520 if (Check('-')) { 521 negate = true; 522 } 523 double dvalue = 0.0; 524 uint32_t uvalue = 0; 525 if (CheckForDouble(&dvalue)) { 526 if (negate) { 527 dvalue = -dvalue; 528 } 529 DeclareGlobal(info, mutable_variable, AsmType::Float(), kWasmF32, 530 WasmInitExpr(DoubleToFloat32(dvalue))); 531 } else if (CheckForUnsigned(&uvalue)) { 532 dvalue = uvalue; 533 if (negate) { 534 dvalue = -dvalue; 535 } 536 DeclareGlobal(info, mutable_variable, AsmType::Float(), kWasmF32, 537 WasmInitExpr(static_cast<float>(dvalue))); 538 } else { 539 FAIL("Expected numeric literal"); 540 } 541 EXPECT_TOKEN(')'); 542} 543 544// 6.1 ValidateModule - foreign imports 545void AsmJsParser::ValidateModuleVarImport(VarInfo* info, 546 bool mutable_variable) { 547 if (Check('+')) { 548 EXPECT_TOKEN(foreign_name_); 549 EXPECT_TOKEN('.'); 550 base::Vector<const char> name = CopyCurrentIdentifierString(); 551 AddGlobalImport(name, AsmType::Double(), kWasmF64, mutable_variable, info); 552 scanner_.Next(); 553 } else { 554 EXPECT_TOKEN(foreign_name_); 555 EXPECT_TOKEN('.'); 556 base::Vector<const char> name = CopyCurrentIdentifierString(); 557 scanner_.Next(); 558 if (Check('|')) { 559 if (!CheckForZero()) { 560 FAIL("Expected |0 type annotation for foreign integer import"); 561 } 562 AddGlobalImport(name, AsmType::Int(), kWasmI32, mutable_variable, info); 563 } else { 564 info->kind = VarKind::kImportedFunction; 565 info->import = zone()->New<FunctionImportInfo>(name, zone()); 566 info->mutable_variable = false; 567 } 568 } 569} 570 571// 6.1 ValidateModule - one variable 572// 9 - Standard Library - heap types 573void AsmJsParser::ValidateModuleVarNewStdlib(VarInfo* info) { 574 EXPECT_TOKEN(stdlib_name_); 575 EXPECT_TOKEN('.'); 576 switch (Consume()) { 577#define V(name, _junk1, _junk2, _junk3) \ 578 case TOK(name): \ 579 DeclareStdlibFunc(info, VarKind::kSpecial, AsmType::name()); \ 580 stdlib_uses_.Add(StandardMember::k##name); \ 581 break; 582 STDLIB_ARRAY_TYPE_LIST(V) 583#undef V 584 default: 585 FAIL("Expected ArrayBuffer view"); 586 } 587 EXPECT_TOKEN('('); 588 EXPECT_TOKEN(heap_name_); 589 EXPECT_TOKEN(')'); 590} 591 592// 6.1 ValidateModule - one variable 593// 9 - Standard Library 594void AsmJsParser::ValidateModuleVarStdlib(VarInfo* info) { 595 if (Check(TOK(Math))) { 596 EXPECT_TOKEN('.'); 597 switch (Consume()) { 598#define V(name, const_value) \ 599 case TOK(name): \ 600 DeclareGlobal(info, false, AsmType::Double(), kWasmF64, \ 601 WasmInitExpr(const_value)); \ 602 stdlib_uses_.Add(StandardMember::kMath##name); \ 603 break; 604 STDLIB_MATH_VALUE_LIST(V) 605#undef V 606#define V(name, Name, op, sig) \ 607 case TOK(name): \ 608 DeclareStdlibFunc(info, VarKind::kMath##Name, stdlib_##sig##_); \ 609 stdlib_uses_.Add(StandardMember::kMath##Name); \ 610 break; 611 STDLIB_MATH_FUNCTION_LIST(V) 612#undef V 613 default: 614 FAIL("Invalid member of stdlib.Math"); 615 } 616 } else if (Check(TOK(Infinity))) { 617 DeclareGlobal(info, false, AsmType::Double(), kWasmF64, 618 WasmInitExpr(std::numeric_limits<double>::infinity())); 619 stdlib_uses_.Add(StandardMember::kInfinity); 620 } else if (Check(TOK(NaN))) { 621 DeclareGlobal(info, false, AsmType::Double(), kWasmF64, 622 WasmInitExpr(std::numeric_limits<double>::quiet_NaN())); 623 stdlib_uses_.Add(StandardMember::kNaN); 624 } else { 625 FAIL("Invalid member of stdlib"); 626 } 627} 628 629// 6.2 ValidateExport 630void AsmJsParser::ValidateExport() { 631 // clang-format off 632 EXPECT_TOKEN(TOK(return)); 633 // clang-format on 634 if (Check('{')) { 635 for (;;) { 636 base::Vector<const char> name = CopyCurrentIdentifierString(); 637 if (!scanner_.IsGlobal() && !scanner_.IsLocal()) { 638 FAIL("Illegal export name"); 639 } 640 Consume(); 641 EXPECT_TOKEN(':'); 642 if (!scanner_.IsGlobal()) { 643 FAIL("Expected function name"); 644 } 645 VarInfo* info = GetVarInfo(Consume()); 646 if (info->kind != VarKind::kFunction) { 647 FAIL("Expected function"); 648 } 649 module_builder_->AddExport(name, info->function_builder); 650 if (Check(',')) { 651 if (!Peek('}')) { 652 continue; 653 } 654 } 655 break; 656 } 657 EXPECT_TOKEN('}'); 658 } else { 659 if (!scanner_.IsGlobal()) { 660 FAIL("Single function export must be a function name"); 661 } 662 VarInfo* info = GetVarInfo(Consume()); 663 if (info->kind != VarKind::kFunction) { 664 FAIL("Single function export must be a function"); 665 } 666 module_builder_->AddExport(base::CStrVector(AsmJs::kSingleFunctionName), 667 info->function_builder); 668 } 669} 670 671// 6.3 ValidateFunctionTable 672void AsmJsParser::ValidateFunctionTable() { 673 EXPECT_TOKEN(TOK(var)); 674 if (!scanner_.IsGlobal()) { 675 FAIL("Expected table name"); 676 } 677 VarInfo* table_info = GetVarInfo(Consume()); 678 if (table_info->kind == VarKind::kTable) { 679 if (table_info->function_defined) { 680 FAIL("Function table redefined"); 681 } 682 table_info->function_defined = true; 683 } else if (table_info->kind != VarKind::kUnused) { 684 FAIL("Function table name collides"); 685 } 686 EXPECT_TOKEN('='); 687 EXPECT_TOKEN('['); 688 uint64_t count = 0; 689 for (;;) { 690 if (!scanner_.IsGlobal()) { 691 FAIL("Expected function name"); 692 } 693 VarInfo* info = GetVarInfo(Consume()); 694 if (info->kind != VarKind::kFunction) { 695 FAIL("Expected function"); 696 } 697 // Only store the function into a table if we used the table somewhere 698 // (i.e. tables are first seen at their use sites and allocated there). 699 if (table_info->kind == VarKind::kTable) { 700 if (count >= static_cast<uint64_t>(table_info->mask) + 1) { 701 FAIL("Exceeded function table size"); 702 } 703 if (!info->type->IsA(table_info->type)) { 704 FAIL("Function table definition doesn't match use"); 705 } 706 module_builder_->SetIndirectFunction( 707 0, static_cast<uint32_t>(table_info->index + count), info->index, 708 WasmModuleBuilder::WasmElemSegment::kRelativeToDeclaredFunctions); 709 } 710 ++count; 711 if (Check(',')) { 712 if (!Peek(']')) { 713 continue; 714 } 715 } 716 break; 717 } 718 EXPECT_TOKEN(']'); 719 if (table_info->kind == VarKind::kTable && 720 count != static_cast<uint64_t>(table_info->mask) + 1) { 721 FAIL("Function table size does not match uses"); 722 } 723 SkipSemicolon(); 724} 725 726// 6.4 ValidateFunction 727void AsmJsParser::ValidateFunction() { 728 // Remember position of the 'function' token as start position. 729 size_t function_start_position = scanner_.Position(); 730 731 EXPECT_TOKEN(TOK(function)); 732 if (!scanner_.IsGlobal()) { 733 FAIL("Expected function name"); 734 } 735 736 base::Vector<const char> function_name_str = CopyCurrentIdentifierString(); 737 AsmJsScanner::token_t function_name = Consume(); 738 VarInfo* function_info = GetVarInfo(function_name); 739 if (function_info->kind == VarKind::kUnused) { 740 function_info->kind = VarKind::kFunction; 741 function_info->function_builder = module_builder_->AddFunction(); 742 function_info->index = function_info->function_builder->func_index(); 743 function_info->mutable_variable = false; 744 } else if (function_info->kind != VarKind::kFunction) { 745 FAIL("Function name collides with variable"); 746 } else if (function_info->function_defined) { 747 FAIL("Function redefined"); 748 } 749 750 function_info->function_defined = true; 751 function_info->function_builder->SetName(function_name_str); 752 current_function_builder_ = function_info->function_builder; 753 return_type_ = nullptr; 754 755 // Record start of the function, used as position for the stack check. 756 current_function_builder_->SetAsmFunctionStartPosition( 757 function_start_position); 758 759 CachedVector<AsmType*> params(&cached_asm_type_p_vectors_); 760 ValidateFunctionParams(¶ms); 761 762 // Check against limit on number of parameters. 763 if (params.size() > kV8MaxWasmFunctionParams) { 764 FAIL("Number of parameters exceeds internal limit"); 765 } 766 767 CachedVector<ValueType> locals(&cached_valuetype_vectors_); 768 ValidateFunctionLocals(params.size(), &locals); 769 770 function_temp_locals_offset_ = static_cast<uint32_t>( 771 params.size() + locals.size()); 772 function_temp_locals_used_ = 0; 773 function_temp_locals_depth_ = 0; 774 775 bool last_statement_is_return = false; 776 while (!failed_ && !Peek('}')) { 777 // clang-format off 778 last_statement_is_return = Peek(TOK(return)); 779 // clang-format on 780 RECURSE(ValidateStatement()); 781 } 782 783 size_t function_end_position = scanner_.Position() + 1; 784 785 EXPECT_TOKEN('}'); 786 787 if (!last_statement_is_return) { 788 if (return_type_ == nullptr) { 789 return_type_ = AsmType::Void(); 790 } else if (!return_type_->IsA(AsmType::Void())) { 791 FAIL("Expected return at end of non-void function"); 792 } 793 } 794 DCHECK_NOT_NULL(return_type_); 795 796 // TODO(bradnelson): WasmModuleBuilder can't take this in the right order. 797 // We should fix that so we can use it instead. 798 FunctionSig* sig = ConvertSignature(return_type_, params); 799 current_function_builder_->SetSignature(sig); 800 for (auto local : locals) { 801 current_function_builder_->AddLocal(local); 802 } 803 // Add bonus temps. 804 for (int i = 0; i < function_temp_locals_used_; ++i) { 805 current_function_builder_->AddLocal(kWasmI32); 806 } 807 808 // Check against limit on number of local variables. 809 if (locals.size() + function_temp_locals_used_ > kV8MaxWasmFunctionLocals) { 810 FAIL("Number of local variables exceeds internal limit"); 811 } 812 813 // End function 814 current_function_builder_->Emit(kExprEnd); 815 816 // Emit function end position as the last position for this function. 817 current_function_builder_->AddAsmWasmOffset(function_end_position, 818 function_end_position); 819 820 if (current_function_builder_->GetPosition() > kV8MaxWasmFunctionSize) { 821 FAIL("Size of function body exceeds internal limit"); 822 } 823 // Record (or validate) function type. 824 AsmType* function_type = AsmType::Function(zone(), return_type_); 825 for (auto t : params) { 826 function_type->AsFunctionType()->AddArgument(t); 827 } 828 function_info = GetVarInfo(function_name); 829 if (function_info->type->IsA(AsmType::None())) { 830 DCHECK_EQ(function_info->kind, VarKind::kFunction); 831 function_info->type = function_type; 832 } else if (!function_type->IsA(function_info->type)) { 833 // TODO(bradnelson): Should IsExactly be used here? 834 FAIL("Function definition doesn't match use"); 835 } 836 837 scanner_.ResetLocals(); 838 std::fill(local_var_info_.begin(), local_var_info_.end(), VarInfo{}); 839} 840 841// 6.4 ValidateFunction 842void AsmJsParser::ValidateFunctionParams(ZoneVector<AsmType*>* params) { 843 // TODO(bradnelson): Do this differently so that the scanner doesn't need to 844 // have a state transition that needs knowledge of how the scanner works 845 // inside. 846 scanner_.EnterLocalScope(); 847 EXPECT_TOKEN('('); 848 CachedVector<AsmJsScanner::token_t> function_parameters( 849 &cached_token_t_vectors_); 850 while (!failed_ && !Peek(')')) { 851 if (!scanner_.IsLocal()) { 852 FAIL("Expected parameter name"); 853 } 854 function_parameters.push_back(Consume()); 855 if (!Peek(')')) { 856 EXPECT_TOKEN(','); 857 } 858 } 859 EXPECT_TOKEN(')'); 860 scanner_.EnterGlobalScope(); 861 EXPECT_TOKEN('{'); 862 // 5.1 Parameter Type Annotations 863 for (auto p : function_parameters) { 864 EXPECT_TOKEN(p); 865 EXPECT_TOKEN('='); 866 VarInfo* info = GetVarInfo(p); 867 if (info->kind != VarKind::kUnused) { 868 FAIL("Duplicate parameter name"); 869 } 870 if (Check(p)) { 871 EXPECT_TOKEN('|'); 872 if (!CheckForZero()) { 873 FAIL("Bad integer parameter annotation."); 874 } 875 info->kind = VarKind::kLocal; 876 info->type = AsmType::Int(); 877 info->index = static_cast<uint32_t>(params->size()); 878 params->push_back(AsmType::Int()); 879 } else if (Check('+')) { 880 EXPECT_TOKEN(p); 881 info->kind = VarKind::kLocal; 882 info->type = AsmType::Double(); 883 info->index = static_cast<uint32_t>(params->size()); 884 params->push_back(AsmType::Double()); 885 } else { 886 if (!scanner_.IsGlobal() || 887 !GetVarInfo(Consume())->type->IsA(stdlib_fround_)) { 888 FAIL("Expected fround"); 889 } 890 EXPECT_TOKEN('('); 891 EXPECT_TOKEN(p); 892 EXPECT_TOKEN(')'); 893 info->kind = VarKind::kLocal; 894 info->type = AsmType::Float(); 895 info->index = static_cast<uint32_t>(params->size()); 896 params->push_back(AsmType::Float()); 897 } 898 SkipSemicolon(); 899 } 900} 901 902// 6.4 ValidateFunction - locals 903void AsmJsParser::ValidateFunctionLocals(size_t param_count, 904 ZoneVector<ValueType>* locals) { 905 DCHECK(locals->empty()); 906 // Local Variables. 907 while (Peek(TOK(var))) { 908 scanner_.EnterLocalScope(); 909 EXPECT_TOKEN(TOK(var)); 910 scanner_.EnterGlobalScope(); 911 for (;;) { 912 if (!scanner_.IsLocal()) { 913 FAIL("Expected local variable identifier"); 914 } 915 VarInfo* info = GetVarInfo(Consume()); 916 if (info->kind != VarKind::kUnused) { 917 FAIL("Duplicate local variable name"); 918 } 919 // Store types. 920 EXPECT_TOKEN('='); 921 double dvalue = 0.0; 922 uint32_t uvalue = 0; 923 if (Check('-')) { 924 if (CheckForDouble(&dvalue)) { 925 info->kind = VarKind::kLocal; 926 info->type = AsmType::Double(); 927 info->index = static_cast<uint32_t>(param_count + locals->size()); 928 locals->push_back(kWasmF64); 929 current_function_builder_->EmitF64Const(-dvalue); 930 current_function_builder_->EmitSetLocal(info->index); 931 } else if (CheckForUnsigned(&uvalue)) { 932 if (uvalue > 0x7FFFFFFF) { 933 FAIL("Numeric literal out of range"); 934 } 935 info->kind = VarKind::kLocal; 936 info->type = AsmType::Int(); 937 info->index = static_cast<uint32_t>(param_count + locals->size()); 938 locals->push_back(kWasmI32); 939 int32_t value = -static_cast<int32_t>(uvalue); 940 current_function_builder_->EmitI32Const(value); 941 current_function_builder_->EmitSetLocal(info->index); 942 } else { 943 FAIL("Expected variable initial value"); 944 } 945 } else if (scanner_.IsGlobal()) { 946 VarInfo* sinfo = GetVarInfo(Consume()); 947 if (sinfo->kind == VarKind::kGlobal) { 948 if (sinfo->mutable_variable) { 949 FAIL("Initializing from global requires const variable"); 950 } 951 info->kind = VarKind::kLocal; 952 info->type = sinfo->type; 953 info->index = static_cast<uint32_t>(param_count + locals->size()); 954 if (sinfo->type->IsA(AsmType::Int())) { 955 locals->push_back(kWasmI32); 956 } else if (sinfo->type->IsA(AsmType::Float())) { 957 locals->push_back(kWasmF32); 958 } else if (sinfo->type->IsA(AsmType::Double())) { 959 locals->push_back(kWasmF64); 960 } else { 961 FAIL("Bad local variable definition"); 962 } 963 current_function_builder_->EmitWithI32V(kExprGlobalGet, 964 VarIndex(sinfo)); 965 current_function_builder_->EmitSetLocal(info->index); 966 } else if (sinfo->type->IsA(stdlib_fround_)) { 967 EXPECT_TOKEN('('); 968 bool negate = false; 969 if (Check('-')) { 970 negate = true; 971 } 972 if (CheckForDouble(&dvalue)) { 973 info->kind = VarKind::kLocal; 974 info->type = AsmType::Float(); 975 info->index = static_cast<uint32_t>(param_count + locals->size()); 976 locals->push_back(kWasmF32); 977 if (negate) { 978 dvalue = -dvalue; 979 } 980 float fvalue = DoubleToFloat32(dvalue); 981 current_function_builder_->EmitF32Const(fvalue); 982 current_function_builder_->EmitSetLocal(info->index); 983 } else if (CheckForUnsigned(&uvalue)) { 984 if (uvalue > 0x7FFFFFFF) { 985 FAIL("Numeric literal out of range"); 986 } 987 info->kind = VarKind::kLocal; 988 info->type = AsmType::Float(); 989 info->index = static_cast<uint32_t>(param_count + locals->size()); 990 locals->push_back(kWasmF32); 991 int32_t value = static_cast<int32_t>(uvalue); 992 if (negate) { 993 value = -value; 994 } 995 float fvalue = static_cast<float>(value); 996 current_function_builder_->EmitF32Const(fvalue); 997 current_function_builder_->EmitSetLocal(info->index); 998 } else { 999 FAIL("Expected variable initial value"); 1000 } 1001 EXPECT_TOKEN(')'); 1002 } else { 1003 FAIL("expected fround or const global"); 1004 } 1005 } else if (CheckForDouble(&dvalue)) { 1006 info->kind = VarKind::kLocal; 1007 info->type = AsmType::Double(); 1008 info->index = static_cast<uint32_t>(param_count + locals->size()); 1009 locals->push_back(kWasmF64); 1010 current_function_builder_->EmitF64Const(dvalue); 1011 current_function_builder_->EmitSetLocal(info->index); 1012 } else if (CheckForUnsigned(&uvalue)) { 1013 info->kind = VarKind::kLocal; 1014 info->type = AsmType::Int(); 1015 info->index = static_cast<uint32_t>(param_count + locals->size()); 1016 locals->push_back(kWasmI32); 1017 int32_t value = static_cast<int32_t>(uvalue); 1018 current_function_builder_->EmitI32Const(value); 1019 current_function_builder_->EmitSetLocal(info->index); 1020 } else { 1021 FAIL("Expected variable initial value"); 1022 } 1023 if (!Peek(',')) { 1024 break; 1025 } 1026 scanner_.EnterLocalScope(); 1027 EXPECT_TOKEN(','); 1028 scanner_.EnterGlobalScope(); 1029 } 1030 SkipSemicolon(); 1031 } 1032} 1033 1034// 6.5 ValidateStatement 1035void AsmJsParser::ValidateStatement() { 1036 call_coercion_ = nullptr; 1037 if (Peek('{')) { 1038 RECURSE(Block()); 1039 } else if (Peek(';')) { 1040 RECURSE(EmptyStatement()); 1041 } else if (Peek(TOK(if))) { 1042 RECURSE(IfStatement()); 1043 // clang-format off 1044 } else if (Peek(TOK(return))) { 1045 // clang-format on 1046 RECURSE(ReturnStatement()); 1047 } else if (IterationStatement()) { 1048 // Handled in IterationStatement. 1049 } else if (Peek(TOK(break))) { 1050 RECURSE(BreakStatement()); 1051 } else if (Peek(TOK(continue))) { 1052 RECURSE(ContinueStatement()); 1053 } else if (Peek(TOK(switch))) { 1054 RECURSE(SwitchStatement()); 1055 } else { 1056 RECURSE(ExpressionStatement()); 1057 } 1058} 1059 1060// 6.5.1 Block 1061void AsmJsParser::Block() { 1062 bool can_break_to_block = pending_label_ != 0; 1063 if (can_break_to_block) { 1064 BareBegin(BlockKind::kNamed, pending_label_); 1065 current_function_builder_->EmitWithU8(kExprBlock, kVoidCode); 1066 } 1067 pending_label_ = 0; 1068 EXPECT_TOKEN('{'); 1069 while (!failed_ && !Peek('}')) { 1070 RECURSE(ValidateStatement()); 1071 } 1072 EXPECT_TOKEN('}'); 1073 if (can_break_to_block) { 1074 End(); 1075 } 1076} 1077 1078// 6.5.2 ExpressionStatement 1079void AsmJsParser::ExpressionStatement() { 1080 if (scanner_.IsGlobal() || scanner_.IsLocal()) { 1081 // NOTE: Both global or local identifiers can also be used as labels. 1082 scanner_.Next(); 1083 if (Peek(':')) { 1084 scanner_.Rewind(); 1085 RECURSE(LabelledStatement()); 1086 return; 1087 } 1088 scanner_.Rewind(); 1089 } 1090 AsmType* ret; 1091 RECURSE(ret = ValidateExpression()); 1092 if (!ret->IsA(AsmType::Void())) { 1093 current_function_builder_->Emit(kExprDrop); 1094 } 1095 SkipSemicolon(); 1096} 1097 1098// 6.5.3 EmptyStatement 1099void AsmJsParser::EmptyStatement() { EXPECT_TOKEN(';'); } 1100 1101// 6.5.4 IfStatement 1102void AsmJsParser::IfStatement() { 1103 EXPECT_TOKEN(TOK(if)); 1104 EXPECT_TOKEN('('); 1105 RECURSE(Expression(AsmType::Int())); 1106 EXPECT_TOKEN(')'); 1107 BareBegin(BlockKind::kOther); 1108 current_function_builder_->EmitWithU8(kExprIf, kVoidCode); 1109 RECURSE(ValidateStatement()); 1110 if (Check(TOK(else))) { 1111 current_function_builder_->Emit(kExprElse); 1112 RECURSE(ValidateStatement()); 1113 } 1114 current_function_builder_->Emit(kExprEnd); 1115 BareEnd(); 1116} 1117 1118// 6.5.5 ReturnStatement 1119void AsmJsParser::ReturnStatement() { 1120 // clang-format off 1121 EXPECT_TOKEN(TOK(return)); 1122 // clang-format on 1123 if (!Peek(';') && !Peek('}')) { 1124 // TODO(bradnelson): See if this can be factored out. 1125 AsmType* ret; 1126 RECURSE(ret = Expression(return_type_)); 1127 if (ret->IsA(AsmType::Double())) { 1128 return_type_ = AsmType::Double(); 1129 } else if (ret->IsA(AsmType::Float())) { 1130 return_type_ = AsmType::Float(); 1131 } else if (ret->IsA(AsmType::Signed())) { 1132 return_type_ = AsmType::Signed(); 1133 } else { 1134 FAIL("Invalid return type"); 1135 } 1136 } else if (return_type_ == nullptr) { 1137 return_type_ = AsmType::Void(); 1138 } else if (!return_type_->IsA(AsmType::Void())) { 1139 FAIL("Invalid void return type"); 1140 } 1141 current_function_builder_->Emit(kExprReturn); 1142 SkipSemicolon(); 1143} 1144 1145// 6.5.6 IterationStatement 1146bool AsmJsParser::IterationStatement() { 1147 if (Peek(TOK(while))) { 1148 WhileStatement(); 1149 } else if (Peek(TOK(do))) { 1150 DoStatement(); 1151 } else if (Peek(TOK(for))) { 1152 ForStatement(); 1153 } else { 1154 return false; 1155 } 1156 return true; 1157} 1158 1159// 6.5.6 IterationStatement - while 1160void AsmJsParser::WhileStatement() { 1161 // a: block { 1162 Begin(pending_label_); 1163 // b: loop { 1164 Loop(pending_label_); 1165 pending_label_ = 0; 1166 EXPECT_TOKEN(TOK(while)); 1167 EXPECT_TOKEN('('); 1168 RECURSE(Expression(AsmType::Int())); 1169 EXPECT_TOKEN(')'); 1170 // if (!CONDITION) break a; 1171 current_function_builder_->Emit(kExprI32Eqz); 1172 current_function_builder_->EmitWithU8(kExprBrIf, 1); 1173 // BODY 1174 RECURSE(ValidateStatement()); 1175 // continue b; 1176 current_function_builder_->EmitWithU8(kExprBr, 0); 1177 End(); 1178 // } 1179 // } 1180 End(); 1181} 1182 1183// 6.5.6 IterationStatement - do 1184void AsmJsParser::DoStatement() { 1185 // a: block { 1186 Begin(pending_label_); 1187 // b: loop { 1188 Loop(); 1189 // c: block { // but treated like loop so continue works 1190 BareBegin(BlockKind::kLoop, pending_label_); 1191 current_function_builder_->EmitWithU8(kExprBlock, kVoidCode); 1192 pending_label_ = 0; 1193 EXPECT_TOKEN(TOK(do)); 1194 // BODY 1195 RECURSE(ValidateStatement()); 1196 EXPECT_TOKEN(TOK(while)); 1197 End(); 1198 // } // end c 1199 EXPECT_TOKEN('('); 1200 RECURSE(Expression(AsmType::Int())); 1201 // if (!CONDITION) break a; 1202 current_function_builder_->Emit(kExprI32Eqz); 1203 current_function_builder_->EmitWithU8(kExprBrIf, 1); 1204 // continue b; 1205 current_function_builder_->EmitWithU8(kExprBr, 0); 1206 EXPECT_TOKEN(')'); 1207 // } // end b 1208 End(); 1209 // } // end a 1210 End(); 1211 SkipSemicolon(); 1212} 1213 1214// 6.5.6 IterationStatement - for 1215void AsmJsParser::ForStatement() { 1216 EXPECT_TOKEN(TOK(for)); 1217 EXPECT_TOKEN('('); 1218 if (!Peek(';')) { 1219 AsmType* ret; 1220 RECURSE(ret = Expression(nullptr)); 1221 if (!ret->IsA(AsmType::Void())) { 1222 current_function_builder_->Emit(kExprDrop); 1223 } 1224 } 1225 EXPECT_TOKEN(';'); 1226 // a: block { 1227 Begin(pending_label_); 1228 // b: loop { 1229 Loop(); 1230 // c: block { // but treated like loop so continue works 1231 BareBegin(BlockKind::kLoop, pending_label_); 1232 current_function_builder_->EmitWithU8(kExprBlock, kVoidCode); 1233 pending_label_ = 0; 1234 if (!Peek(';')) { 1235 // if (!CONDITION) break a; 1236 RECURSE(Expression(AsmType::Int())); 1237 current_function_builder_->Emit(kExprI32Eqz); 1238 current_function_builder_->EmitWithU8(kExprBrIf, 2); 1239 } 1240 EXPECT_TOKEN(';'); 1241 // Race past INCREMENT 1242 size_t increment_position = scanner_.Position(); 1243 ScanToClosingParenthesis(); 1244 EXPECT_TOKEN(')'); 1245 // BODY 1246 RECURSE(ValidateStatement()); 1247 // } // end c 1248 End(); 1249 // INCREMENT 1250 size_t end_position = scanner_.Position(); 1251 scanner_.Seek(increment_position); 1252 if (!Peek(')')) { 1253 RECURSE(Expression(nullptr)); 1254 // NOTE: No explicit drop because below break is an implicit drop. 1255 } 1256 // continue b; 1257 current_function_builder_->EmitWithU8(kExprBr, 0); 1258 scanner_.Seek(end_position); 1259 // } // end b 1260 End(); 1261 // } // end a 1262 End(); 1263} 1264 1265// 6.5.7 BreakStatement 1266void AsmJsParser::BreakStatement() { 1267 EXPECT_TOKEN(TOK(break)); 1268 AsmJsScanner::token_t label_name = kTokenNone; 1269 if (scanner_.IsGlobal() || scanner_.IsLocal()) { 1270 // NOTE: Currently using globals/locals for labels too. 1271 label_name = Consume(); 1272 } 1273 int depth = FindBreakLabelDepth(label_name); 1274 if (depth < 0) { 1275 FAIL("Illegal break"); 1276 } 1277 current_function_builder_->Emit(kExprBr); 1278 current_function_builder_->EmitI32V(depth); 1279 SkipSemicolon(); 1280} 1281 1282// 6.5.8 ContinueStatement 1283void AsmJsParser::ContinueStatement() { 1284 EXPECT_TOKEN(TOK(continue)); 1285 AsmJsScanner::token_t label_name = kTokenNone; 1286 if (scanner_.IsGlobal() || scanner_.IsLocal()) { 1287 // NOTE: Currently using globals/locals for labels too. 1288 label_name = Consume(); 1289 } 1290 int depth = FindContinueLabelDepth(label_name); 1291 if (depth < 0) { 1292 FAIL("Illegal continue"); 1293 } 1294 current_function_builder_->EmitWithI32V(kExprBr, depth); 1295 SkipSemicolon(); 1296} 1297 1298// 6.5.9 LabelledStatement 1299void AsmJsParser::LabelledStatement() { 1300 DCHECK(scanner_.IsGlobal() || scanner_.IsLocal()); 1301 // NOTE: Currently using globals/locals for labels too. 1302 if (pending_label_ != 0) { 1303 FAIL("Double label unsupported"); 1304 } 1305 pending_label_ = scanner_.Token(); 1306 scanner_.Next(); 1307 EXPECT_TOKEN(':'); 1308 RECURSE(ValidateStatement()); 1309} 1310 1311// 6.5.10 SwitchStatement 1312void AsmJsParser::SwitchStatement() { 1313 EXPECT_TOKEN(TOK(switch)); 1314 EXPECT_TOKEN('('); 1315 AsmType* test; 1316 RECURSE(test = Expression(nullptr)); 1317 if (!test->IsA(AsmType::Signed())) { 1318 FAIL("Expected signed for switch value"); 1319 } 1320 EXPECT_TOKEN(')'); 1321 uint32_t tmp = TempVariable(0); 1322 current_function_builder_->EmitSetLocal(tmp); 1323 Begin(pending_label_); 1324 pending_label_ = 0; 1325 // TODO(bradnelson): Make less weird. 1326 CachedVector<int32_t> cases(&cached_int_vectors_); 1327 GatherCases(&cases); 1328 EXPECT_TOKEN('{'); 1329 size_t count = cases.size() + 1; 1330 for (size_t i = 0; i < count; ++i) { 1331 BareBegin(BlockKind::kOther); 1332 current_function_builder_->EmitWithU8(kExprBlock, kVoidCode); 1333 } 1334 int table_pos = 0; 1335 for (auto c : cases) { 1336 current_function_builder_->EmitGetLocal(tmp); 1337 current_function_builder_->EmitI32Const(c); 1338 current_function_builder_->Emit(kExprI32Eq); 1339 current_function_builder_->EmitWithI32V(kExprBrIf, table_pos++); 1340 } 1341 current_function_builder_->EmitWithI32V(kExprBr, table_pos++); 1342 while (!failed_ && Peek(TOK(case))) { 1343 current_function_builder_->Emit(kExprEnd); 1344 BareEnd(); 1345 RECURSE(ValidateCase()); 1346 } 1347 current_function_builder_->Emit(kExprEnd); 1348 BareEnd(); 1349 if (Peek(TOK(default))) { 1350 RECURSE(ValidateDefault()); 1351 } 1352 EXPECT_TOKEN('}'); 1353 End(); 1354} 1355 1356// 6.6. ValidateCase 1357void AsmJsParser::ValidateCase() { 1358 EXPECT_TOKEN(TOK(case)); 1359 bool negate = false; 1360 if (Check('-')) { 1361 negate = true; 1362 } 1363 uint32_t uvalue; 1364 if (!CheckForUnsigned(&uvalue)) { 1365 FAIL("Expected numeric literal"); 1366 } 1367 // TODO(bradnelson): Share negation plumbing. 1368 if ((negate && uvalue > 0x80000000) || (!negate && uvalue > 0x7FFFFFFF)) { 1369 FAIL("Numeric literal out of range"); 1370 } 1371 int32_t value = static_cast<int32_t>(uvalue); 1372 DCHECK_IMPLIES(negate && uvalue == 0x80000000, value == kMinInt); 1373 if (negate && value != kMinInt) { 1374 value = -value; 1375 } 1376 EXPECT_TOKEN(':'); 1377 while (!failed_ && !Peek('}') && !Peek(TOK(case)) && !Peek(TOK(default))) { 1378 RECURSE(ValidateStatement()); 1379 } 1380} 1381 1382// 6.7 ValidateDefault 1383void AsmJsParser::ValidateDefault() { 1384 EXPECT_TOKEN(TOK(default)); 1385 EXPECT_TOKEN(':'); 1386 while (!failed_ && !Peek('}')) { 1387 RECURSE(ValidateStatement()); 1388 } 1389} 1390 1391// 6.8 ValidateExpression 1392AsmType* AsmJsParser::ValidateExpression() { 1393 AsmType* ret; 1394 RECURSEn(ret = Expression(nullptr)); 1395 return ret; 1396} 1397 1398// 6.8.1 Expression 1399AsmType* AsmJsParser::Expression(AsmType* expected) { 1400 AsmType* a; 1401 for (;;) { 1402 RECURSEn(a = AssignmentExpression()); 1403 if (Peek(',')) { 1404 if (a->IsA(AsmType::None())) { 1405 FAILn("Expected actual type"); 1406 } 1407 if (!a->IsA(AsmType::Void())) { 1408 current_function_builder_->Emit(kExprDrop); 1409 } 1410 EXPECT_TOKENn(','); 1411 continue; 1412 } 1413 break; 1414 } 1415 if (expected != nullptr && !a->IsA(expected)) { 1416 FAILn("Unexpected type"); 1417 } 1418 return a; 1419} 1420 1421// 6.8.2 NumericLiteral 1422AsmType* AsmJsParser::NumericLiteral() { 1423 call_coercion_ = nullptr; 1424 double dvalue = 0.0; 1425 uint32_t uvalue = 0; 1426 if (CheckForDouble(&dvalue)) { 1427 current_function_builder_->EmitF64Const(dvalue); 1428 return AsmType::Double(); 1429 } else if (CheckForUnsigned(&uvalue)) { 1430 if (uvalue <= 0x7FFFFFFF) { 1431 current_function_builder_->EmitI32Const(static_cast<int32_t>(uvalue)); 1432 return AsmType::FixNum(); 1433 } else { 1434 current_function_builder_->EmitI32Const(static_cast<int32_t>(uvalue)); 1435 return AsmType::Unsigned(); 1436 } 1437 } else { 1438 FAILn("Expected numeric literal."); 1439 } 1440} 1441 1442// 6.8.3 Identifier 1443AsmType* AsmJsParser::Identifier() { 1444 call_coercion_ = nullptr; 1445 if (scanner_.IsLocal()) { 1446 VarInfo* info = GetVarInfo(Consume()); 1447 if (info->kind != VarKind::kLocal) { 1448 FAILn("Undefined local variable"); 1449 } 1450 current_function_builder_->EmitGetLocal(info->index); 1451 return info->type; 1452 } else if (scanner_.IsGlobal()) { 1453 VarInfo* info = GetVarInfo(Consume()); 1454 if (info->kind != VarKind::kGlobal) { 1455 FAILn("Undefined global variable"); 1456 } 1457 current_function_builder_->EmitWithI32V(kExprGlobalGet, VarIndex(info)); 1458 return info->type; 1459 } 1460 UNREACHABLE(); 1461} 1462 1463// 6.8.4 CallExpression 1464AsmType* AsmJsParser::CallExpression() { 1465 AsmType* ret; 1466 if (scanner_.IsGlobal() && 1467 GetVarInfo(scanner_.Token())->type->IsA(stdlib_fround_)) { 1468 ValidateFloatCoercion(); 1469 return AsmType::Float(); 1470 } else if (scanner_.IsGlobal() && 1471 GetVarInfo(scanner_.Token())->type->IsA(AsmType::Heap())) { 1472 RECURSEn(ret = MemberExpression()); 1473 } else if (Peek('(')) { 1474 RECURSEn(ret = ParenthesizedExpression()); 1475 } else if (PeekCall()) { 1476 RECURSEn(ret = ValidateCall()); 1477 } else if (scanner_.IsLocal() || scanner_.IsGlobal()) { 1478 RECURSEn(ret = Identifier()); 1479 } else { 1480 RECURSEn(ret = NumericLiteral()); 1481 } 1482 return ret; 1483} 1484 1485// 6.8.5 MemberExpression 1486AsmType* AsmJsParser::MemberExpression() { 1487 call_coercion_ = nullptr; 1488 RECURSEn(ValidateHeapAccess()); 1489 DCHECK_NOT_NULL(heap_access_type_); 1490 if (Peek('=')) { 1491 inside_heap_assignment_ = true; 1492 return heap_access_type_->StoreType(); 1493 } else { 1494#define V(array_type, wasmload, wasmstore, type) \ 1495 if (heap_access_type_->IsA(AsmType::array_type())) { \ 1496 current_function_builder_->Emit(kExpr##type##AsmjsLoad##wasmload); \ 1497 return heap_access_type_->LoadType(); \ 1498 } 1499 STDLIB_ARRAY_TYPE_LIST(V) 1500#undef V 1501 FAILn("Expected valid heap load"); 1502 } 1503} 1504 1505// 6.8.6 AssignmentExpression 1506AsmType* AsmJsParser::AssignmentExpression() { 1507 AsmType* ret; 1508 if (scanner_.IsGlobal() && 1509 GetVarInfo(scanner_.Token())->type->IsA(AsmType::Heap())) { 1510 RECURSEn(ret = ConditionalExpression()); 1511 if (Peek('=')) { 1512 if (!inside_heap_assignment_) { 1513 FAILn("Invalid assignment target"); 1514 } 1515 inside_heap_assignment_ = false; 1516 DCHECK_NOT_NULL(heap_access_type_); 1517 AsmType* heap_type = heap_access_type_; 1518 EXPECT_TOKENn('='); 1519 AsmType* value; 1520 RECURSEn(value = AssignmentExpression()); 1521 if (!value->IsA(ret)) { 1522 FAILn("Illegal type stored to heap view"); 1523 } 1524 ret = value; 1525 if (heap_type->IsA(AsmType::Float32Array()) && 1526 value->IsA(AsmType::DoubleQ())) { 1527 // Assignment to a float32 heap can be used to convert doubles. 1528 current_function_builder_->Emit(kExprF32ConvertF64); 1529 ret = AsmType::FloatQ(); 1530 } 1531 if (heap_type->IsA(AsmType::Float64Array()) && 1532 value->IsA(AsmType::FloatQ())) { 1533 // Assignment to a float64 heap can be used to convert floats. 1534 current_function_builder_->Emit(kExprF64ConvertF32); 1535 ret = AsmType::DoubleQ(); 1536 } 1537#define V(array_type, wasmload, wasmstore, type) \ 1538 if (heap_type->IsA(AsmType::array_type())) { \ 1539 current_function_builder_->Emit(kExpr##type##AsmjsStore##wasmstore); \ 1540 return ret; \ 1541 } 1542 STDLIB_ARRAY_TYPE_LIST(V) 1543#undef V 1544 } 1545 } else if (scanner_.IsLocal() || scanner_.IsGlobal()) { 1546 bool is_local = scanner_.IsLocal(); 1547 VarInfo* info = GetVarInfo(scanner_.Token()); 1548 USE(is_local); 1549 ret = info->type; 1550 scanner_.Next(); 1551 if (Check('=')) { 1552 // NOTE: Before this point, this might have been VarKind::kUnused even in 1553 // valid code, as it might be a label. 1554 if (info->kind == VarKind::kUnused) { 1555 FAILn("Undeclared assignment target"); 1556 } 1557 if (!info->mutable_variable) { 1558 FAILn("Expected mutable variable in assignment"); 1559 } 1560 DCHECK(is_local ? info->kind == VarKind::kLocal 1561 : info->kind == VarKind::kGlobal); 1562 AsmType* value; 1563 RECURSEn(value = AssignmentExpression()); 1564 if (!value->IsA(ret)) { 1565 FAILn("Type mismatch in assignment"); 1566 } 1567 if (info->kind == VarKind::kLocal) { 1568 current_function_builder_->EmitTeeLocal(info->index); 1569 } else if (info->kind == VarKind::kGlobal) { 1570 current_function_builder_->EmitWithU32V(kExprGlobalSet, VarIndex(info)); 1571 current_function_builder_->EmitWithU32V(kExprGlobalGet, VarIndex(info)); 1572 } else { 1573 UNREACHABLE(); 1574 } 1575 return ret; 1576 } 1577 scanner_.Rewind(); 1578 RECURSEn(ret = ConditionalExpression()); 1579 } else { 1580 RECURSEn(ret = ConditionalExpression()); 1581 } 1582 return ret; 1583} 1584 1585// 6.8.7 UnaryExpression 1586AsmType* AsmJsParser::UnaryExpression() { 1587 AsmType* ret; 1588 if (Check('-')) { 1589 uint32_t uvalue; 1590 if (CheckForUnsigned(&uvalue)) { 1591 if (uvalue == 0) { 1592 current_function_builder_->EmitF64Const(-0.0); 1593 ret = AsmType::Double(); 1594 } else if (uvalue <= 0x80000000) { 1595 // TODO(bradnelson): was supposed to be 0x7FFFFFFF, check errata. 1596 current_function_builder_->EmitI32Const( 1597 base::NegateWithWraparound(static_cast<int32_t>(uvalue))); 1598 ret = AsmType::Signed(); 1599 } else { 1600 FAILn("Integer numeric literal out of range."); 1601 } 1602 } else { 1603 RECURSEn(ret = UnaryExpression()); 1604 if (ret->IsA(AsmType::Int())) { 1605 TemporaryVariableScope tmp(this); 1606 current_function_builder_->EmitSetLocal(tmp.get()); 1607 current_function_builder_->EmitI32Const(0); 1608 current_function_builder_->EmitGetLocal(tmp.get()); 1609 current_function_builder_->Emit(kExprI32Sub); 1610 ret = AsmType::Intish(); 1611 } else if (ret->IsA(AsmType::DoubleQ())) { 1612 current_function_builder_->Emit(kExprF64Neg); 1613 ret = AsmType::Double(); 1614 } else if (ret->IsA(AsmType::FloatQ())) { 1615 current_function_builder_->Emit(kExprF32Neg); 1616 ret = AsmType::Floatish(); 1617 } else { 1618 FAILn("expected int/double?/float?"); 1619 } 1620 } 1621 } else if (Peek('+')) { 1622 call_coercion_ = AsmType::Double(); 1623 call_coercion_position_ = scanner_.Position(); 1624 scanner_.Next(); // Done late for correct position. 1625 RECURSEn(ret = UnaryExpression()); 1626 // TODO(bradnelson): Generalize. 1627 if (ret->IsA(AsmType::Signed())) { 1628 current_function_builder_->Emit(kExprF64SConvertI32); 1629 ret = AsmType::Double(); 1630 } else if (ret->IsA(AsmType::Unsigned())) { 1631 current_function_builder_->Emit(kExprF64UConvertI32); 1632 ret = AsmType::Double(); 1633 } else if (ret->IsA(AsmType::DoubleQ())) { 1634 ret = AsmType::Double(); 1635 } else if (ret->IsA(AsmType::FloatQ())) { 1636 current_function_builder_->Emit(kExprF64ConvertF32); 1637 ret = AsmType::Double(); 1638 } else { 1639 FAILn("expected signed/unsigned/double?/float?"); 1640 } 1641 } else if (Check('!')) { 1642 RECURSEn(ret = UnaryExpression()); 1643 if (!ret->IsA(AsmType::Int())) { 1644 FAILn("expected int"); 1645 } 1646 current_function_builder_->Emit(kExprI32Eqz); 1647 } else if (Check('~')) { 1648 if (Check('~')) { 1649 RECURSEn(ret = UnaryExpression()); 1650 if (ret->IsA(AsmType::Double())) { 1651 current_function_builder_->Emit(kExprI32AsmjsSConvertF64); 1652 } else if (ret->IsA(AsmType::FloatQ())) { 1653 current_function_builder_->Emit(kExprI32AsmjsSConvertF32); 1654 } else { 1655 FAILn("expected double or float?"); 1656 } 1657 ret = AsmType::Signed(); 1658 } else { 1659 RECURSEn(ret = UnaryExpression()); 1660 if (!ret->IsA(AsmType::Intish())) { 1661 FAILn("operator ~ expects intish"); 1662 } 1663 current_function_builder_->EmitI32Const(0xFFFFFFFF); 1664 current_function_builder_->Emit(kExprI32Xor); 1665 ret = AsmType::Signed(); 1666 } 1667 } else { 1668 RECURSEn(ret = CallExpression()); 1669 } 1670 return ret; 1671} 1672 1673// 6.8.8 MultiplicativeExpression 1674AsmType* AsmJsParser::MultiplicativeExpression() { 1675 AsmType* a; 1676 uint32_t uvalue; 1677 if (CheckForUnsignedBelow(0x100000, &uvalue)) { 1678 if (Check('*')) { 1679 AsmType* type; 1680 RECURSEn(type = UnaryExpression()); 1681 if (!type->IsA(AsmType::Int())) { 1682 FAILn("Expected int"); 1683 } 1684 int32_t value = static_cast<int32_t>(uvalue); 1685 current_function_builder_->EmitI32Const(value); 1686 current_function_builder_->Emit(kExprI32Mul); 1687 return AsmType::Intish(); 1688 } else { 1689 scanner_.Rewind(); 1690 RECURSEn(a = UnaryExpression()); 1691 } 1692 } else if (Check('-')) { 1693 if (!PeekForZero() && CheckForUnsignedBelow(0x100000, &uvalue)) { 1694 int32_t value = -static_cast<int32_t>(uvalue); 1695 current_function_builder_->EmitI32Const(value); 1696 if (Check('*')) { 1697 AsmType* type; 1698 RECURSEn(type = UnaryExpression()); 1699 if (!type->IsA(AsmType::Int())) { 1700 FAILn("Expected int"); 1701 } 1702 current_function_builder_->Emit(kExprI32Mul); 1703 return AsmType::Intish(); 1704 } 1705 a = AsmType::Signed(); 1706 } else { 1707 scanner_.Rewind(); 1708 RECURSEn(a = UnaryExpression()); 1709 } 1710 } else { 1711 RECURSEn(a = UnaryExpression()); 1712 } 1713 for (;;) { 1714 if (Check('*')) { 1715 if (Check('-')) { 1716 if (!PeekForZero() && CheckForUnsigned(&uvalue)) { 1717 if (uvalue >= 0x100000) { 1718 FAILn("Constant multiple out of range"); 1719 } 1720 if (!a->IsA(AsmType::Int())) { 1721 FAILn("Integer multiply of expects int"); 1722 } 1723 int32_t value = -static_cast<int32_t>(uvalue); 1724 current_function_builder_->EmitI32Const(value); 1725 current_function_builder_->Emit(kExprI32Mul); 1726 return AsmType::Intish(); 1727 } 1728 scanner_.Rewind(); 1729 } else if (CheckForUnsigned(&uvalue)) { 1730 if (uvalue >= 0x100000) { 1731 FAILn("Constant multiple out of range"); 1732 } 1733 if (!a->IsA(AsmType::Int())) { 1734 FAILn("Integer multiply of expects int"); 1735 } 1736 int32_t value = static_cast<int32_t>(uvalue); 1737 current_function_builder_->EmitI32Const(value); 1738 current_function_builder_->Emit(kExprI32Mul); 1739 return AsmType::Intish(); 1740 } 1741 AsmType* b; 1742 RECURSEn(b = UnaryExpression()); 1743 if (a->IsA(AsmType::DoubleQ()) && b->IsA(AsmType::DoubleQ())) { 1744 current_function_builder_->Emit(kExprF64Mul); 1745 a = AsmType::Double(); 1746 } else if (a->IsA(AsmType::FloatQ()) && b->IsA(AsmType::FloatQ())) { 1747 current_function_builder_->Emit(kExprF32Mul); 1748 a = AsmType::Floatish(); 1749 } else { 1750 FAILn("expected doubles or floats"); 1751 } 1752 } else if (Check('/')) { 1753 AsmType* b; 1754 RECURSEn(b = UnaryExpression()); 1755 if (a->IsA(AsmType::DoubleQ()) && b->IsA(AsmType::DoubleQ())) { 1756 current_function_builder_->Emit(kExprF64Div); 1757 a = AsmType::Double(); 1758 } else if (a->IsA(AsmType::FloatQ()) && b->IsA(AsmType::FloatQ())) { 1759 current_function_builder_->Emit(kExprF32Div); 1760 a = AsmType::Floatish(); 1761 } else if (a->IsA(AsmType::Signed()) && b->IsA(AsmType::Signed())) { 1762 current_function_builder_->Emit(kExprI32AsmjsDivS); 1763 a = AsmType::Intish(); 1764 } else if (a->IsA(AsmType::Unsigned()) && b->IsA(AsmType::Unsigned())) { 1765 current_function_builder_->Emit(kExprI32AsmjsDivU); 1766 a = AsmType::Intish(); 1767 } else { 1768 FAILn("expected doubles or floats"); 1769 } 1770 } else if (Check('%')) { 1771 AsmType* b; 1772 RECURSEn(b = UnaryExpression()); 1773 if (a->IsA(AsmType::DoubleQ()) && b->IsA(AsmType::DoubleQ())) { 1774 current_function_builder_->Emit(kExprF64Mod); 1775 a = AsmType::Double(); 1776 } else if (a->IsA(AsmType::Signed()) && b->IsA(AsmType::Signed())) { 1777 current_function_builder_->Emit(kExprI32AsmjsRemS); 1778 a = AsmType::Intish(); 1779 } else if (a->IsA(AsmType::Unsigned()) && b->IsA(AsmType::Unsigned())) { 1780 current_function_builder_->Emit(kExprI32AsmjsRemU); 1781 a = AsmType::Intish(); 1782 } else { 1783 FAILn("expected doubles or floats"); 1784 } 1785 } else { 1786 break; 1787 } 1788 } 1789 return a; 1790} 1791 1792// 6.8.9 AdditiveExpression 1793AsmType* AsmJsParser::AdditiveExpression() { 1794 AsmType* a; 1795 RECURSEn(a = MultiplicativeExpression()); 1796 int n = 0; 1797 for (;;) { 1798 if (Check('+')) { 1799 AsmType* b; 1800 RECURSEn(b = MultiplicativeExpression()); 1801 if (a->IsA(AsmType::Double()) && b->IsA(AsmType::Double())) { 1802 current_function_builder_->Emit(kExprF64Add); 1803 a = AsmType::Double(); 1804 } else if (a->IsA(AsmType::FloatQ()) && b->IsA(AsmType::FloatQ())) { 1805 current_function_builder_->Emit(kExprF32Add); 1806 a = AsmType::Floatish(); 1807 } else if (a->IsA(AsmType::Int()) && b->IsA(AsmType::Int())) { 1808 current_function_builder_->Emit(kExprI32Add); 1809 a = AsmType::Intish(); 1810 n = 2; 1811 } else if (a->IsA(AsmType::Intish()) && b->IsA(AsmType::Intish())) { 1812 // TODO(bradnelson): b should really only be Int. 1813 // specialize intish to capture count. 1814 ++n; 1815 if (n > (1 << 20)) { 1816 FAILn("more than 2^20 additive values"); 1817 } 1818 current_function_builder_->Emit(kExprI32Add); 1819 } else { 1820 FAILn("illegal types for +"); 1821 } 1822 } else if (Check('-')) { 1823 AsmType* b; 1824 RECURSEn(b = MultiplicativeExpression()); 1825 if (a->IsA(AsmType::Double()) && b->IsA(AsmType::Double())) { 1826 current_function_builder_->Emit(kExprF64Sub); 1827 a = AsmType::Double(); 1828 } else if (a->IsA(AsmType::FloatQ()) && b->IsA(AsmType::FloatQ())) { 1829 current_function_builder_->Emit(kExprF32Sub); 1830 a = AsmType::Floatish(); 1831 } else if (a->IsA(AsmType::Int()) && b->IsA(AsmType::Int())) { 1832 current_function_builder_->Emit(kExprI32Sub); 1833 a = AsmType::Intish(); 1834 n = 2; 1835 } else if (a->IsA(AsmType::Intish()) && b->IsA(AsmType::Intish())) { 1836 // TODO(bradnelson): b should really only be Int. 1837 // specialize intish to capture count. 1838 ++n; 1839 if (n > (1 << 20)) { 1840 FAILn("more than 2^20 additive values"); 1841 } 1842 current_function_builder_->Emit(kExprI32Sub); 1843 } else { 1844 FAILn("illegal types for +"); 1845 } 1846 } else { 1847 break; 1848 } 1849 } 1850 return a; 1851} 1852 1853// 6.8.10 ShiftExpression 1854AsmType* AsmJsParser::ShiftExpression() { 1855 AsmType* a = nullptr; 1856 RECURSEn(a = AdditiveExpression()); 1857 heap_access_shift_position_ = kNoHeapAccessShift; 1858 // TODO(bradnelson): Implement backtracking to avoid emitting code 1859 // for the x >>> 0 case (similar to what's there for |0). 1860 for (;;) { 1861 switch (scanner_.Token()) { 1862 case TOK(SAR): { 1863 EXPECT_TOKENn(TOK(SAR)); 1864 heap_access_shift_position_ = kNoHeapAccessShift; 1865 // Remember position allowing this shift-expression to be used as part 1866 // of a heap access operation expecting `a >> n:NumericLiteral`. 1867 bool imm = false; 1868 size_t old_pos; 1869 size_t old_code; 1870 uint32_t shift_imm; 1871 if (a->IsA(AsmType::Intish()) && CheckForUnsigned(&shift_imm)) { 1872 old_pos = scanner_.Position(); 1873 old_code = current_function_builder_->GetPosition(); 1874 scanner_.Rewind(); 1875 imm = true; 1876 } 1877 AsmType* b = nullptr; 1878 RECURSEn(b = AdditiveExpression()); 1879 // Check for `a >> n:NumericLiteral` pattern. 1880 if (imm && old_pos == scanner_.Position()) { 1881 heap_access_shift_position_ = old_code; 1882 heap_access_shift_value_ = shift_imm; 1883 } 1884 if (!(a->IsA(AsmType::Intish()) && b->IsA(AsmType::Intish()))) { 1885 FAILn("Expected intish for operator >>."); 1886 } 1887 current_function_builder_->Emit(kExprI32ShrS); 1888 a = AsmType::Signed(); 1889 continue; 1890 } 1891#define HANDLE_CASE(op, opcode, name, result) \ 1892 case TOK(op): { \ 1893 EXPECT_TOKENn(TOK(op)); \ 1894 heap_access_shift_position_ = kNoHeapAccessShift; \ 1895 AsmType* b = nullptr; \ 1896 RECURSEn(b = AdditiveExpression()); \ 1897 if (!(a->IsA(AsmType::Intish()) && b->IsA(AsmType::Intish()))) { \ 1898 FAILn("Expected intish for operator " #name "."); \ 1899 } \ 1900 current_function_builder_->Emit(kExpr##opcode); \ 1901 a = AsmType::result(); \ 1902 continue; \ 1903 } 1904 HANDLE_CASE(SHL, I32Shl, "<<", Signed); 1905 HANDLE_CASE(SHR, I32ShrU, ">>>", Unsigned); 1906#undef HANDLE_CASE 1907 default: 1908 return a; 1909 } 1910 } 1911} 1912 1913// 6.8.11 RelationalExpression 1914AsmType* AsmJsParser::RelationalExpression() { 1915 AsmType* a = nullptr; 1916 RECURSEn(a = ShiftExpression()); 1917 for (;;) { 1918 switch (scanner_.Token()) { 1919#define HANDLE_CASE(op, sop, uop, dop, fop, name) \ 1920 case op: { \ 1921 EXPECT_TOKENn(op); \ 1922 AsmType* b = nullptr; \ 1923 RECURSEn(b = ShiftExpression()); \ 1924 if (a->IsA(AsmType::Signed()) && b->IsA(AsmType::Signed())) { \ 1925 current_function_builder_->Emit(kExpr##sop); \ 1926 } else if (a->IsA(AsmType::Unsigned()) && b->IsA(AsmType::Unsigned())) { \ 1927 current_function_builder_->Emit(kExpr##uop); \ 1928 } else if (a->IsA(AsmType::Double()) && b->IsA(AsmType::Double())) { \ 1929 current_function_builder_->Emit(kExpr##dop); \ 1930 } else if (a->IsA(AsmType::Float()) && b->IsA(AsmType::Float())) { \ 1931 current_function_builder_->Emit(kExpr##fop); \ 1932 } else { \ 1933 FAILn("Expected signed, unsigned, double, or float for operator " #name \ 1934 "."); \ 1935 } \ 1936 a = AsmType::Int(); \ 1937 continue; \ 1938 } 1939 HANDLE_CASE('<', I32LtS, I32LtU, F64Lt, F32Lt, "<"); 1940 HANDLE_CASE(TOK(LE), I32LeS, I32LeU, F64Le, F32Le, "<="); 1941 HANDLE_CASE('>', I32GtS, I32GtU, F64Gt, F32Gt, ">"); 1942 HANDLE_CASE(TOK(GE), I32GeS, I32GeU, F64Ge, F32Ge, ">="); 1943#undef HANDLE_CASE 1944 default: 1945 return a; 1946 } 1947 } 1948} 1949 1950// 6.8.12 EqualityExpression 1951AsmType* AsmJsParser::EqualityExpression() { 1952 AsmType* a = nullptr; 1953 RECURSEn(a = RelationalExpression()); 1954 for (;;) { 1955 switch (scanner_.Token()) { 1956#define HANDLE_CASE(op, sop, uop, dop, fop, name) \ 1957 case op: { \ 1958 EXPECT_TOKENn(op); \ 1959 AsmType* b = nullptr; \ 1960 RECURSEn(b = RelationalExpression()); \ 1961 if (a->IsA(AsmType::Signed()) && b->IsA(AsmType::Signed())) { \ 1962 current_function_builder_->Emit(kExpr##sop); \ 1963 } else if (a->IsA(AsmType::Unsigned()) && b->IsA(AsmType::Unsigned())) { \ 1964 current_function_builder_->Emit(kExpr##uop); \ 1965 } else if (a->IsA(AsmType::Double()) && b->IsA(AsmType::Double())) { \ 1966 current_function_builder_->Emit(kExpr##dop); \ 1967 } else if (a->IsA(AsmType::Float()) && b->IsA(AsmType::Float())) { \ 1968 current_function_builder_->Emit(kExpr##fop); \ 1969 } else { \ 1970 FAILn("Expected signed, unsigned, double, or float for operator " #name \ 1971 "."); \ 1972 } \ 1973 a = AsmType::Int(); \ 1974 continue; \ 1975 } 1976 HANDLE_CASE(TOK(EQ), I32Eq, I32Eq, F64Eq, F32Eq, "=="); 1977 HANDLE_CASE(TOK(NE), I32Ne, I32Ne, F64Ne, F32Ne, "!="); 1978#undef HANDLE_CASE 1979 default: 1980 return a; 1981 } 1982 } 1983} 1984 1985// 6.8.13 BitwiseANDExpression 1986AsmType* AsmJsParser::BitwiseANDExpression() { 1987 AsmType* a = nullptr; 1988 RECURSEn(a = EqualityExpression()); 1989 while (Check('&')) { 1990 AsmType* b = nullptr; 1991 RECURSEn(b = EqualityExpression()); 1992 if (a->IsA(AsmType::Intish()) && b->IsA(AsmType::Intish())) { 1993 current_function_builder_->Emit(kExprI32And); 1994 a = AsmType::Signed(); 1995 } else { 1996 FAILn("Expected intish for operator &."); 1997 } 1998 } 1999 return a; 2000} 2001 2002// 6.8.14 BitwiseXORExpression 2003AsmType* AsmJsParser::BitwiseXORExpression() { 2004 AsmType* a = nullptr; 2005 RECURSEn(a = BitwiseANDExpression()); 2006 while (Check('^')) { 2007 AsmType* b = nullptr; 2008 RECURSEn(b = BitwiseANDExpression()); 2009 if (a->IsA(AsmType::Intish()) && b->IsA(AsmType::Intish())) { 2010 current_function_builder_->Emit(kExprI32Xor); 2011 a = AsmType::Signed(); 2012 } else { 2013 FAILn("Expected intish for operator &."); 2014 } 2015 } 2016 return a; 2017} 2018 2019// 6.8.15 BitwiseORExpression 2020AsmType* AsmJsParser::BitwiseORExpression() { 2021 AsmType* a = nullptr; 2022 call_coercion_deferred_position_ = scanner_.Position(); 2023 RECURSEn(a = BitwiseXORExpression()); 2024 while (Check('|')) { 2025 AsmType* b = nullptr; 2026 // Remember whether the first operand to this OR-expression has requested 2027 // deferred validation of the |0 annotation. 2028 // NOTE: This has to happen here to work recursively. 2029 bool requires_zero = 2030 AsmType::IsExactly(call_coercion_deferred_, AsmType::Signed()); 2031 call_coercion_deferred_ = nullptr; 2032 // TODO(bradnelson): Make it prettier. 2033 bool zero = false; 2034 size_t old_pos; 2035 size_t old_code; 2036 if (a->IsA(AsmType::Intish()) && CheckForZero()) { 2037 old_pos = scanner_.Position(); 2038 old_code = current_function_builder_->GetPosition(); 2039 scanner_.Rewind(); 2040 zero = true; 2041 } 2042 RECURSEn(b = BitwiseXORExpression()); 2043 // Handle |0 specially. 2044 if (zero && old_pos == scanner_.Position()) { 2045 current_function_builder_->DeleteCodeAfter(old_code); 2046 a = AsmType::Signed(); 2047 continue; 2048 } 2049 // Anything not matching |0 breaks the lookahead in {ValidateCall}. 2050 if (requires_zero) { 2051 FAILn("Expected |0 type annotation for call"); 2052 } 2053 if (a->IsA(AsmType::Intish()) && b->IsA(AsmType::Intish())) { 2054 current_function_builder_->Emit(kExprI32Ior); 2055 a = AsmType::Signed(); 2056 } else { 2057 FAILn("Expected intish for operator |."); 2058 } 2059 } 2060 DCHECK_NULL(call_coercion_deferred_); 2061 return a; 2062} 2063 2064// 6.8.16 ConditionalExpression 2065AsmType* AsmJsParser::ConditionalExpression() { 2066 AsmType* test = nullptr; 2067 RECURSEn(test = BitwiseORExpression()); 2068 if (Check('?')) { 2069 if (!test->IsA(AsmType::Int())) { 2070 FAILn("Expected int in condition of ternary operator."); 2071 } 2072 current_function_builder_->EmitWithU8(kExprIf, kI32Code); 2073 size_t fixup = current_function_builder_->GetPosition() - 2074 1; // Assumes encoding knowledge. 2075 AsmType* cons = nullptr; 2076 RECURSEn(cons = AssignmentExpression()); 2077 current_function_builder_->Emit(kExprElse); 2078 EXPECT_TOKENn(':'); 2079 AsmType* alt = nullptr; 2080 RECURSEn(alt = AssignmentExpression()); 2081 current_function_builder_->Emit(kExprEnd); 2082 if (cons->IsA(AsmType::Int()) && alt->IsA(AsmType::Int())) { 2083 current_function_builder_->FixupByte(fixup, kI32Code); 2084 return AsmType::Int(); 2085 } else if (cons->IsA(AsmType::Double()) && alt->IsA(AsmType::Double())) { 2086 current_function_builder_->FixupByte(fixup, kF64Code); 2087 return AsmType::Double(); 2088 } else if (cons->IsA(AsmType::Float()) && alt->IsA(AsmType::Float())) { 2089 current_function_builder_->FixupByte(fixup, kF32Code); 2090 return AsmType::Float(); 2091 } else { 2092 FAILn("Type mismatch in ternary operator."); 2093 } 2094 } else { 2095 return test; 2096 } 2097} 2098 2099// 6.8.17 ParenthesiedExpression 2100AsmType* AsmJsParser::ParenthesizedExpression() { 2101 call_coercion_ = nullptr; 2102 AsmType* ret; 2103 EXPECT_TOKENn('('); 2104 RECURSEn(ret = Expression(nullptr)); 2105 EXPECT_TOKENn(')'); 2106 return ret; 2107} 2108 2109// 6.9 ValidateCall 2110AsmType* AsmJsParser::ValidateCall() { 2111 AsmType* return_type = call_coercion_; 2112 call_coercion_ = nullptr; 2113 size_t call_pos = scanner_.Position(); 2114 size_t to_number_pos = call_coercion_position_; 2115 bool allow_peek = (call_coercion_deferred_position_ == scanner_.Position()); 2116 AsmJsScanner::token_t function_name = Consume(); 2117 2118 // Distinguish between ordinary function calls and function table calls. In 2119 // both cases we might be seeing the {function_name} for the first time and 2120 // hence allocate a {VarInfo} here, all subsequent uses of the same name then 2121 // need to match the information stored at this point. 2122 base::Optional<TemporaryVariableScope> tmp_scope; 2123 if (Check('[')) { 2124 AsmType* index = nullptr; 2125 RECURSEn(index = EqualityExpression()); 2126 if (!index->IsA(AsmType::Intish())) { 2127 FAILn("Expected intish index"); 2128 } 2129 EXPECT_TOKENn('&'); 2130 uint32_t mask = 0; 2131 if (!CheckForUnsigned(&mask)) { 2132 FAILn("Expected mask literal"); 2133 } 2134 if (!base::bits::IsPowerOfTwo(mask + 1)) { 2135 FAILn("Expected power of 2 mask"); 2136 } 2137 current_function_builder_->EmitI32Const(mask); 2138 current_function_builder_->Emit(kExprI32And); 2139 EXPECT_TOKENn(']'); 2140 VarInfo* function_info = GetVarInfo(function_name); 2141 if (function_info->kind == VarKind::kUnused) { 2142 if (module_builder_->NumTables() == 0) { 2143 module_builder_->AddTable(kWasmFuncRef, 0); 2144 } 2145 uint32_t func_index = module_builder_->IncreaseTableMinSize(0, mask + 1); 2146 if (func_index == std::numeric_limits<uint32_t>::max()) { 2147 FAILn("Exceeded maximum function table size"); 2148 } 2149 function_info->kind = VarKind::kTable; 2150 function_info->mask = mask; 2151 function_info->index = func_index; 2152 function_info->mutable_variable = false; 2153 } else { 2154 if (function_info->kind != VarKind::kTable) { 2155 FAILn("Expected call table"); 2156 } 2157 if (function_info->mask != mask) { 2158 FAILn("Mask size mismatch"); 2159 } 2160 } 2161 current_function_builder_->EmitI32Const(function_info->index); 2162 current_function_builder_->Emit(kExprI32Add); 2163 // We have to use a temporary for the correct order of evaluation. 2164 tmp_scope.emplace(this); 2165 current_function_builder_->EmitSetLocal(tmp_scope->get()); 2166 // The position of function table calls is after the table lookup. 2167 call_pos = scanner_.Position(); 2168 } else { 2169 VarInfo* function_info = GetVarInfo(function_name); 2170 if (function_info->kind == VarKind::kUnused) { 2171 function_info->kind = VarKind::kFunction; 2172 function_info->function_builder = module_builder_->AddFunction(); 2173 function_info->index = function_info->function_builder->func_index(); 2174 function_info->mutable_variable = false; 2175 } else { 2176 if (function_info->kind != VarKind::kFunction && 2177 function_info->kind < VarKind::kImportedFunction) { 2178 FAILn("Expected function as call target"); 2179 } 2180 } 2181 } 2182 2183 // Parse argument list and gather types. 2184 CachedVector<AsmType*> param_types(&cached_asm_type_p_vectors_); 2185 CachedVector<AsmType*> param_specific_types(&cached_asm_type_p_vectors_); 2186 EXPECT_TOKENn('('); 2187 while (!failed_ && !Peek(')')) { 2188 AsmType* t; 2189 RECURSEn(t = AssignmentExpression()); 2190 param_specific_types.push_back(t); 2191 if (t->IsA(AsmType::Int())) { 2192 param_types.push_back(AsmType::Int()); 2193 } else if (t->IsA(AsmType::Float())) { 2194 param_types.push_back(AsmType::Float()); 2195 } else if (t->IsA(AsmType::Double())) { 2196 param_types.push_back(AsmType::Double()); 2197 } else { 2198 FAILn("Bad function argument type"); 2199 } 2200 if (!Peek(')')) { 2201 EXPECT_TOKENn(','); 2202 } 2203 } 2204 EXPECT_TOKENn(')'); 2205 2206 // Reload {VarInfo} after parsing arguments as table might have grown. 2207 VarInfo* function_info = GetVarInfo(function_name); 2208 2209 // We potentially use lookahead in order to determine the return type in case 2210 // it is not yet clear from the call context. Special care has to be taken to 2211 // ensure the non-contextual lookahead is valid. The following restrictions 2212 // substantiate the validity of the lookahead implemented below: 2213 // - All calls (except stdlib calls) require some sort of type annotation. 2214 // - The coercion to "signed" is part of the {BitwiseORExpression}, any 2215 // intermittent expressions like parenthesis in `(callsite(..))|0` are 2216 // syntactically not considered coercions. 2217 // - The coercion to "double" as part of the {UnaryExpression} has higher 2218 // precedence and wins in `+callsite(..)|0` cases. Only "float" return 2219 // types are overridden in `fround(callsite(..)|0)` expressions. 2220 // - Expected coercions to "signed" are flagged via {call_coercion_deferred} 2221 // and later on validated as part of {BitwiseORExpression} to ensure they 2222 // indeed apply to the current call expression. 2223 // - The deferred validation is only allowed if {BitwiseORExpression} did 2224 // promise to fulfill the request via {call_coercion_deferred_position}. 2225 if (allow_peek && Peek('|') && 2226 function_info->kind <= VarKind::kImportedFunction && 2227 (return_type == nullptr || return_type->IsA(AsmType::Float()))) { 2228 DCHECK_NULL(call_coercion_deferred_); 2229 call_coercion_deferred_ = AsmType::Signed(); 2230 to_number_pos = scanner_.Position(); 2231 return_type = AsmType::Signed(); 2232 } else if (return_type == nullptr) { 2233 to_number_pos = call_pos; // No conversion. 2234 return_type = AsmType::Void(); 2235 } 2236 2237 // Compute function type and signature based on gathered types. 2238 AsmType* function_type = AsmType::Function(zone(), return_type); 2239 for (auto t : param_types) { 2240 function_type->AsFunctionType()->AddArgument(t); 2241 } 2242 FunctionSig* sig = ConvertSignature(return_type, param_types); 2243 uint32_t signature_index = module_builder_->AddSignature(sig); 2244 2245 // Emit actual function invocation depending on the kind. At this point we 2246 // also determined the complete function type and can perform checking against 2247 // the expected type or update the expected type in case of first occurrence. 2248 if (function_info->kind == VarKind::kImportedFunction) { 2249 if (param_types.size() > kV8MaxWasmFunctionParams) { 2250 FAILn("Number of parameters exceeds internal limit"); 2251 } 2252 for (auto t : param_specific_types) { 2253 if (!t->IsA(AsmType::Extern())) { 2254 FAILn("Imported function args must be type extern"); 2255 } 2256 } 2257 if (return_type->IsA(AsmType::Float())) { 2258 FAILn("Imported function can't be called as float"); 2259 } 2260 DCHECK_NOT_NULL(function_info->import); 2261 // TODO(bradnelson): Factor out. 2262 uint32_t index; 2263 auto it = function_info->import->cache.find(*sig); 2264 if (it != function_info->import->cache.end()) { 2265 index = it->second; 2266 DCHECK(function_info->function_defined); 2267 } else { 2268 index = 2269 module_builder_->AddImport(function_info->import->function_name, sig); 2270 function_info->import->cache[*sig] = index; 2271 function_info->function_defined = true; 2272 } 2273 current_function_builder_->AddAsmWasmOffset(call_pos, to_number_pos); 2274 current_function_builder_->EmitWithU32V(kExprCallFunction, index); 2275 } else if (function_info->kind > VarKind::kImportedFunction) { 2276 AsmCallableType* callable = function_info->type->AsCallableType(); 2277 if (!callable) { 2278 FAILn("Expected callable function"); 2279 } 2280 // TODO(bradnelson): Refactor AsmType to not need this. 2281 if (callable->CanBeInvokedWith(return_type, param_specific_types)) { 2282 // Return type ok. 2283 } else if (callable->CanBeInvokedWith(AsmType::Float(), 2284 param_specific_types)) { 2285 return_type = AsmType::Float(); 2286 } else if (callable->CanBeInvokedWith(AsmType::Floatish(), 2287 param_specific_types)) { 2288 return_type = AsmType::Floatish(); 2289 } else if (callable->CanBeInvokedWith(AsmType::Double(), 2290 param_specific_types)) { 2291 return_type = AsmType::Double(); 2292 } else if (callable->CanBeInvokedWith(AsmType::Signed(), 2293 param_specific_types)) { 2294 return_type = AsmType::Signed(); 2295 } else if (callable->CanBeInvokedWith(AsmType::Unsigned(), 2296 param_specific_types)) { 2297 return_type = AsmType::Unsigned(); 2298 } else { 2299 FAILn("Function use doesn't match definition"); 2300 } 2301 switch (function_info->kind) { 2302#define V(name, Name, op, sig) \ 2303 case VarKind::kMath##Name: \ 2304 current_function_builder_->Emit(op); \ 2305 break; 2306 STDLIB_MATH_FUNCTION_MONOMORPHIC_LIST(V) 2307#undef V 2308#define V(name, Name, op, sig) \ 2309 case VarKind::kMath##Name: \ 2310 if (param_specific_types[0]->IsA(AsmType::DoubleQ())) { \ 2311 current_function_builder_->Emit(kExprF64##Name); \ 2312 } else if (param_specific_types[0]->IsA(AsmType::FloatQ())) { \ 2313 current_function_builder_->Emit(kExprF32##Name); \ 2314 } else { \ 2315 UNREACHABLE(); \ 2316 } \ 2317 break; 2318 STDLIB_MATH_FUNCTION_CEIL_LIKE_LIST(V) 2319#undef V 2320 case VarKind::kMathMin: 2321 case VarKind::kMathMax: 2322 if (param_specific_types[0]->IsA(AsmType::Double())) { 2323 for (size_t i = 1; i < param_specific_types.size(); ++i) { 2324 if (function_info->kind == VarKind::kMathMin) { 2325 current_function_builder_->Emit(kExprF64Min); 2326 } else { 2327 current_function_builder_->Emit(kExprF64Max); 2328 } 2329 } 2330 } else if (param_specific_types[0]->IsA(AsmType::Float())) { 2331 // NOTE: Not technically part of the asm.js spec, but Firefox 2332 // accepts it. 2333 for (size_t i = 1; i < param_specific_types.size(); ++i) { 2334 if (function_info->kind == VarKind::kMathMin) { 2335 current_function_builder_->Emit(kExprF32Min); 2336 } else { 2337 current_function_builder_->Emit(kExprF32Max); 2338 } 2339 } 2340 } else if (param_specific_types[0]->IsA(AsmType::Signed())) { 2341 TemporaryVariableScope tmp_x(this); 2342 TemporaryVariableScope tmp_y(this); 2343 for (size_t i = 1; i < param_specific_types.size(); ++i) { 2344 current_function_builder_->EmitSetLocal(tmp_x.get()); 2345 current_function_builder_->EmitTeeLocal(tmp_y.get()); 2346 current_function_builder_->EmitGetLocal(tmp_x.get()); 2347 if (function_info->kind == VarKind::kMathMin) { 2348 current_function_builder_->Emit(kExprI32GeS); 2349 } else { 2350 current_function_builder_->Emit(kExprI32LeS); 2351 } 2352 current_function_builder_->EmitWithU8(kExprIf, kI32Code); 2353 current_function_builder_->EmitGetLocal(tmp_x.get()); 2354 current_function_builder_->Emit(kExprElse); 2355 current_function_builder_->EmitGetLocal(tmp_y.get()); 2356 current_function_builder_->Emit(kExprEnd); 2357 } 2358 } else { 2359 UNREACHABLE(); 2360 } 2361 break; 2362 2363 case VarKind::kMathAbs: 2364 if (param_specific_types[0]->IsA(AsmType::Signed())) { 2365 TemporaryVariableScope tmp(this); 2366 current_function_builder_->EmitTeeLocal(tmp.get()); 2367 current_function_builder_->EmitGetLocal(tmp.get()); 2368 current_function_builder_->EmitI32Const(31); 2369 current_function_builder_->Emit(kExprI32ShrS); 2370 current_function_builder_->EmitTeeLocal(tmp.get()); 2371 current_function_builder_->Emit(kExprI32Xor); 2372 current_function_builder_->EmitGetLocal(tmp.get()); 2373 current_function_builder_->Emit(kExprI32Sub); 2374 } else if (param_specific_types[0]->IsA(AsmType::DoubleQ())) { 2375 current_function_builder_->Emit(kExprF64Abs); 2376 } else if (param_specific_types[0]->IsA(AsmType::FloatQ())) { 2377 current_function_builder_->Emit(kExprF32Abs); 2378 } else { 2379 UNREACHABLE(); 2380 } 2381 break; 2382 2383 case VarKind::kMathFround: 2384 // NOTE: Handled in {AsmJsParser::CallExpression} specially and treated 2385 // as a coercion to "float" type. Cannot be reached as a call here. 2386 UNREACHABLE(); 2387 2388 default: 2389 UNREACHABLE(); 2390 } 2391 } else { 2392 DCHECK(function_info->kind == VarKind::kFunction || 2393 function_info->kind == VarKind::kTable); 2394 if (function_info->type->IsA(AsmType::None())) { 2395 function_info->type = function_type; 2396 } else { 2397 AsmCallableType* callable = function_info->type->AsCallableType(); 2398 if (!callable || 2399 !callable->CanBeInvokedWith(return_type, param_specific_types)) { 2400 FAILn("Function use doesn't match definition"); 2401 } 2402 } 2403 if (function_info->kind == VarKind::kTable) { 2404 current_function_builder_->EmitGetLocal(tmp_scope->get()); 2405 current_function_builder_->AddAsmWasmOffset(call_pos, to_number_pos); 2406 current_function_builder_->Emit(kExprCallIndirect); 2407 current_function_builder_->EmitU32V(signature_index); 2408 current_function_builder_->EmitU32V(0); // table index 2409 } else { 2410 current_function_builder_->AddAsmWasmOffset(call_pos, to_number_pos); 2411 current_function_builder_->Emit(kExprCallFunction); 2412 current_function_builder_->EmitDirectCallIndex(function_info->index); 2413 } 2414 } 2415 2416 return return_type; 2417} 2418 2419// 6.9 ValidateCall - helper 2420bool AsmJsParser::PeekCall() { 2421 if (!scanner_.IsGlobal()) { 2422 return false; 2423 } 2424 if (GetVarInfo(scanner_.Token())->kind == VarKind::kFunction) { 2425 return true; 2426 } 2427 if (GetVarInfo(scanner_.Token())->kind >= VarKind::kImportedFunction) { 2428 return true; 2429 } 2430 if (GetVarInfo(scanner_.Token())->kind == VarKind::kUnused || 2431 GetVarInfo(scanner_.Token())->kind == VarKind::kTable) { 2432 scanner_.Next(); 2433 if (Peek('(') || Peek('[')) { 2434 scanner_.Rewind(); 2435 return true; 2436 } 2437 scanner_.Rewind(); 2438 } 2439 return false; 2440} 2441 2442// 6.10 ValidateHeapAccess 2443void AsmJsParser::ValidateHeapAccess() { 2444 VarInfo* info = GetVarInfo(Consume()); 2445 int32_t size = info->type->ElementSizeInBytes(); 2446 EXPECT_TOKEN('['); 2447 uint32_t offset; 2448 if (CheckForUnsigned(&offset)) { 2449 // TODO(bradnelson): Check more things. 2450 // TODO(asmjs): Clarify and explain where this limit is coming from, 2451 // as it is not mandated by the spec directly. 2452 if (offset > 0x7FFFFFFF || 2453 static_cast<uint64_t>(offset) * static_cast<uint64_t>(size) > 2454 0x7FFFFFFF) { 2455 FAIL("Heap access out of range"); 2456 } 2457 if (Check(']')) { 2458 current_function_builder_->EmitI32Const( 2459 static_cast<uint32_t>(offset * size)); 2460 // NOTE: This has to happen here to work recursively. 2461 heap_access_type_ = info->type; 2462 return; 2463 } else { 2464 scanner_.Rewind(); 2465 } 2466 } 2467 AsmType* index_type; 2468 if (info->type->IsA(AsmType::Int8Array()) || 2469 info->type->IsA(AsmType::Uint8Array())) { 2470 RECURSE(index_type = Expression(nullptr)); 2471 } else { 2472 RECURSE(index_type = ShiftExpression()); 2473 if (heap_access_shift_position_ == kNoHeapAccessShift) { 2474 FAIL("Expected shift of word size"); 2475 } 2476 if (heap_access_shift_value_ > 3) { 2477 FAIL("Expected valid heap access shift"); 2478 } 2479 if ((1 << heap_access_shift_value_) != size) { 2480 FAIL("Expected heap access shift to match heap view"); 2481 } 2482 // Delete the code of the actual shift operation. 2483 current_function_builder_->DeleteCodeAfter(heap_access_shift_position_); 2484 // Mask bottom bits to match asm.js behavior. 2485 current_function_builder_->EmitI32Const(~(size - 1)); 2486 current_function_builder_->Emit(kExprI32And); 2487 } 2488 if (!index_type->IsA(AsmType::Intish())) { 2489 FAIL("Expected intish index"); 2490 } 2491 EXPECT_TOKEN(']'); 2492 // NOTE: This has to happen here to work recursively. 2493 heap_access_type_ = info->type; 2494} 2495 2496// 6.11 ValidateFloatCoercion 2497void AsmJsParser::ValidateFloatCoercion() { 2498 if (!scanner_.IsGlobal() || 2499 !GetVarInfo(scanner_.Token())->type->IsA(stdlib_fround_)) { 2500 FAIL("Expected fround"); 2501 } 2502 scanner_.Next(); 2503 EXPECT_TOKEN('('); 2504 call_coercion_ = AsmType::Float(); 2505 // NOTE: The coercion position to float is not observable from JavaScript, 2506 // because imported functions are not allowed to have float return type. 2507 call_coercion_position_ = scanner_.Position(); 2508 AsmType* ret; 2509 RECURSE(ret = AssignmentExpression()); 2510 if (ret->IsA(AsmType::Floatish())) { 2511 // Do nothing, as already a float. 2512 } else if (ret->IsA(AsmType::DoubleQ())) { 2513 current_function_builder_->Emit(kExprF32ConvertF64); 2514 } else if (ret->IsA(AsmType::Signed())) { 2515 current_function_builder_->Emit(kExprF32SConvertI32); 2516 } else if (ret->IsA(AsmType::Unsigned())) { 2517 current_function_builder_->Emit(kExprF32UConvertI32); 2518 } else { 2519 FAIL("Illegal conversion to float"); 2520 } 2521 EXPECT_TOKEN(')'); 2522} 2523 2524void AsmJsParser::ScanToClosingParenthesis() { 2525 int depth = 0; 2526 for (;;) { 2527 if (Peek('(')) { 2528 ++depth; 2529 } else if (Peek(')')) { 2530 --depth; 2531 if (depth < 0) { 2532 break; 2533 } 2534 } else if (Peek(AsmJsScanner::kEndOfInput)) { 2535 break; 2536 } 2537 scanner_.Next(); 2538 } 2539} 2540 2541void AsmJsParser::GatherCases(ZoneVector<int32_t>* cases) { 2542 size_t start = scanner_.Position(); 2543 int depth = 0; 2544 for (;;) { 2545 if (Peek('{')) { 2546 ++depth; 2547 } else if (Peek('}')) { 2548 --depth; 2549 if (depth <= 0) { 2550 break; 2551 } 2552 } else if (depth == 1 && Peek(TOK(case))) { 2553 scanner_.Next(); 2554 uint32_t uvalue; 2555 bool negate = false; 2556 if (Check('-')) negate = true; 2557 if (!CheckForUnsigned(&uvalue)) { 2558 break; 2559 } 2560 int32_t value = static_cast<int32_t>(uvalue); 2561 DCHECK_IMPLIES(negate && uvalue == 0x80000000, value == kMinInt); 2562 if (negate && value != kMinInt) { 2563 value = -value; 2564 } 2565 cases->push_back(value); 2566 } else if (Peek(AsmJsScanner::kEndOfInput) || 2567 Peek(AsmJsScanner::kParseError)) { 2568 break; 2569 } 2570 scanner_.Next(); 2571 } 2572 scanner_.Seek(start); 2573} 2574 2575} // namespace wasm 2576} // namespace internal 2577} // namespace v8 2578 2579#undef RECURSE 2580