5 #include "src/asmjs/asm-parser.h" 12 #include "src/asmjs/asm-js.h" 13 #include "src/asmjs/asm-types.h" 14 #include "src/base/optional.h" 15 #include "src/flags.h" 16 #include "src/parsing/scanner.h" 17 #include "src/wasm/wasm-limits.h" 18 #include "src/wasm/wasm-opcodes.h" 25 #define FAIL_AND_RETURN(ret, msg) \ 27 failure_message_ = msg; \ 28 failure_location_ = static_cast<int>(scanner_.Position()); \ 29 if (FLAG_trace_asm_parser) { \ 30 PrintF("[asm.js failure: %s, token: '%s', see: %s:%d]\n", msg, \ 31 scanner_.Name(scanner_.Token()).c_str(), __FILE__, __LINE__); \ 35 #define FAIL_AND_RETURN(ret, msg) \ 37 failure_message_ = msg; \ 38 failure_location_ = static_cast<int>(scanner_.Position()); \ 42 #define FAIL(msg) FAIL_AND_RETURN(, msg) 43 #define FAILn(msg) FAIL_AND_RETURN(nullptr, msg) 45 #define EXPECT_TOKEN_OR_RETURN(ret, token) \ 47 if (scanner_.Token() != token) { \ 48 FAIL_AND_RETURN(ret, "Unexpected token"); \ 53 #define EXPECT_TOKEN(token) EXPECT_TOKEN_OR_RETURN(, token) 54 #define EXPECT_TOKENn(token) EXPECT_TOKEN_OR_RETURN(nullptr, token) 56 #define RECURSE_OR_RETURN(ret, call) \ 59 if (GetCurrentStackPosition() < stack_limit_) { \ 60 FAIL_AND_RETURN(ret, "Stack overflow while parsing asm.js module."); \ 63 if (failed_) return ret; \ 66 #define RECURSE(call) RECURSE_OR_RETURN(, call) 67 #define RECURSEn(call) RECURSE_OR_RETURN(nullptr, call) 69 #define TOK(name) AsmJsScanner::kToken_##name 71 AsmJsParser::AsmJsParser(Zone* zone,
uintptr_t stack_limit,
72 Utf16CharacterStream* stream)
75 module_builder_(new (zone) WasmModuleBuilder(zone)),
76 return_type_(nullptr),
77 stack_limit_(stack_limit),
78 global_var_info_(zone),
79 local_var_info_(zone),
81 failure_location_(kNoSourcePosition),
82 stdlib_name_(kTokenNone),
83 foreign_name_(kTokenNone),
84 heap_name_(kTokenNone),
85 inside_heap_assignment_(false),
86 heap_access_type_(nullptr),
88 call_coercion_(nullptr),
89 call_coercion_deferred_(nullptr),
91 global_imports_(zone) {
92 module_builder_->SetMinMemorySize(0);
93 InitializeStdlibTypes();
96 void AsmJsParser::InitializeStdlibTypes() {
97 auto* d = AsmType::Double();
98 auto* dq = AsmType::DoubleQ();
99 stdlib_dq2d_ = AsmType::Function(zone(), d);
100 stdlib_dq2d_->AsFunctionType()->AddArgument(dq);
102 stdlib_dqdq2d_ = AsmType::Function(zone(), d);
103 stdlib_dqdq2d_->AsFunctionType()->AddArgument(dq);
104 stdlib_dqdq2d_->AsFunctionType()->AddArgument(dq);
106 auto* f = AsmType::Float();
107 auto* fh = AsmType::Floatish();
108 auto* fq = AsmType::FloatQ();
109 auto* fq2fh = AsmType::Function(zone(), fh);
110 fq2fh->AsFunctionType()->AddArgument(fq);
112 auto* s = AsmType::Signed();
113 auto* u = AsmType::Unsigned();
114 auto* s2u = AsmType::Function(zone(), u);
115 s2u->AsFunctionType()->AddArgument(s);
117 auto*
i = AsmType::Int();
118 stdlib_i2s_ = AsmType::Function(zone_, s);
119 stdlib_i2s_->AsFunctionType()->AddArgument(
i);
121 stdlib_ii2s_ = AsmType::Function(zone(), s);
122 stdlib_ii2s_->AsFunctionType()->AddArgument(
i);
123 stdlib_ii2s_->AsFunctionType()->AddArgument(
i);
130 auto* minmax_d = AsmType::MinMaxType(zone(), d, d);
131 auto* minmax_f = AsmType::MinMaxType(zone(), f, f);
132 auto* minmax_s = AsmType::MinMaxType(zone(), s, s);
133 stdlib_minmax_ = AsmType::OverloadedFunction(zone());
134 stdlib_minmax_->AsOverloadedFunctionType()->AddOverload(minmax_s);
135 stdlib_minmax_->AsOverloadedFunctionType()->AddOverload(minmax_f);
136 stdlib_minmax_->AsOverloadedFunctionType()->AddOverload(minmax_d);
143 stdlib_abs_ = AsmType::OverloadedFunction(zone());
144 stdlib_abs_->AsOverloadedFunctionType()->AddOverload(s2u);
145 stdlib_abs_->AsOverloadedFunctionType()->AddOverload(stdlib_dq2d_);
146 stdlib_abs_->AsOverloadedFunctionType()->AddOverload(fq2fh);
152 stdlib_ceil_like_ = AsmType::OverloadedFunction(zone());
153 stdlib_ceil_like_->AsOverloadedFunctionType()->AddOverload(stdlib_dq2d_);
154 stdlib_ceil_like_->AsOverloadedFunctionType()->AddOverload(fq2fh);
156 stdlib_fround_ = AsmType::FroundType(zone());
159 FunctionSig* AsmJsParser::ConvertSignature(AsmType* return_type,
160 const ZoneVector<AsmType*>& params) {
161 FunctionSig::Builder sig_builder(
162 zone(), !return_type->IsA(AsmType::Void()) ? 1 : 0, params.size());
163 for (
auto param : params) {
164 if (param->IsA(AsmType::Double())) {
165 sig_builder.AddParam(kWasmF64);
166 }
else if (param->IsA(AsmType::Float())) {
167 sig_builder.AddParam(kWasmF32);
168 }
else if (param->IsA(AsmType::Int())) {
169 sig_builder.AddParam(kWasmI32);
174 if (!return_type->IsA(AsmType::Void())) {
175 if (return_type->IsA(AsmType::Double())) {
176 sig_builder.AddReturn(kWasmF64);
177 }
else if (return_type->IsA(AsmType::Float())) {
178 sig_builder.AddReturn(kWasmF32);
179 }
else if (return_type->IsA(AsmType::Signed())) {
180 sig_builder.AddReturn(kWasmI32);
185 return sig_builder.Build();
188 bool AsmJsParser::Run() {
196 local_depth_ = parser_->function_temp_locals_depth_;
197 parser_->function_temp_locals_depth_++;
200 DCHECK_EQ(local_depth_, parser_->function_temp_locals_depth_ - 1);
201 parser_->function_temp_locals_depth_--;
203 uint32_t get()
const {
return parser_->TempVariable(local_depth_); }
210 wasm::AsmJsParser::VarInfo* AsmJsParser::GetVarInfo(
211 AsmJsScanner::token_t token) {
212 if (AsmJsScanner::IsGlobal(token)) {
213 size_t old = global_var_info_.size();
214 size_t index = AsmJsScanner::GlobalIndex(token);
215 size_t sz = std::max(old, index + 1);
217 global_var_info_.resize(sz);
219 return &global_var_info_[index];
220 }
else if (AsmJsScanner::IsLocal(token)) {
221 size_t old = local_var_info_.size();
222 size_t index = AsmJsScanner::LocalIndex(token);
223 size_t sz = std::max(old, index + 1);
225 local_var_info_.resize(sz);
227 return &local_var_info_[index];
232 uint32_t AsmJsParser::VarIndex(VarInfo* info) {
233 DCHECK_EQ(info->kind, VarKind::kGlobal);
234 return info->index +
static_cast<uint32_t>(global_imports_.size());
237 void AsmJsParser::AddGlobalImport(Vector<const char> name, AsmType* type,
238 ValueType vtype,
bool mutable_variable,
243 DeclareGlobal(info, mutable_variable, type, vtype);
246 global_imports_.push_back({name, vtype, info});
249 void AsmJsParser::DeclareGlobal(VarInfo* info,
bool mutable_variable,
250 AsmType* type, ValueType vtype,
251 const WasmInitExpr& init) {
252 info->kind = VarKind::kGlobal;
254 info->index = module_builder_->AddGlobal(vtype,
false,
true, init);
255 info->mutable_variable = mutable_variable;
258 void AsmJsParser::DeclareStdlibFunc(VarInfo* info, VarKind kind,
263 info->mutable_variable =
false;
266 uint32_t AsmJsParser::TempVariable(
int index) {
267 if (index + 1 > function_temp_locals_used_) {
268 function_temp_locals_used_ = index + 1;
270 return function_temp_locals_offset_ + index;
273 Vector<const char> AsmJsParser::CopyCurrentIdentifierString() {
274 const std::string& str = scanner_.GetIdentifierString();
275 char* buffer = zone()->NewArray<
char>(str.size());
276 str.copy(buffer, str.size());
277 return Vector<const char>(buffer,
static_cast<int>(str.size()));
280 void AsmJsParser::SkipSemicolon() {
283 }
else if (!Peek(
'}') && !scanner_.IsPrecededByNewline()) {
288 void AsmJsParser::Begin(AsmJsScanner::token_t label) {
289 BareBegin(BlockKind::kRegular, label);
290 current_function_builder_->EmitWithU8(kExprBlock, kLocalVoid);
293 void AsmJsParser::Loop(AsmJsScanner::token_t label) {
294 BareBegin(BlockKind::kLoop, label);
295 size_t position = scanner_.Position();
296 current_function_builder_->AddAsmWasmOffset(position, position);
297 current_function_builder_->EmitWithU8(kExprLoop, kLocalVoid);
300 void AsmJsParser::End() {
302 current_function_builder_->Emit(kExprEnd);
305 void AsmJsParser::BareBegin(BlockKind kind, AsmJsScanner::token_t label) {
309 block_stack_.push_back(info);
312 void AsmJsParser::BareEnd() {
313 DCHECK_GT(block_stack_.size(), 0);
314 block_stack_.pop_back();
317 int AsmJsParser::FindContinueLabelDepth(AsmJsScanner::token_t label) {
319 for (
auto it = block_stack_.rbegin(); it != block_stack_.rend();
321 if (it->kind == BlockKind::kLoop &&
322 (label == kTokenNone || it->label == label)) {
329 int AsmJsParser::FindBreakLabelDepth(AsmJsScanner::token_t label) {
331 for (
auto it = block_stack_.rbegin(); it != block_stack_.rend();
333 if (it->kind == BlockKind::kRegular &&
334 (label == kTokenNone || it->label == label)) {
342 void AsmJsParser::ValidateModule() {
343 RECURSE(ValidateModuleParameters());
345 EXPECT_TOKEN(TOK(UseAsm));
347 RECURSE(ValidateModuleVars());
348 while (Peek(TOK(
function))) {
349 RECURSE(ValidateFunction());
351 while (Peek(TOK(var))) {
352 RECURSE(ValidateFunctionTable());
354 RECURSE(ValidateExport());
357 for (
auto& info : global_var_info_) {
358 if (info.kind == VarKind::kFunction && !info.function_defined) {
359 FAIL(
"Undefined function");
361 if (info.kind == VarKind::kTable && !info.function_defined) {
362 FAIL(
"Undefined function table");
364 if (info.kind == VarKind::kImportedFunction && !info.function_defined) {
367 FunctionSig* void_void_sig = FunctionSig::Builder(zone(), 0, 0).Build();
368 module_builder_->AddImport(info.import->function_name, void_void_sig);
373 WasmFunctionBuilder* start = module_builder_->AddFunction();
374 module_builder_->MarkStartFunction(start);
375 for (
auto& global_import : global_imports_) {
376 uint32_t import_index = module_builder_->AddGlobalImport(
377 global_import.import_name, global_import.value_type);
378 start->EmitWithI32V(kExprGetGlobal, import_index);
379 start->EmitWithI32V(kExprSetGlobal, VarIndex(global_import.var_info));
381 start->Emit(kExprEnd);
382 FunctionSig::Builder b(zone(), 0, 0);
383 start->SetSignature(b.Build());
387 void AsmJsParser::ValidateModuleParameters() {
393 if (!scanner_.IsGlobal()) {
394 FAIL(
"Expected stdlib parameter");
396 stdlib_name_ = Consume();
399 if (!scanner_.IsGlobal()) {
400 FAIL(
"Expected foreign parameter");
402 foreign_name_ = Consume();
405 if (!scanner_.IsGlobal()) {
406 FAIL(
"Expected heap parameter");
408 heap_name_ = Consume();
416 void AsmJsParser::ValidateModuleVars() {
417 while (Peek(TOK(var)) || Peek(TOK(
const))) {
418 bool mutable_variable =
true;
419 if (Check(TOK(var))) {
422 EXPECT_TOKEN(TOK(
const));
423 mutable_variable =
false;
426 RECURSE(ValidateModuleVar(mutable_variable));
437 void AsmJsParser::ValidateModuleVar(
bool mutable_variable) {
438 if (!scanner_.IsGlobal()) {
439 FAIL(
"Expected identifier");
441 VarInfo* info = GetVarInfo(Consume());
442 if (info->kind != VarKind::kUnused) {
443 FAIL(
"Redefinition of variable");
448 if (CheckForDouble(&dvalue)) {
449 DeclareGlobal(info, mutable_variable, AsmType::Double(), kWasmF64,
450 WasmInitExpr(dvalue));
451 }
else if (CheckForUnsigned(&uvalue)) {
452 if (uvalue > 0x7FFFFFFF) {
453 FAIL(
"Numeric literal out of range");
455 DeclareGlobal(info, mutable_variable,
456 mutable_variable ? AsmType::Int() : AsmType::Signed(),
457 kWasmI32, WasmInitExpr(static_cast<int32_t>(uvalue)));
458 }
else if (Check(
'-')) {
459 if (CheckForDouble(&dvalue)) {
460 DeclareGlobal(info, mutable_variable, AsmType::Double(), kWasmF64,
461 WasmInitExpr(-dvalue));
462 }
else if (CheckForUnsigned(&uvalue)) {
463 if (uvalue > 0x7FFFFFFF) {
464 FAIL(
"Numeric literal out of range");
466 DeclareGlobal(info, mutable_variable,
467 mutable_variable ? AsmType::Int() : AsmType::Signed(),
468 kWasmI32, WasmInitExpr(-static_cast<int32_t>(uvalue)));
470 FAIL(
"Expected numeric literal");
472 }
else if (Check(TOK(
new))) {
473 RECURSE(ValidateModuleVarNewStdlib(info));
474 }
else if (Check(stdlib_name_)) {
476 RECURSE(ValidateModuleVarStdlib(info));
477 }
else if (Peek(foreign_name_) || Peek(
'+')) {
478 RECURSE(ValidateModuleVarImport(info, mutable_variable));
479 }
else if (scanner_.IsGlobal()) {
480 RECURSE(ValidateModuleVarFromGlobal(info, mutable_variable));
482 FAIL(
"Bad variable declaration");
487 void AsmJsParser::ValidateModuleVarFromGlobal(VarInfo* info,
488 bool mutable_variable) {
489 VarInfo* src_info = GetVarInfo(Consume());
490 if (!src_info->type->IsA(stdlib_fround_)) {
491 if (src_info->mutable_variable) {
492 FAIL(
"Can only use immutable variables in global definition");
494 if (mutable_variable) {
495 FAIL(
"Can only define immutable variables with other immutables");
497 if (!src_info->type->IsA(AsmType::Int()) &&
498 !src_info->type->IsA(AsmType::Float()) &&
499 !src_info->type->IsA(AsmType::Double())) {
500 FAIL(
"Expected int, float, double, or fround for global definition");
502 info->kind = VarKind::kGlobal;
503 info->type = src_info->type;
504 info->index = src_info->index;
505 info->mutable_variable =
false;
515 if (CheckForDouble(&dvalue)) {
519 DeclareGlobal(info, mutable_variable, AsmType::Float(), kWasmF32,
520 WasmInitExpr(static_cast<float>(dvalue)));
521 }
else if (CheckForUnsigned(&uvalue)) {
526 DeclareGlobal(info, mutable_variable, AsmType::Float(), kWasmF32,
527 WasmInitExpr(static_cast<float>(dvalue)));
529 FAIL(
"Expected numeric literal");
535 void AsmJsParser::ValidateModuleVarImport(VarInfo* info,
536 bool mutable_variable) {
538 EXPECT_TOKEN(foreign_name_);
540 Vector<const char> name = CopyCurrentIdentifierString();
541 AddGlobalImport(name, AsmType::Double(), kWasmF64, mutable_variable, info);
544 EXPECT_TOKEN(foreign_name_);
546 Vector<const char> name = CopyCurrentIdentifierString();
549 if (!CheckForZero()) {
550 FAIL(
"Expected |0 type annotation for foreign integer import");
552 AddGlobalImport(name, AsmType::Int(), kWasmI32, mutable_variable, info);
554 info->kind = VarKind::kImportedFunction;
555 info->import =
new (zone()->New(
sizeof(FunctionImportInfo)))
556 FunctionImportInfo(name, zone());
557 info->mutable_variable =
false;
564 void AsmJsParser::ValidateModuleVarNewStdlib(VarInfo* info) {
565 EXPECT_TOKEN(stdlib_name_);
568 #define V(name, _junk1, _junk2, _junk3) \ 570 DeclareStdlibFunc(info, VarKind::kSpecial, AsmType::name()); \ 571 stdlib_uses_.Add(StandardMember::k##name); \ 573 STDLIB_ARRAY_TYPE_LIST(
V)
576 FAIL(
"Expected ArrayBuffer view");
580 EXPECT_TOKEN(heap_name_);
586 void AsmJsParser::ValidateModuleVarStdlib(VarInfo* info) {
587 if (Check(TOK(Math))) {
590 #define V(name, const_value) \ 592 DeclareGlobal(info, false, AsmType::Double(), kWasmF64, \ 593 WasmInitExpr(const_value)); \ 594 stdlib_uses_.Add(StandardMember::kMath##name); \ 596 STDLIB_MATH_VALUE_LIST(
V)
598 #define V(name, Name, op, sig) \ 600 DeclareStdlibFunc(info, VarKind::kMath##Name, stdlib_##sig##_); \ 601 stdlib_uses_.Add(StandardMember::kMath##Name); \ 603 STDLIB_MATH_FUNCTION_LIST(
V)
606 FAIL(
"Invalid member of stdlib.Math");
608 }
else if (Check(TOK(Infinity))) {
609 DeclareGlobal(info,
false, AsmType::Double(), kWasmF64,
610 WasmInitExpr(std::numeric_limits<double>::infinity()));
611 stdlib_uses_.Add(StandardMember::kInfinity);
612 }
else if (Check(TOK(NaN))) {
613 DeclareGlobal(info,
false, AsmType::Double(), kWasmF64,
614 WasmInitExpr(std::numeric_limits<double>::quiet_NaN()));
615 stdlib_uses_.Add(StandardMember::kNaN);
617 FAIL(
"Invalid member of stdlib");
622 void AsmJsParser::ValidateExport() {
624 EXPECT_TOKEN(TOK(
return));
628 Vector<const char> name = CopyCurrentIdentifierString();
629 if (!scanner_.IsGlobal() && !scanner_.IsLocal()) {
630 FAIL(
"Illegal export name");
634 if (!scanner_.IsGlobal()) {
635 FAIL(
"Expected function name");
637 VarInfo* info = GetVarInfo(Consume());
638 if (info->kind != VarKind::kFunction) {
639 FAIL(
"Expected function");
641 module_builder_->AddExport(name, info->function_builder);
651 if (!scanner_.IsGlobal()) {
652 FAIL(
"Single function export must be a function name");
654 VarInfo* info = GetVarInfo(Consume());
655 if (info->kind != VarKind::kFunction) {
656 FAIL(
"Single function export must be a function");
658 module_builder_->AddExport(CStrVector(AsmJs::kSingleFunctionName),
659 info->function_builder);
664 void AsmJsParser::ValidateFunctionTable() {
665 EXPECT_TOKEN(TOK(var));
666 if (!scanner_.IsGlobal()) {
667 FAIL(
"Expected table name");
669 VarInfo* table_info = GetVarInfo(Consume());
670 if (table_info->kind == VarKind::kTable) {
671 if (table_info->function_defined) {
672 FAIL(
"Function table redefined");
674 table_info->function_defined =
true;
675 }
else if (table_info->kind != VarKind::kUnused) {
676 FAIL(
"Function table name collides");
682 if (!scanner_.IsGlobal()) {
683 FAIL(
"Expected function name");
685 VarInfo* info = GetVarInfo(Consume());
686 if (info->kind != VarKind::kFunction) {
687 FAIL(
"Expected function");
691 if (table_info->kind == VarKind::kTable) {
692 if (count >= static_cast<uint64_t>(table_info->mask) + 1) {
693 FAIL(
"Exceeded function table size");
695 if (!info->type->IsA(table_info->type)) {
696 FAIL(
"Function table definition doesn't match use");
698 module_builder_->SetIndirectFunction(
699 static_cast<uint32_t>(table_info->index + count), info->index);
710 if (table_info->kind == VarKind::kTable &&
711 count != static_cast<uint64_t>(table_info->mask) + 1) {
712 FAIL(
"Function table size does not match uses");
718 void AsmJsParser::ValidateFunction() {
719 EXPECT_TOKEN(TOK(
function));
720 if (!scanner_.IsGlobal()) {
721 FAIL(
"Expected function name");
724 Vector<const char> function_name_str = CopyCurrentIdentifierString();
725 AsmJsScanner::token_t function_name = Consume();
726 VarInfo* function_info = GetVarInfo(function_name);
727 if (function_info->kind == VarKind::kUnused) {
728 function_info->kind = VarKind::kFunction;
729 function_info->function_builder = module_builder_->AddFunction();
730 function_info->index = function_info->function_builder->func_index();
731 function_info->mutable_variable =
false;
732 }
else if (function_info->kind != VarKind::kFunction) {
733 FAIL(
"Function name collides with variable");
734 }
else if (function_info->function_defined) {
735 FAIL(
"Function redefined");
738 function_info->function_defined =
true;
739 function_info->function_builder->SetName(function_name_str);
740 current_function_builder_ = function_info->function_builder;
741 return_type_ =
nullptr;
744 current_function_builder_->SetAsmFunctionStartPosition(scanner_.Position());
746 CachedVector<AsmType*> params(cached_asm_type_p_vectors_);
747 ValidateFunctionParams(¶ms);
750 if (params.size() >= kV8MaxWasmFunctionParams) {
751 FAIL(
"Number of parameters exceeds internal limit");
754 CachedVector<ValueType> locals(cached_valuetype_vectors_);
755 ValidateFunctionLocals(params.size(), &locals);
757 function_temp_locals_offset_ =
static_cast<uint32_t>(
758 params.size() + locals.size());
759 function_temp_locals_used_ = 0;
760 function_temp_locals_depth_ = 0;
762 bool last_statement_is_return =
false;
763 while (!failed_ && !Peek(
'}')) {
765 last_statement_is_return = Peek(TOK(
return));
767 RECURSE(ValidateStatement());
771 if (!last_statement_is_return) {
772 if (return_type_ ==
nullptr) {
773 return_type_ = AsmType::Void();
774 }
else if (!return_type_->IsA(AsmType::Void())) {
775 FAIL(
"Expected return at end of non-void function");
778 DCHECK_NOT_NULL(return_type_);
782 FunctionSig* sig = ConvertSignature(return_type_, params);
783 current_function_builder_->SetSignature(sig);
784 for (
auto local : locals) {
785 current_function_builder_->AddLocal(local);
788 for (
int i = 0;
i < function_temp_locals_used_; ++
i) {
789 current_function_builder_->AddLocal(kWasmI32);
793 if (locals.size() + function_temp_locals_used_ > kV8MaxWasmFunctionLocals) {
794 FAIL(
"Number of local variables exceeds internal limit");
798 current_function_builder_->Emit(kExprEnd);
801 AsmType* function_type = AsmType::Function(zone(), return_type_);
802 for (
auto t : params) {
803 function_type->AsFunctionType()->AddArgument(t);
805 function_info = GetVarInfo(function_name);
806 if (function_info->type->IsA(AsmType::None())) {
807 DCHECK_EQ(function_info->kind, VarKind::kFunction);
808 function_info->type = function_type;
809 }
else if (!function_type->IsA(function_info->type)) {
811 FAIL(
"Function definition doesn't match use");
814 scanner_.ResetLocals();
815 local_var_info_.clear();
819 void AsmJsParser::ValidateFunctionParams(ZoneVector<AsmType*>* params) {
823 scanner_.EnterLocalScope();
825 CachedVector<AsmJsScanner::token_t> function_parameters(
826 cached_token_t_vectors_);
827 while (!failed_ && !Peek(
')')) {
828 if (!scanner_.IsLocal()) {
829 FAIL(
"Expected parameter name");
831 function_parameters.push_back(Consume());
837 scanner_.EnterGlobalScope();
840 for (
auto p : function_parameters) {
843 VarInfo* info = GetVarInfo(p);
844 if (info->kind != VarKind::kUnused) {
845 FAIL(
"Duplicate parameter name");
849 if (!CheckForZero()) {
850 FAIL(
"Bad integer parameter annotation.");
852 info->kind = VarKind::kLocal;
853 info->type = AsmType::Int();
854 info->index =
static_cast<uint32_t>(params->size());
855 params->push_back(AsmType::Int());
856 }
else if (Check(
'+')) {
858 info->kind = VarKind::kLocal;
859 info->type = AsmType::Double();
860 info->index =
static_cast<uint32_t>(params->size());
861 params->push_back(AsmType::Double());
863 if (!scanner_.IsGlobal() ||
864 !GetVarInfo(Consume())->type->IsA(stdlib_fround_)) {
865 FAIL(
"Expected fround");
870 info->kind = VarKind::kLocal;
871 info->type = AsmType::Float();
872 info->index =
static_cast<uint32_t>(params->size());
873 params->push_back(AsmType::Float());
880 void AsmJsParser::ValidateFunctionLocals(
size_t param_count,
881 ZoneVector<ValueType>* locals) {
882 DCHECK(locals->empty());
884 while (Peek(TOK(var))) {
885 scanner_.EnterLocalScope();
886 EXPECT_TOKEN(TOK(var));
887 scanner_.EnterGlobalScope();
889 if (!scanner_.IsLocal()) {
890 FAIL(
"Expected local variable identifier");
892 VarInfo* info = GetVarInfo(Consume());
893 if (info->kind != VarKind::kUnused) {
894 FAIL(
"Duplicate local variable name");
901 if (CheckForDouble(&dvalue)) {
902 info->kind = VarKind::kLocal;
903 info->type = AsmType::Double();
904 info->index =
static_cast<uint32_t>(param_count + locals->size());
905 locals->push_back(kWasmF64);
906 current_function_builder_->EmitF64Const(-dvalue);
907 current_function_builder_->EmitSetLocal(info->index);
908 }
else if (CheckForUnsigned(&uvalue)) {
909 if (uvalue > 0x7FFFFFFF) {
910 FAIL(
"Numeric literal out of range");
912 info->kind = VarKind::kLocal;
913 info->type = AsmType::Int();
914 info->index =
static_cast<uint32_t>(param_count + locals->size());
915 locals->push_back(kWasmI32);
916 int32_t value = -
static_cast<int32_t
>(uvalue);
917 current_function_builder_->EmitI32Const(value);
918 current_function_builder_->EmitSetLocal(info->index);
920 FAIL(
"Expected variable initial value");
922 }
else if (scanner_.IsGlobal()) {
923 VarInfo* sinfo = GetVarInfo(Consume());
924 if (sinfo->kind == VarKind::kGlobal) {
925 if (sinfo->mutable_variable) {
926 FAIL(
"Initializing from global requires const variable");
928 info->kind = VarKind::kLocal;
929 info->type = sinfo->type;
930 info->index =
static_cast<uint32_t>(param_count + locals->size());
931 if (sinfo->type->IsA(AsmType::Int())) {
932 locals->push_back(kWasmI32);
933 }
else if (sinfo->type->IsA(AsmType::Float())) {
934 locals->push_back(kWasmF32);
935 }
else if (sinfo->type->IsA(AsmType::Double())) {
936 locals->push_back(kWasmF64);
938 FAIL(
"Bad local variable definition");
940 current_function_builder_->EmitWithI32V(kExprGetGlobal,
942 current_function_builder_->EmitSetLocal(info->index);
943 }
else if (sinfo->type->IsA(stdlib_fround_)) {
950 if (CheckForDouble(&dvalue)) {
951 info->kind = VarKind::kLocal;
952 info->type = AsmType::Float();
953 info->index =
static_cast<uint32_t>(param_count + locals->size());
954 locals->push_back(kWasmF32);
958 current_function_builder_->EmitF32Const(dvalue);
959 current_function_builder_->EmitSetLocal(info->index);
960 }
else if (CheckForUnsigned(&uvalue)) {
961 if (uvalue > 0x7FFFFFFF) {
962 FAIL(
"Numeric literal out of range");
964 info->kind = VarKind::kLocal;
965 info->type = AsmType::Float();
966 info->index =
static_cast<uint32_t>(param_count + locals->size());
967 locals->push_back(kWasmF32);
968 int32_t value =
static_cast<int32_t
>(uvalue);
972 float fvalue =
static_cast<float>(value);
973 current_function_builder_->EmitF32Const(fvalue);
974 current_function_builder_->EmitSetLocal(info->index);
976 FAIL(
"Expected variable initial value");
980 FAIL(
"expected fround or const global");
982 }
else if (CheckForDouble(&dvalue)) {
983 info->kind = VarKind::kLocal;
984 info->type = AsmType::Double();
985 info->index =
static_cast<uint32_t>(param_count + locals->size());
986 locals->push_back(kWasmF64);
987 current_function_builder_->EmitF64Const(dvalue);
988 current_function_builder_->EmitSetLocal(info->index);
989 }
else if (CheckForUnsigned(&uvalue)) {
990 info->kind = VarKind::kLocal;
991 info->type = AsmType::Int();
992 info->index =
static_cast<uint32_t>(param_count + locals->size());
993 locals->push_back(kWasmI32);
994 int32_t value =
static_cast<int32_t
>(uvalue);
995 current_function_builder_->EmitI32Const(value);
996 current_function_builder_->EmitSetLocal(info->index);
998 FAIL(
"Expected variable initial value");
1003 scanner_.EnterLocalScope();
1005 scanner_.EnterGlobalScope();
1012 void AsmJsParser::ValidateStatement() {
1013 call_coercion_ =
nullptr;
1016 }
else if (Peek(
';')) {
1017 RECURSE(EmptyStatement());
1018 }
else if (Peek(TOK(
if))) {
1019 RECURSE(IfStatement());
1021 }
else if (Peek(TOK(
return))) {
1023 RECURSE(ReturnStatement());
1024 }
else if (IterationStatement()) {
1026 }
else if (Peek(TOK(
break))) {
1027 RECURSE(BreakStatement());
1028 }
else if (Peek(TOK(
continue))) {
1029 RECURSE(ContinueStatement());
1030 }
else if (Peek(TOK(
switch))) {
1031 RECURSE(SwitchStatement());
1033 RECURSE(ExpressionStatement());
1038 void AsmJsParser::Block() {
1039 bool can_break_to_block = pending_label_ != 0;
1040 if (can_break_to_block) {
1041 Begin(pending_label_);
1045 while (!failed_ && !Peek(
'}')) {
1046 RECURSE(ValidateStatement());
1049 if (can_break_to_block) {
1055 void AsmJsParser::ExpressionStatement() {
1056 if (scanner_.IsGlobal() || scanner_.IsLocal()) {
1061 RECURSE(LabelledStatement());
1067 RECURSE(ret = ValidateExpression());
1068 if (!ret->IsA(AsmType::Void())) {
1069 current_function_builder_->Emit(kExprDrop);
1075 void AsmJsParser::EmptyStatement() { EXPECT_TOKEN(
';'); }
1078 void AsmJsParser::IfStatement() {
1079 EXPECT_TOKEN(TOK(
if));
1081 RECURSE(Expression(AsmType::Int()));
1083 current_function_builder_->EmitWithU8(kExprIf, kLocalVoid);
1085 RECURSE(ValidateStatement());
1086 if (Check(TOK(
else))) {
1087 current_function_builder_->Emit(kExprElse);
1088 RECURSE(ValidateStatement());
1090 current_function_builder_->Emit(kExprEnd);
1095 void AsmJsParser::ReturnStatement() {
1097 EXPECT_TOKEN(TOK(
return));
1099 if (!Peek(
';') && !Peek(
'}')) {
1102 RECURSE(ret = Expression(return_type_));
1103 if (ret->IsA(AsmType::Double())) {
1104 return_type_ = AsmType::Double();
1105 }
else if (ret->IsA(AsmType::Float())) {
1106 return_type_ = AsmType::Float();
1107 }
else if (ret->IsA(AsmType::Signed())) {
1108 return_type_ = AsmType::Signed();
1110 FAIL(
"Invalid return type");
1112 }
else if (return_type_ ==
nullptr) {
1113 return_type_ = AsmType::Void();
1114 }
else if (!return_type_->IsA(AsmType::Void())) {
1115 FAIL(
"Invalid void return type");
1117 current_function_builder_->Emit(kExprReturn);
1122 bool AsmJsParser::IterationStatement() {
1123 if (Peek(TOK(
while))) {
1125 }
else if (Peek(TOK(
do))) {
1127 }
else if (Peek(TOK(
for))) {
1136 void AsmJsParser::WhileStatement() {
1138 Begin(pending_label_);
1140 Loop(pending_label_);
1142 EXPECT_TOKEN(TOK(
while));
1144 RECURSE(Expression(AsmType::Int()));
1147 current_function_builder_->Emit(kExprI32Eqz);
1148 current_function_builder_->EmitWithU8(kExprBrIf, 1);
1150 RECURSE(ValidateStatement());
1152 current_function_builder_->EmitWithU8(kExprBr, 0);
1160 void AsmJsParser::DoStatement() {
1162 Begin(pending_label_);
1166 BareBegin(BlockKind::kLoop, pending_label_);
1167 current_function_builder_->EmitWithU8(kExprBlock, kLocalVoid);
1169 EXPECT_TOKEN(TOK(
do));
1171 RECURSE(ValidateStatement());
1172 EXPECT_TOKEN(TOK(
while));
1176 RECURSE(Expression(AsmType::Int()));
1178 current_function_builder_->Emit(kExprI32Eqz);
1179 current_function_builder_->EmitWithU8(kExprBrIf, 1);
1181 current_function_builder_->EmitWithU8(kExprBr, 0);
1191 void AsmJsParser::ForStatement() {
1192 EXPECT_TOKEN(TOK(
for));
1196 RECURSE(ret = Expression(
nullptr));
1197 if (!ret->IsA(AsmType::Void())) {
1198 current_function_builder_->Emit(kExprDrop);
1203 Begin(pending_label_);
1207 BareBegin(BlockKind::kLoop, pending_label_);
1208 current_function_builder_->EmitWithU8(kExprBlock, kLocalVoid);
1212 RECURSE(Expression(AsmType::Int()));
1213 current_function_builder_->Emit(kExprI32Eqz);
1214 current_function_builder_->EmitWithU8(kExprBrIf, 2);
1218 size_t increment_position = scanner_.Position();
1219 ScanToClosingParenthesis();
1222 RECURSE(ValidateStatement());
1226 size_t end_position = scanner_.Position();
1227 scanner_.Seek(increment_position);
1229 RECURSE(Expression(
nullptr));
1233 current_function_builder_->EmitWithU8(kExprBr, 0);
1234 scanner_.Seek(end_position);
1242 void AsmJsParser::BreakStatement() {
1243 EXPECT_TOKEN(TOK(
break));
1244 AsmJsScanner::token_t label_name = kTokenNone;
1245 if (scanner_.IsGlobal() || scanner_.IsLocal()) {
1247 label_name = Consume();
1249 int depth = FindBreakLabelDepth(label_name);
1251 FAIL(
"Illegal break");
1253 current_function_builder_->Emit(kExprBr);
1254 current_function_builder_->EmitI32V(depth);
1259 void AsmJsParser::ContinueStatement() {
1260 EXPECT_TOKEN(TOK(
continue));
1261 AsmJsScanner::token_t label_name = kTokenNone;
1262 if (scanner_.IsGlobal() || scanner_.IsLocal()) {
1264 label_name = Consume();
1266 int depth = FindContinueLabelDepth(label_name);
1268 FAIL(
"Illegal continue");
1270 current_function_builder_->EmitWithI32V(kExprBr, depth);
1275 void AsmJsParser::LabelledStatement() {
1276 DCHECK(scanner_.IsGlobal() || scanner_.IsLocal());
1278 if (pending_label_ != 0) {
1279 FAIL(
"Double label unsupported");
1281 pending_label_ = scanner_.Token();
1284 RECURSE(ValidateStatement());
1288 void AsmJsParser::SwitchStatement() {
1289 EXPECT_TOKEN(TOK(
switch));
1292 RECURSE(test = Expression(
nullptr));
1293 if (!test->IsA(AsmType::Signed())) {
1294 FAIL(
"Expected signed for switch value");
1298 current_function_builder_->EmitSetLocal(tmp);
1299 Begin(pending_label_);
1302 CachedVector<int32_t> cases(cached_int_vectors_);
1303 GatherCases(&cases);
1305 size_t count = cases.size() + 1;
1306 for (
size_t i = 0;
i < count; ++
i) {
1307 BareBegin(BlockKind::kOther);
1308 current_function_builder_->EmitWithU8(kExprBlock, kLocalVoid);
1311 for (
auto c : cases) {
1312 current_function_builder_->EmitGetLocal(tmp);
1313 current_function_builder_->EmitI32Const(c);
1314 current_function_builder_->Emit(kExprI32Eq);
1315 current_function_builder_->EmitWithI32V(kExprBrIf, table_pos++);
1317 current_function_builder_->EmitWithI32V(kExprBr, table_pos++);
1318 while (!failed_ && Peek(TOK(
case))) {
1319 current_function_builder_->Emit(kExprEnd);
1321 RECURSE(ValidateCase());
1323 current_function_builder_->Emit(kExprEnd);
1325 if (Peek(TOK(
default))) {
1326 RECURSE(ValidateDefault());
1333 void AsmJsParser::ValidateCase() {
1334 EXPECT_TOKEN(TOK(
case));
1335 bool negate =
false;
1340 if (!CheckForUnsigned(&uvalue)) {
1341 FAIL(
"Expected numeric literal");
1344 if ((negate && uvalue > 0x80000000) || (!negate && uvalue > 0x7FFFFFFF)) {
1345 FAIL(
"Numeric literal out of range");
1347 int32_t value =
static_cast<int32_t
>(uvalue);
1348 DCHECK_IMPLIES(negate && uvalue == 0x80000000, value == kMinInt);
1349 if (negate && value != kMinInt) {
1353 while (!failed_ && !Peek(
'}') && !Peek(TOK(
case)) && !Peek(TOK(
default))) {
1354 RECURSE(ValidateStatement());
1359 void AsmJsParser::ValidateDefault() {
1360 EXPECT_TOKEN(TOK(
default));
1362 while (!failed_ && !Peek(
'}')) {
1363 RECURSE(ValidateStatement());
1368 AsmType* AsmJsParser::ValidateExpression() {
1370 RECURSEn(ret = Expression(
nullptr));
1375 AsmType* AsmJsParser::Expression(AsmType* expected) {
1378 RECURSEn(a = AssignmentExpression());
1380 if (a->IsA(AsmType::None())) {
1381 FAILn(
"Expected actual type");
1383 if (!a->IsA(AsmType::Void())) {
1384 current_function_builder_->Emit(kExprDrop);
1391 if (expected !=
nullptr && !a->IsA(expected)) {
1392 FAILn(
"Unexpected type");
1398 AsmType* AsmJsParser::NumericLiteral() {
1399 call_coercion_ =
nullptr;
1400 double dvalue = 0.0;
1402 if (CheckForDouble(&dvalue)) {
1403 current_function_builder_->EmitF64Const(dvalue);
1404 return AsmType::Double();
1405 }
else if (CheckForUnsigned(&uvalue)) {
1406 if (uvalue <= 0x7FFFFFFF) {
1407 current_function_builder_->EmitI32Const(static_cast<int32_t>(uvalue));
1408 return AsmType::FixNum();
1410 current_function_builder_->EmitI32Const(static_cast<int32_t>(uvalue));
1411 return AsmType::Unsigned();
1414 FAILn(
"Expected numeric literal.");
1419 AsmType* AsmJsParser::Identifier() {
1420 call_coercion_ =
nullptr;
1421 if (scanner_.IsLocal()) {
1422 VarInfo* info = GetVarInfo(Consume());
1423 if (info->kind != VarKind::kLocal) {
1424 FAILn(
"Undefined local variable");
1426 current_function_builder_->EmitGetLocal(info->index);
1428 }
else if (scanner_.IsGlobal()) {
1429 VarInfo* info = GetVarInfo(Consume());
1430 if (info->kind != VarKind::kGlobal) {
1431 FAILn(
"Undefined global variable");
1433 current_function_builder_->EmitWithI32V(kExprGetGlobal, VarIndex(info));
1440 AsmType* AsmJsParser::CallExpression() {
1442 if (scanner_.IsGlobal() &&
1443 GetVarInfo(scanner_.Token())->type->IsA(stdlib_fround_)) {
1444 ValidateFloatCoercion();
1445 return AsmType::Float();
1446 }
else if (scanner_.IsGlobal() &&
1447 GetVarInfo(scanner_.Token())->type->IsA(AsmType::Heap())) {
1448 RECURSEn(ret = MemberExpression());
1449 }
else if (Peek(
'(')) {
1450 RECURSEn(ret = ParenthesizedExpression());
1451 }
else if (PeekCall()) {
1452 RECURSEn(ret = ValidateCall());
1453 }
else if (scanner_.IsLocal() || scanner_.IsGlobal()) {
1454 RECURSEn(ret = Identifier());
1456 RECURSEn(ret = NumericLiteral());
1462 AsmType* AsmJsParser::MemberExpression() {
1463 call_coercion_ =
nullptr;
1464 RECURSEn(ValidateHeapAccess());
1465 DCHECK_NOT_NULL(heap_access_type_);
1467 inside_heap_assignment_ =
true;
1468 return heap_access_type_->StoreType();
1470 #define V(array_type, wasmload, wasmstore, type) \ 1471 if (heap_access_type_->IsA(AsmType::array_type())) { \ 1472 current_function_builder_->Emit(kExpr##type##AsmjsLoad##wasmload); \ 1473 return heap_access_type_->LoadType(); \ 1475 STDLIB_ARRAY_TYPE_LIST(
V)
1477 FAILn(
"Expected valid heap load");
1482 AsmType* AsmJsParser::AssignmentExpression() {
1484 if (scanner_.IsGlobal() &&
1485 GetVarInfo(scanner_.Token())->type->IsA(AsmType::Heap())) {
1486 RECURSEn(ret = ConditionalExpression());
1488 if (!inside_heap_assignment_) {
1489 FAILn(
"Invalid assignment target");
1491 inside_heap_assignment_ =
false;
1492 DCHECK_NOT_NULL(heap_access_type_);
1493 AsmType* heap_type = heap_access_type_;
1496 RECURSEn(value = AssignmentExpression());
1497 if (!value->IsA(ret)) {
1498 FAILn(
"Illegal type stored to heap view");
1500 if (heap_type->IsA(AsmType::Float32Array()) &&
1501 value->IsA(AsmType::DoubleQ())) {
1503 current_function_builder_->Emit(kExprF32ConvertF64);
1505 if (heap_type->IsA(AsmType::Float64Array()) &&
1506 value->IsA(AsmType::FloatQ())) {
1508 current_function_builder_->Emit(kExprF64ConvertF32);
1511 #define V(array_type, wasmload, wasmstore, type) \ 1512 if (heap_type->IsA(AsmType::array_type())) { \ 1513 current_function_builder_->Emit(kExpr##type##AsmjsStore##wasmstore); \ 1516 STDLIB_ARRAY_TYPE_LIST(
V)
1519 }
else if (scanner_.IsLocal() || scanner_.IsGlobal()) {
1520 bool is_local = scanner_.IsLocal();
1521 VarInfo* info = GetVarInfo(scanner_.Token());
1528 if (info->kind == VarKind::kUnused) {
1529 FAILn(
"Undeclared assignment target");
1531 if (!info->mutable_variable) {
1532 FAILn(
"Expected mutable variable in assignment");
1534 DCHECK(is_local ? info->kind == VarKind::kLocal
1535 : info->kind == VarKind::kGlobal);
1537 RECURSEn(value = AssignmentExpression());
1538 if (!value->IsA(ret)) {
1539 FAILn(
"Type mismatch in assignment");
1541 if (info->kind == VarKind::kLocal) {
1542 current_function_builder_->EmitTeeLocal(info->index);
1543 }
else if (info->kind == VarKind::kGlobal) {
1544 current_function_builder_->EmitWithU32V(kExprSetGlobal, VarIndex(info));
1545 current_function_builder_->EmitWithU32V(kExprGetGlobal, VarIndex(info));
1552 RECURSEn(ret = ConditionalExpression());
1554 RECURSEn(ret = ConditionalExpression());
1560 AsmType* AsmJsParser::UnaryExpression() {
1564 if (CheckForUnsigned(&uvalue)) {
1566 if (uvalue <= 0x80000000) {
1567 current_function_builder_->EmitI32Const(-static_cast<int32_t>(uvalue));
1569 FAILn(
"Integer numeric literal out of range.");
1571 ret = AsmType::Signed();
1573 RECURSEn(ret = UnaryExpression());
1574 if (ret->IsA(AsmType::Int())) {
1575 TemporaryVariableScope tmp(
this);
1576 current_function_builder_->EmitSetLocal(tmp.get());
1577 current_function_builder_->EmitI32Const(0);
1578 current_function_builder_->EmitGetLocal(tmp.get());
1579 current_function_builder_->Emit(kExprI32Sub);
1580 ret = AsmType::Intish();
1581 }
else if (ret->IsA(AsmType::DoubleQ())) {
1582 current_function_builder_->Emit(kExprF64Neg);
1583 ret = AsmType::Double();
1584 }
else if (ret->IsA(AsmType::FloatQ())) {
1585 current_function_builder_->Emit(kExprF32Neg);
1586 ret = AsmType::Floatish();
1588 FAILn(
"expected int/double?/float?");
1591 }
else if (Peek(
'+')) {
1592 call_coercion_ = AsmType::Double();
1593 call_coercion_position_ = scanner_.Position();
1595 RECURSEn(ret = UnaryExpression());
1597 if (ret->IsA(AsmType::Signed())) {
1598 current_function_builder_->Emit(kExprF64SConvertI32);
1599 ret = AsmType::Double();
1600 }
else if (ret->IsA(AsmType::Unsigned())) {
1601 current_function_builder_->Emit(kExprF64UConvertI32);
1602 ret = AsmType::Double();
1603 }
else if (ret->IsA(AsmType::DoubleQ())) {
1604 ret = AsmType::Double();
1605 }
else if (ret->IsA(AsmType::FloatQ())) {
1606 current_function_builder_->Emit(kExprF64ConvertF32);
1607 ret = AsmType::Double();
1609 FAILn(
"expected signed/unsigned/double?/float?");
1611 }
else if (Check(
'!')) {
1612 RECURSEn(ret = UnaryExpression());
1613 if (!ret->IsA(AsmType::Int())) {
1614 FAILn(
"expected int");
1616 current_function_builder_->Emit(kExprI32Eqz);
1617 }
else if (Check(
'~')) {
1619 RECURSEn(ret = UnaryExpression());
1620 if (ret->IsA(AsmType::Double())) {
1621 current_function_builder_->Emit(kExprI32AsmjsSConvertF64);
1622 }
else if (ret->IsA(AsmType::FloatQ())) {
1623 current_function_builder_->Emit(kExprI32AsmjsSConvertF32);
1625 FAILn(
"expected double or float?");
1627 ret = AsmType::Signed();
1629 RECURSEn(ret = UnaryExpression());
1630 if (!ret->IsA(AsmType::Intish())) {
1631 FAILn(
"operator ~ expects intish");
1633 current_function_builder_->EmitI32Const(0xFFFFFFFF);
1634 current_function_builder_->Emit(kExprI32Xor);
1635 ret = AsmType::Signed();
1638 RECURSEn(ret = CallExpression());
1644 AsmType* AsmJsParser::MultiplicativeExpression() {
1647 if (CheckForUnsignedBelow(0x100000, &uvalue)) {
1650 RECURSEn(a = UnaryExpression());
1651 if (!a->IsA(AsmType::Int())) {
1652 FAILn(
"Expected int");
1654 int32_t value =
static_cast<int32_t
>(uvalue);
1655 current_function_builder_->EmitI32Const(value);
1656 current_function_builder_->Emit(kExprI32Mul);
1657 return AsmType::Intish();
1660 RECURSEn(a = UnaryExpression());
1662 }
else if (Check(
'-')) {
1663 if (CheckForUnsignedBelow(0x100000, &uvalue)) {
1664 int32_t value = -
static_cast<int32_t
>(uvalue);
1665 current_function_builder_->EmitI32Const(value);
1668 RECURSEn(a = UnaryExpression());
1669 if (!a->IsA(AsmType::Int())) {
1670 FAILn(
"Expected int");
1672 current_function_builder_->Emit(kExprI32Mul);
1673 return AsmType::Intish();
1675 a = AsmType::Signed();
1678 RECURSEn(a = UnaryExpression());
1681 RECURSEn(a = UnaryExpression());
1687 if (CheckForUnsigned(&uvalue)) {
1688 if (uvalue >= 0x100000) {
1689 FAILn(
"Constant multiple out of range");
1691 if (!a->IsA(AsmType::Int())) {
1692 FAILn(
"Integer multiply of expects int");
1694 int32_t value = -
static_cast<int32_t
>(uvalue);
1695 current_function_builder_->EmitI32Const(value);
1696 current_function_builder_->Emit(kExprI32Mul);
1697 return AsmType::Intish();
1700 }
else if (CheckForUnsigned(&uvalue)) {
1701 if (uvalue >= 0x100000) {
1702 FAILn(
"Constant multiple out of range");
1704 if (!a->IsA(AsmType::Int())) {
1705 FAILn(
"Integer multiply of expects int");
1707 int32_t value =
static_cast<int32_t
>(uvalue);
1708 current_function_builder_->EmitI32Const(value);
1709 current_function_builder_->Emit(kExprI32Mul);
1710 return AsmType::Intish();
1713 RECURSEn(b = UnaryExpression());
1714 if (a->IsA(AsmType::DoubleQ()) && b->IsA(AsmType::DoubleQ())) {
1715 current_function_builder_->Emit(kExprF64Mul);
1716 a = AsmType::Double();
1717 }
else if (a->IsA(AsmType::FloatQ()) && b->IsA(AsmType::FloatQ())) {
1718 current_function_builder_->Emit(kExprF32Mul);
1719 a = AsmType::Floatish();
1721 FAILn(
"expected doubles or floats");
1723 }
else if (Check(
'/')) {
1725 RECURSEn(b = UnaryExpression());
1726 if (a->IsA(AsmType::DoubleQ()) && b->IsA(AsmType::DoubleQ())) {
1727 current_function_builder_->Emit(kExprF64Div);
1728 a = AsmType::Double();
1729 }
else if (a->IsA(AsmType::FloatQ()) && b->IsA(AsmType::FloatQ())) {
1730 current_function_builder_->Emit(kExprF32Div);
1731 a = AsmType::Floatish();
1732 }
else if (a->IsA(AsmType::Signed()) && b->IsA(AsmType::Signed())) {
1733 current_function_builder_->Emit(kExprI32AsmjsDivS);
1734 a = AsmType::Intish();
1735 }
else if (a->IsA(AsmType::Unsigned()) && b->IsA(AsmType::Unsigned())) {
1736 current_function_builder_->Emit(kExprI32AsmjsDivU);
1737 a = AsmType::Intish();
1739 FAILn(
"expected doubles or floats");
1741 }
else if (Check(
'%')) {
1743 RECURSEn(b = UnaryExpression());
1744 if (a->IsA(AsmType::DoubleQ()) && b->IsA(AsmType::DoubleQ())) {
1745 current_function_builder_->Emit(kExprF64Mod);
1746 a = AsmType::Double();
1747 }
else if (a->IsA(AsmType::Signed()) && b->IsA(AsmType::Signed())) {
1748 current_function_builder_->Emit(kExprI32AsmjsRemS);
1749 a = AsmType::Intish();
1750 }
else if (a->IsA(AsmType::Unsigned()) && b->IsA(AsmType::Unsigned())) {
1751 current_function_builder_->Emit(kExprI32AsmjsRemU);
1752 a = AsmType::Intish();
1754 FAILn(
"expected doubles or floats");
1764 AsmType* AsmJsParser::AdditiveExpression() {
1766 RECURSEn(a = MultiplicativeExpression());
1771 RECURSEn(b = MultiplicativeExpression());
1772 if (a->IsA(AsmType::Double()) && b->IsA(AsmType::Double())) {
1773 current_function_builder_->Emit(kExprF64Add);
1774 a = AsmType::Double();
1775 }
else if (a->IsA(AsmType::FloatQ()) && b->IsA(AsmType::FloatQ())) {
1776 current_function_builder_->Emit(kExprF32Add);
1777 a = AsmType::Floatish();
1778 }
else if (a->IsA(AsmType::Int()) && b->IsA(AsmType::Int())) {
1779 current_function_builder_->Emit(kExprI32Add);
1780 a = AsmType::Intish();
1782 }
else if (a->IsA(AsmType::Intish()) && b->IsA(AsmType::Intish())) {
1786 if (n > (1 << 20)) {
1787 FAILn(
"more than 2^20 additive values");
1789 current_function_builder_->Emit(kExprI32Add);
1791 FAILn(
"illegal types for +");
1793 }
else if (Check(
'-')) {
1795 RECURSEn(b = MultiplicativeExpression());
1796 if (a->IsA(AsmType::Double()) && b->IsA(AsmType::Double())) {
1797 current_function_builder_->Emit(kExprF64Sub);
1798 a = AsmType::Double();
1799 }
else if (a->IsA(AsmType::FloatQ()) && b->IsA(AsmType::FloatQ())) {
1800 current_function_builder_->Emit(kExprF32Sub);
1801 a = AsmType::Floatish();
1802 }
else if (a->IsA(AsmType::Int()) && b->IsA(AsmType::Int())) {
1803 current_function_builder_->Emit(kExprI32Sub);
1804 a = AsmType::Intish();
1806 }
else if (a->IsA(AsmType::Intish()) && b->IsA(AsmType::Intish())) {
1810 if (n > (1 << 20)) {
1811 FAILn(
"more than 2^20 additive values");
1813 current_function_builder_->Emit(kExprI32Sub);
1815 FAILn(
"illegal types for +");
1825 AsmType* AsmJsParser::ShiftExpression() {
1826 AsmType* a =
nullptr;
1827 RECURSEn(a = AdditiveExpression());
1828 heap_access_shift_position_ = kNoHeapAccessShift;
1832 switch (scanner_.Token()) {
1834 EXPECT_TOKENn(TOK(SAR));
1835 heap_access_shift_position_ = kNoHeapAccessShift;
1842 if (a->IsA(AsmType::Intish()) && CheckForUnsigned(&shift_imm)) {
1843 old_pos = scanner_.Position();
1844 old_code = current_function_builder_->GetPosition();
1848 AsmType* b =
nullptr;
1849 RECURSEn(b = AdditiveExpression());
1851 if (imm && old_pos == scanner_.Position()) {
1852 heap_access_shift_position_ = old_code;
1853 heap_access_shift_value_ = shift_imm;
1855 if (!(a->IsA(AsmType::Intish()) && b->IsA(AsmType::Intish()))) {
1856 FAILn(
"Expected intish for operator >>.");
1858 current_function_builder_->Emit(kExprI32ShrS);
1859 a = AsmType::Signed();
1862 #define HANDLE_CASE(op, opcode, name, result) \ 1864 EXPECT_TOKENn(TOK(op)); \ 1865 heap_access_shift_position_ = kNoHeapAccessShift; \ 1866 AsmType* b = nullptr; \ 1867 RECURSEn(b = AdditiveExpression()); \ 1868 if (!(a->IsA(AsmType::Intish()) && b->IsA(AsmType::Intish()))) { \ 1869 FAILn("Expected intish for operator " #name "."); \ 1871 current_function_builder_->Emit(kExpr##opcode); \ 1872 a = AsmType::result(); \ 1875 HANDLE_CASE(SHL, I32Shl,
"<<", Signed);
1876 HANDLE_CASE(SHR, I32ShrU,
">>>", Unsigned);
1885 AsmType* AsmJsParser::RelationalExpression() {
1886 AsmType* a =
nullptr;
1887 RECURSEn(a = ShiftExpression());
1889 switch (scanner_.Token()) {
1890 #define HANDLE_CASE(op, sop, uop, dop, fop, name) \ 1892 EXPECT_TOKENn(op); \ 1893 AsmType* b = nullptr; \ 1894 RECURSEn(b = ShiftExpression()); \ 1895 if (a->IsA(AsmType::Signed()) && b->IsA(AsmType::Signed())) { \ 1896 current_function_builder_->Emit(kExpr##sop); \ 1897 } else if (a->IsA(AsmType::Unsigned()) && b->IsA(AsmType::Unsigned())) { \ 1898 current_function_builder_->Emit(kExpr##uop); \ 1899 } else if (a->IsA(AsmType::Double()) && b->IsA(AsmType::Double())) { \ 1900 current_function_builder_->Emit(kExpr##dop); \ 1901 } else if (a->IsA(AsmType::Float()) && b->IsA(AsmType::Float())) { \ 1902 current_function_builder_->Emit(kExpr##fop); \ 1904 FAILn("Expected signed, unsigned, double, or float for operator " #name \ 1907 a = AsmType::Int(); \ 1910 HANDLE_CASE(
'<', I32LtS, I32LtU, F64Lt, F32Lt,
"<");
1911 HANDLE_CASE(TOK(LE), I32LeS, I32LeU, F64Le, F32Le,
"<=");
1912 HANDLE_CASE(
'>', I32GtS, I32GtU, F64Gt, F32Gt,
">");
1913 HANDLE_CASE(TOK(GE), I32GeS, I32GeU, F64Ge, F32Ge,
">=");
1922 AsmType* AsmJsParser::EqualityExpression() {
1923 AsmType* a =
nullptr;
1924 RECURSEn(a = RelationalExpression());
1926 switch (scanner_.Token()) {
1927 #define HANDLE_CASE(op, sop, uop, dop, fop, name) \ 1929 EXPECT_TOKENn(op); \ 1930 AsmType* b = nullptr; \ 1931 RECURSEn(b = RelationalExpression()); \ 1932 if (a->IsA(AsmType::Signed()) && b->IsA(AsmType::Signed())) { \ 1933 current_function_builder_->Emit(kExpr##sop); \ 1934 } else if (a->IsA(AsmType::Unsigned()) && b->IsA(AsmType::Unsigned())) { \ 1935 current_function_builder_->Emit(kExpr##uop); \ 1936 } else if (a->IsA(AsmType::Double()) && b->IsA(AsmType::Double())) { \ 1937 current_function_builder_->Emit(kExpr##dop); \ 1938 } else if (a->IsA(AsmType::Float()) && b->IsA(AsmType::Float())) { \ 1939 current_function_builder_->Emit(kExpr##fop); \ 1941 FAILn("Expected signed, unsigned, double, or float for operator " #name \ 1944 a = AsmType::Int(); \ 1947 HANDLE_CASE(TOK(EQ), I32Eq, I32Eq, F64Eq, F32Eq,
"==");
1948 HANDLE_CASE(TOK(NE), I32Ne, I32Ne, F64Ne, F32Ne,
"!=");
1957 AsmType* AsmJsParser::BitwiseANDExpression() {
1958 AsmType* a =
nullptr;
1959 RECURSEn(a = EqualityExpression());
1960 while (Check(
'&')) {
1961 AsmType* b =
nullptr;
1962 RECURSEn(b = EqualityExpression());
1963 if (a->IsA(AsmType::Intish()) && b->IsA(AsmType::Intish())) {
1964 current_function_builder_->Emit(kExprI32And);
1965 a = AsmType::Signed();
1967 FAILn(
"Expected intish for operator &.");
1974 AsmType* AsmJsParser::BitwiseXORExpression() {
1975 AsmType* a =
nullptr;
1976 RECURSEn(a = BitwiseANDExpression());
1977 while (Check(
'^')) {
1978 AsmType* b =
nullptr;
1979 RECURSEn(b = BitwiseANDExpression());
1980 if (a->IsA(AsmType::Intish()) && b->IsA(AsmType::Intish())) {
1981 current_function_builder_->Emit(kExprI32Xor);
1982 a = AsmType::Signed();
1984 FAILn(
"Expected intish for operator &.");
1991 AsmType* AsmJsParser::BitwiseORExpression() {
1992 AsmType* a =
nullptr;
1993 call_coercion_deferred_position_ = scanner_.Position();
1994 RECURSEn(a = BitwiseXORExpression());
1995 while (Check(
'|')) {
1996 AsmType* b =
nullptr;
2000 bool requires_zero = call_coercion_deferred_->IsExactly(AsmType::Signed());
2001 call_coercion_deferred_ =
nullptr;
2006 if (a->IsA(AsmType::Intish()) && CheckForZero()) {
2007 old_pos = scanner_.Position();
2008 old_code = current_function_builder_->GetPosition();
2012 RECURSEn(b = BitwiseXORExpression());
2014 if (zero && old_pos == scanner_.Position()) {
2015 current_function_builder_->DeleteCodeAfter(old_code);
2016 a = AsmType::Signed();
2020 if (requires_zero) {
2021 FAILn(
"Expected |0 type annotation for call");
2023 if (a->IsA(AsmType::Intish()) && b->IsA(AsmType::Intish())) {
2024 current_function_builder_->Emit(kExprI32Ior);
2025 a = AsmType::Signed();
2027 FAILn(
"Expected intish for operator |.");
2030 DCHECK_NULL(call_coercion_deferred_);
2035 AsmType* AsmJsParser::ConditionalExpression() {
2036 AsmType* test =
nullptr;
2037 RECURSEn(test = BitwiseORExpression());
2039 if (!test->IsA(AsmType::Int())) {
2040 FAILn(
"Expected int in condition of ternary operator.");
2042 current_function_builder_->EmitWithU8(kExprIf, kLocalI32);
2043 size_t fixup = current_function_builder_->GetPosition() -
2045 AsmType* cons =
nullptr;
2046 RECURSEn(cons = AssignmentExpression());
2047 current_function_builder_->Emit(kExprElse);
2049 AsmType* alt =
nullptr;
2050 RECURSEn(alt = AssignmentExpression());
2051 current_function_builder_->Emit(kExprEnd);
2052 if (cons->IsA(AsmType::Int()) && alt->IsA(AsmType::Int())) {
2053 current_function_builder_->FixupByte(fixup, kLocalI32);
2054 return AsmType::Int();
2055 }
else if (cons->IsA(AsmType::Double()) && alt->IsA(AsmType::Double())) {
2056 current_function_builder_->FixupByte(fixup, kLocalF64);
2057 return AsmType::Double();
2058 }
else if (cons->IsA(AsmType::Float()) && alt->IsA(AsmType::Float())) {
2059 current_function_builder_->FixupByte(fixup, kLocalF32);
2060 return AsmType::Float();
2062 FAILn(
"Type mismatch in ternary operator.");
2070 AsmType* AsmJsParser::ParenthesizedExpression() {
2071 call_coercion_ =
nullptr;
2074 RECURSEn(ret = Expression(
nullptr));
2080 AsmType* AsmJsParser::ValidateCall() {
2081 AsmType* return_type = call_coercion_;
2082 call_coercion_ =
nullptr;
2083 size_t call_pos = scanner_.Position();
2084 size_t to_number_pos = call_coercion_position_;
2085 bool allow_peek = (call_coercion_deferred_position_ == scanner_.Position());
2086 AsmJsScanner::token_t function_name = Consume();
2092 base::Optional<TemporaryVariableScope> tmp;
2094 RECURSEn(EqualityExpression());
2097 if (!CheckForUnsigned(&mask)) {
2098 FAILn(
"Expected mask literal");
2100 if (!base::bits::IsPowerOfTwo(mask + 1)) {
2101 FAILn(
"Expected power of 2 mask");
2103 current_function_builder_->EmitI32Const(mask);
2104 current_function_builder_->Emit(kExprI32And);
2106 VarInfo* function_info = GetVarInfo(function_name);
2107 if (function_info->kind == VarKind::kUnused) {
2108 uint32_t index = module_builder_->AllocateIndirectFunctions(mask + 1);
2109 if (index == std::numeric_limits<uint32_t>::max()) {
2110 FAILn(
"Exceeded maximum function table size");
2112 function_info->kind = VarKind::kTable;
2113 function_info->mask = mask;
2114 function_info->index = index;
2115 function_info->mutable_variable =
false;
2117 if (function_info->kind != VarKind::kTable) {
2118 FAILn(
"Expected call table");
2120 if (function_info->mask != mask) {
2121 FAILn(
"Mask size mismatch");
2124 current_function_builder_->EmitI32Const(function_info->index);
2125 current_function_builder_->Emit(kExprI32Add);
2128 current_function_builder_->EmitSetLocal(tmp->get());
2130 call_pos = scanner_.Position();
2132 VarInfo* function_info = GetVarInfo(function_name);
2133 if (function_info->kind == VarKind::kUnused) {
2134 function_info->kind = VarKind::kFunction;
2135 function_info->function_builder = module_builder_->AddFunction();
2136 function_info->index = function_info->function_builder->func_index();
2137 function_info->mutable_variable =
false;
2139 if (function_info->kind != VarKind::kFunction &&
2140 function_info->kind < VarKind::kImportedFunction) {
2141 FAILn(
"Expected function as call target");
2147 CachedVector<AsmType*> param_types(cached_asm_type_p_vectors_);
2148 CachedVector<AsmType*> param_specific_types(cached_asm_type_p_vectors_);
2150 while (!failed_ && !Peek(
')')) {
2152 RECURSEn(t = AssignmentExpression());
2153 param_specific_types.push_back(t);
2154 if (t->IsA(AsmType::Int())) {
2155 param_types.push_back(AsmType::Int());
2156 }
else if (t->IsA(AsmType::Float())) {
2157 param_types.push_back(AsmType::Float());
2158 }
else if (t->IsA(AsmType::Double())) {
2159 param_types.push_back(AsmType::Double());
2161 FAILn(
"Bad function argument type");
2170 VarInfo* function_info = GetVarInfo(function_name);
2188 if (allow_peek && Peek(
'|') &&
2189 function_info->kind <= VarKind::kImportedFunction &&
2190 (return_type ==
nullptr || return_type->IsA(AsmType::Float()))) {
2191 DCHECK_NULL(call_coercion_deferred_);
2192 call_coercion_deferred_ = AsmType::Signed();
2193 to_number_pos = scanner_.Position();
2194 return_type = AsmType::Signed();
2195 }
else if (return_type ==
nullptr) {
2196 to_number_pos = call_pos;
2197 return_type = AsmType::Void();
2201 AsmType* function_type = AsmType::Function(zone(), return_type);
2202 for (
auto t : param_types) {
2203 function_type->AsFunctionType()->AddArgument(t);
2205 FunctionSig* sig = ConvertSignature(return_type, param_types);
2206 uint32_t signature_index = module_builder_->AddSignature(sig);
2211 if (function_info->kind == VarKind::kImportedFunction) {
2212 for (
auto t : param_specific_types) {
2213 if (!t->IsA(AsmType::Extern())) {
2214 FAILn(
"Imported function args must be type extern");
2217 if (return_type->IsA(AsmType::Float())) {
2218 FAILn(
"Imported function can't be called as float");
2220 DCHECK_NOT_NULL(function_info->import);
2223 auto it = function_info->import->cache.find(*sig);
2224 if (it != function_info->import->cache.end()) {
2226 DCHECK(function_info->function_defined);
2229 module_builder_->AddImport(function_info->import->function_name, sig);
2230 function_info->import->cache[*sig] = index;
2231 function_info->function_defined =
true;
2233 current_function_builder_->AddAsmWasmOffset(call_pos, to_number_pos);
2234 current_function_builder_->EmitWithU32V(kExprCallFunction, index);
2235 }
else if (function_info->kind > VarKind::kImportedFunction) {
2236 AsmCallableType* callable = function_info->type->AsCallableType();
2238 FAILn(
"Expected callable function");
2241 if (callable->CanBeInvokedWith(return_type, param_specific_types)) {
2243 }
else if (callable->CanBeInvokedWith(AsmType::Float(),
2244 param_specific_types)) {
2245 return_type = AsmType::Float();
2246 }
else if (callable->CanBeInvokedWith(AsmType::Floatish(),
2247 param_specific_types)) {
2248 return_type = AsmType::Floatish();
2249 }
else if (callable->CanBeInvokedWith(AsmType::Double(),
2250 param_specific_types)) {
2251 return_type = AsmType::Double();
2252 }
else if (callable->CanBeInvokedWith(AsmType::Signed(),
2253 param_specific_types)) {
2254 return_type = AsmType::Signed();
2255 }
else if (callable->CanBeInvokedWith(AsmType::Unsigned(),
2256 param_specific_types)) {
2257 return_type = AsmType::Unsigned();
2259 FAILn(
"Function use doesn't match definition");
2261 switch (function_info->kind) {
2262 #define V(name, Name, op, sig) \ 2263 case VarKind::kMath##Name: \ 2264 current_function_builder_->Emit(op); \ 2266 STDLIB_MATH_FUNCTION_MONOMORPHIC_LIST(
V)
2268 #define V(name, Name, op, sig) \ 2269 case VarKind::kMath##Name: \ 2270 if (param_specific_types[0]->IsA(AsmType::DoubleQ())) { \ 2271 current_function_builder_->Emit(kExprF64##Name); \ 2272 } else if (param_specific_types[0]->IsA(AsmType::FloatQ())) { \ 2273 current_function_builder_->Emit(kExprF32##Name); \ 2278 STDLIB_MATH_FUNCTION_CEIL_LIKE_LIST(
V)
2280 case VarKind::kMathMin:
2281 case VarKind::kMathMax:
2282 if (param_specific_types[0]->IsA(AsmType::Double())) {
2283 for (
size_t i = 1;
i < param_specific_types.size(); ++
i) {
2284 if (function_info->kind == VarKind::kMathMin) {
2285 current_function_builder_->Emit(kExprF64Min);
2287 current_function_builder_->Emit(kExprF64Max);
2290 }
else if (param_specific_types[0]->IsA(AsmType::Float())) {
2293 for (
size_t i = 1;
i < param_specific_types.size(); ++
i) {
2294 if (function_info->kind == VarKind::kMathMin) {
2295 current_function_builder_->Emit(kExprF32Min);
2297 current_function_builder_->Emit(kExprF32Max);
2300 }
else if (param_specific_types[0]->IsA(AsmType::Signed())) {
2301 TemporaryVariableScope tmp_x(
this);
2302 TemporaryVariableScope tmp_y(
this);
2303 for (
size_t i = 1;
i < param_specific_types.size(); ++
i) {
2304 current_function_builder_->EmitSetLocal(tmp_x.get());
2305 current_function_builder_->EmitTeeLocal(tmp_y.get());
2306 current_function_builder_->EmitGetLocal(tmp_x.get());
2307 if (function_info->kind == VarKind::kMathMin) {
2308 current_function_builder_->Emit(kExprI32GeS);
2310 current_function_builder_->Emit(kExprI32LeS);
2312 current_function_builder_->EmitWithU8(kExprIf, kLocalI32);
2313 current_function_builder_->EmitGetLocal(tmp_x.get());
2314 current_function_builder_->Emit(kExprElse);
2315 current_function_builder_->EmitGetLocal(tmp_y.get());
2316 current_function_builder_->Emit(kExprEnd);
2323 case VarKind::kMathAbs:
2324 if (param_specific_types[0]->IsA(AsmType::Signed())) {
2325 TemporaryVariableScope tmp(
this);
2326 current_function_builder_->EmitTeeLocal(tmp.get());
2327 current_function_builder_->EmitGetLocal(tmp.get());
2328 current_function_builder_->EmitI32Const(31);
2329 current_function_builder_->Emit(kExprI32ShrS);
2330 current_function_builder_->EmitTeeLocal(tmp.get());
2331 current_function_builder_->Emit(kExprI32Xor);
2332 current_function_builder_->EmitGetLocal(tmp.get());
2333 current_function_builder_->Emit(kExprI32Sub);
2334 }
else if (param_specific_types[0]->IsA(AsmType::DoubleQ())) {
2335 current_function_builder_->Emit(kExprF64Abs);
2336 }
else if (param_specific_types[0]->IsA(AsmType::FloatQ())) {
2337 current_function_builder_->Emit(kExprF32Abs);
2343 case VarKind::kMathFround:
2352 DCHECK(function_info->kind == VarKind::kFunction ||
2353 function_info->kind == VarKind::kTable);
2354 if (function_info->type->IsA(AsmType::None())) {
2355 function_info->type = function_type;
2357 AsmCallableType* callable = function_info->type->AsCallableType();
2359 !callable->CanBeInvokedWith(return_type, param_specific_types)) {
2360 FAILn(
"Function use doesn't match definition");
2363 if (function_info->kind == VarKind::kTable) {
2364 current_function_builder_->EmitGetLocal(tmp->get());
2365 current_function_builder_->AddAsmWasmOffset(call_pos, to_number_pos);
2366 current_function_builder_->Emit(kExprCallIndirect);
2367 current_function_builder_->EmitU32V(signature_index);
2368 current_function_builder_->EmitU32V(0);
2370 current_function_builder_->AddAsmWasmOffset(call_pos, to_number_pos);
2371 current_function_builder_->Emit(kExprCallFunction);
2372 current_function_builder_->EmitDirectCallIndex(function_info->index);
2380 bool AsmJsParser::PeekCall() {
2381 if (!scanner_.IsGlobal()) {
2384 if (GetVarInfo(scanner_.Token())->kind == VarKind::kFunction) {
2387 if (GetVarInfo(scanner_.Token())->kind >= VarKind::kImportedFunction) {
2390 if (GetVarInfo(scanner_.Token())->kind == VarKind::kUnused ||
2391 GetVarInfo(scanner_.Token())->kind == VarKind::kTable) {
2393 if (Peek(
'(') || Peek(
'[')) {
2403 void AsmJsParser::ValidateHeapAccess() {
2404 VarInfo* info = GetVarInfo(Consume());
2405 int32_t size = info->type->ElementSizeInBytes();
2408 if (CheckForUnsigned(&offset)) {
2412 if (offset > 0x7FFFFFFF ||
2413 static_cast<uint64_t>(offset) * static_cast<uint64_t>(size) >
2415 FAIL(
"Heap access out of range");
2418 current_function_builder_->EmitI32Const(
2419 static_cast<uint32_t>(offset * size));
2421 heap_access_type_ = info->type;
2427 AsmType* index_type;
2428 if (info->type->IsA(AsmType::Int8Array()) ||
2429 info->type->IsA(AsmType::Uint8Array())) {
2430 RECURSE(index_type = Expression(
nullptr));
2432 RECURSE(index_type = ShiftExpression());
2433 if (heap_access_shift_position_ == kNoHeapAccessShift) {
2434 FAIL(
"Expected shift of word size");
2436 if (heap_access_shift_value_ > 3) {
2437 FAIL(
"Expected valid heap access shift");
2439 if ((1 << heap_access_shift_value_) != size) {
2440 FAIL(
"Expected heap access shift to match heap view");
2443 current_function_builder_->DeleteCodeAfter(heap_access_shift_position_);
2445 current_function_builder_->EmitI32Const(~(size - 1));
2446 current_function_builder_->Emit(kExprI32And);
2448 if (!index_type->IsA(AsmType::Intish())) {
2449 FAIL(
"Expected intish index");
2453 heap_access_type_ = info->type;
2457 void AsmJsParser::ValidateFloatCoercion() {
2458 if (!scanner_.IsGlobal() ||
2459 !GetVarInfo(scanner_.Token())->type->IsA(stdlib_fround_)) {
2460 FAIL(
"Expected fround");
2464 call_coercion_ = AsmType::Float();
2467 call_coercion_position_ = scanner_.Position();
2469 RECURSE(ret = ValidateExpression());
2470 if (ret->IsA(AsmType::Floatish())) {
2472 }
else if (ret->IsA(AsmType::DoubleQ())) {
2473 current_function_builder_->Emit(kExprF32ConvertF64);
2474 }
else if (ret->IsA(AsmType::Signed())) {
2475 current_function_builder_->Emit(kExprF32SConvertI32);
2476 }
else if (ret->IsA(AsmType::Unsigned())) {
2477 current_function_builder_->Emit(kExprF32UConvertI32);
2479 FAIL(
"Illegal conversion to float");
2484 void AsmJsParser::ScanToClosingParenthesis() {
2489 }
else if (Peek(
')')) {
2494 }
else if (Peek(AsmJsScanner::kEndOfInput)) {
2501 void AsmJsParser::GatherCases(ZoneVector<int32_t>* cases) {
2502 size_t start = scanner_.Position();
2507 }
else if (Peek(
'}')) {
2512 }
else if (depth == 1 && Peek(TOK(
case))) {
2515 bool negate =
false;
2516 if (Check(
'-')) negate =
true;
2517 if (!CheckForUnsigned(&uvalue)) {
2520 int32_t value =
static_cast<int32_t
>(uvalue);
2521 DCHECK_IMPLIES(negate && uvalue == 0x80000000, value == kMinInt);
2522 if (negate && value != kMinInt) {
2525 cases->push_back(value);
2526 }
else if (Peek(AsmJsScanner::kEndOfInput) ||
2527 Peek(AsmJsScanner::kParseError)) {
2532 scanner_.Seek(start);