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