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 3720 : AsmJsParser::AsmJsParser(Zone* zone, uintptr_t stack_limit,
73 : Utf16CharacterStream* stream)
74 : : zone_(zone),
75 : scanner_(stream),
76 3721 : 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 18604 : global_imports_(zone) {
93 3721 : module_builder_->SetMinMemorySize(0);
94 3718 : InitializeStdlibTypes();
95 3717 : }
96 :
97 44637 : void AsmJsParser::InitializeStdlibTypes() {
98 : auto* d = AsmType::Double();
99 : auto* dq = AsmType::DoubleQ();
100 3719 : stdlib_dq2d_ = AsmType::Function(zone(), d);
101 : stdlib_dq2d_->AsFunctionType()->AddArgument(dq);
102 :
103 3721 : stdlib_dqdq2d_ = AsmType::Function(zone(), d);
104 : stdlib_dqdq2d_->AsFunctionType()->AddArgument(dq);
105 3721 : stdlib_dqdq2d_->AsFunctionType()->AddArgument(dq);
106 :
107 : auto* f = AsmType::Float();
108 : auto* fh = AsmType::Floatish();
109 : auto* fq = AsmType::FloatQ();
110 3721 : auto* fq2fh = AsmType::Function(zone(), fh);
111 : fq2fh->AsFunctionType()->AddArgument(fq);
112 :
113 : auto* s = AsmType::Signed();
114 : auto* u = AsmType::Unsigned();
115 3721 : auto* s2u = AsmType::Function(zone(), u);
116 : s2u->AsFunctionType()->AddArgument(s);
117 :
118 : auto* i = AsmType::Int();
119 3721 : stdlib_i2s_ = AsmType::Function(zone_, s);
120 : stdlib_i2s_->AsFunctionType()->AddArgument(i);
121 :
122 3721 : stdlib_ii2s_ = AsmType::Function(zone(), s);
123 : stdlib_ii2s_->AsFunctionType()->AddArgument(i);
124 3721 : 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 3721 : auto* minmax_d = AsmType::MinMaxType(zone(), d, d);
132 3718 : auto* minmax_f = AsmType::MinMaxType(zone(), f, f);
133 3718 : auto* minmax_s = AsmType::MinMaxType(zone(), s, s);
134 3720 : stdlib_minmax_ = AsmType::OverloadedFunction(zone());
135 3717 : stdlib_minmax_->AsOverloadedFunctionType()->AddOverload(minmax_s);
136 7437 : stdlib_minmax_->AsOverloadedFunctionType()->AddOverload(minmax_f);
137 7443 : 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 3720 : stdlib_abs_ = AsmType::OverloadedFunction(zone());
145 3720 : stdlib_abs_->AsOverloadedFunctionType()->AddOverload(s2u);
146 7438 : stdlib_abs_->AsOverloadedFunctionType()->AddOverload(stdlib_dq2d_);
147 7440 : 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 3719 : stdlib_ceil_like_ = AsmType::OverloadedFunction(zone());
154 7437 : stdlib_ceil_like_->AsOverloadedFunctionType()->AddOverload(stdlib_dq2d_);
155 7440 : stdlib_ceil_like_->AsOverloadedFunctionType()->AddOverload(fq2fh);
156 :
157 3718 : stdlib_fround_ = AsmType::FroundType(zone());
158 3717 : }
159 :
160 59378 : FunctionSig* AsmJsParser::ConvertSignature(AsmType* return_type,
161 59378 : const ZoneVector<AsmType*>& params) {
162 : FunctionSig::Builder sig_builder(
163 118756 : zone(), !return_type->IsA(AsmType::Void()) ? 1 : 0, params.size());
164 242155 : for (auto param : params) {
165 123402 : if (param->IsA(AsmType::Double())) {
166 : sig_builder.AddParam(kWasmF64);
167 119697 : } else if (param->IsA(AsmType::Float())) {
168 : sig_builder.AddParam(kWasmF32);
169 118759 : } else if (param->IsA(AsmType::Int())) {
170 : sig_builder.AddParam(kWasmI32);
171 : } else {
172 0 : UNREACHABLE();
173 : }
174 : }
175 59378 : if (!return_type->IsA(AsmType::Void())) {
176 30523 : if (return_type->IsA(AsmType::Double())) {
177 2167 : sig_builder.AddReturn(kWasmF64);
178 28356 : } else if (return_type->IsA(AsmType::Float())) {
179 297 : sig_builder.AddReturn(kWasmF32);
180 28059 : } else if (return_type->IsA(AsmType::Signed())) {
181 28059 : sig_builder.AddReturn(kWasmI32);
182 : } else {
183 0 : UNREACHABLE();
184 : }
185 : }
186 59378 : return sig_builder.Build();
187 : }
188 :
189 3714 : bool AsmJsParser::Run() {
190 3714 : ValidateModule();
191 3718 : return !failed_;
192 : }
193 :
194 : class AsmJsParser::TemporaryVariableScope {
195 : public:
196 4102 : explicit TemporaryVariableScope(AsmJsParser* parser) : parser_(parser) {
197 4135 : local_depth_ = parser_->function_temp_locals_depth_;
198 4135 : parser_->function_temp_locals_depth_++;
199 : }
200 : ~TemporaryVariableScope() {
201 : DCHECK_EQ(local_depth_, parser_->function_temp_locals_depth_ - 1);
202 4135 : 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 2807175 : wasm::AsmJsParser::VarInfo* AsmJsParser::GetVarInfo(
212 : AsmJsScanner::token_t token) {
213 2807175 : if (AsmJsScanner::IsGlobal(token)) {
214 3823885 : size_t old = global_var_info_.size();
215 : size_t index = AsmJsScanner::GlobalIndex(token);
216 2549252 : size_t sz = std::max(old, index + 1);
217 1274626 : if (sz != old) {
218 21805 : global_var_info_.resize(sz);
219 : }
220 : return &global_var_info_[index];
221 1532549 : } else if (AsmJsScanner::IsLocal(token)) {
222 4597647 : size_t old = local_var_info_.size();
223 : size_t index = AsmJsScanner::LocalIndex(token);
224 3065098 : size_t sz = std::max(old, index + 1);
225 1532549 : if (sz != old) {
226 575709 : 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 124928 : return info->index + static_cast<uint32_t>(global_imports_.size());
236 : }
237 :
238 507 : 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 507 : DeclareGlobal(info, mutable_variable, type, vtype);
245 :
246 : // Record the need to initialize the global from the import.
247 507 : global_imports_.push_back({name, vtype, info});
248 507 : }
249 :
250 0 : void AsmJsParser::DeclareGlobal(VarInfo* info, bool mutable_variable,
251 : AsmType* type, ValueType vtype,
252 : const WasmInitExpr& init) {
253 2326 : info->kind = VarKind::kGlobal;
254 2326 : info->type = type;
255 2326 : info->index = module_builder_->AddGlobal(vtype, false, true, init);
256 2326 : info->mutable_variable = mutable_variable;
257 0 : }
258 :
259 0 : void AsmJsParser::DeclareStdlibFunc(VarInfo* info, VarKind kind,
260 : AsmType* type) {
261 4329 : info->kind = kind;
262 4329 : info->type = type;
263 4329 : info->index = 0; // unused
264 4329 : info->mutable_variable = false;
265 0 : }
266 :
267 0 : uint32_t AsmJsParser::TempVariable(int index) {
268 8950 : if (index + 1 > function_temp_locals_used_) {
269 1612 : function_temp_locals_used_ = index + 1;
270 : }
271 8950 : return function_temp_locals_offset_ + index;
272 : }
273 :
274 39572 : Vector<const char> AsmJsParser::CopyCurrentIdentifierString() {
275 19786 : const std::string& str = scanner_.GetIdentifierString();
276 : char* buffer = zone()->NewArray<char>(str.size());
277 19786 : str.copy(buffer, str.size());
278 19785 : return Vector<const char>(buffer, static_cast<int>(str.size()));
279 : }
280 :
281 912741 : void AsmJsParser::SkipSemicolon() {
282 912749 : if (Check(';')) {
283 : // Had a semicolon.
284 32384 : } else if (!Peek('}') && !scanner_.IsPrecededByNewline()) {
285 44 : FAIL("Expected ;");
286 : }
287 : }
288 :
289 14641 : void AsmJsParser::Begin(AsmJsScanner::token_t label) {
290 : BareBegin(BlockKind::kRegular, label);
291 14641 : current_function_builder_->EmitWithU8(kExprBlock, kLocalVoid);
292 14641 : }
293 :
294 14013 : void AsmJsParser::Loop(AsmJsScanner::token_t label) {
295 : BareBegin(BlockKind::kLoop, label);
296 14013 : size_t position = scanner_.Position();
297 14013 : current_function_builder_->AddAsmWasmOffset(position, position);
298 14013 : current_function_builder_->EmitWithU8(kExprLoop, kLocalVoid);
299 14013 : }
300 :
301 0 : void AsmJsParser::End() {
302 : BareEnd();
303 37412 : current_function_builder_->Emit(kExprEnd);
304 0 : }
305 :
306 0 : void AsmJsParser::BareBegin(BlockKind kind, AsmJsScanner::token_t label) {
307 : BlockInfo info;
308 116140 : info.kind = kind;
309 116140 : info.label = label;
310 116140 : 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 23602 : for (auto it = block_stack_.rbegin(); it != block_stack_.rend();
321 : ++it, ++count) {
322 24684 : if (it->kind == BlockKind::kLoop &&
323 889 : (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 820994 : for (auto it = block_stack_.rbegin(); it != block_stack_.rend();
333 : ++it, ++count) {
334 845916 : if (it->kind == BlockKind::kRegular &&
335 13893 : (label == kTokenNone || it->label == label)) {
336 : return count;
337 : }
338 : }
339 : return -1;
340 : }
341 :
342 : // 6.1 ValidateModule
343 7387 : void AsmJsParser::ValidateModule() {
344 8664 : RECURSE(ValidateModuleParameters());
345 3676 : EXPECT_TOKEN('{');
346 3678 : EXPECT_TOKEN(TOK(UseAsm));
347 3678 : RECURSE(SkipSemicolon());
348 3674 : RECURSE(ValidateModuleVars());
349 15543 : while (Peek(TOK(function))) {
350 12611 : RECURSE(ValidateFunction());
351 : }
352 3121 : while (Peek(TOK(var))) {
353 205 : RECURSE(ValidateFunctionTable());
354 : }
355 2916 : RECURSE(ValidateExport());
356 :
357 : // Check that all functions were eventually defined.
358 33109 : for (auto& info : global_var_info_) {
359 28148 : if (info.kind == VarKind::kFunction && !info.function_defined) {
360 32 : FAIL("Undefined function");
361 : }
362 28132 : if (info.kind == VarKind::kTable && !info.function_defined) {
363 16 : FAIL("Undefined function table");
364 : }
365 28124 : 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 1204 : FunctionSig* void_void_sig = FunctionSig::Builder(zone(), 0, 0).Build();
369 1204 : module_builder_->AddImport(info.import->function_name, void_void_sig);
370 : }
371 : }
372 :
373 : // Add start function to initialize things.
374 2469 : WasmFunctionBuilder* start = module_builder_->AddFunction();
375 2468 : module_builder_->MarkStartFunction(start);
376 7876 : for (auto& global_import : global_imports_) {
377 : uint32_t import_index = module_builder_->AddGlobalImport(
378 469 : global_import.import_name, global_import.value_type);
379 469 : start->EmitWithI32V(kExprGetGlobal, import_index);
380 938 : start->EmitWithI32V(kExprSetGlobal, VarIndex(global_import.var_info));
381 : }
382 2469 : start->Emit(kExprEnd);
383 : FunctionSig::Builder b(zone(), 0, 0);
384 2469 : start->SetSignature(b.Build());
385 : }
386 :
387 : // 6.1 ValidateModule - parameters
388 3714 : void AsmJsParser::ValidateModuleParameters() {
389 7470 : EXPECT_TOKEN('(');
390 3714 : stdlib_name_ = 0;
391 3714 : foreign_name_ = 0;
392 3714 : heap_name_ = 0;
393 3714 : if (!Peek(')')) {
394 2636 : if (!scanner_.IsGlobal()) {
395 0 : FAIL("Expected stdlib parameter");
396 : }
397 2636 : stdlib_name_ = Consume();
398 2636 : if (!Peek(')')) {
399 1858 : EXPECT_TOKEN(',');
400 1859 : if (!scanner_.IsGlobal()) {
401 0 : FAIL("Expected foreign parameter");
402 : }
403 1860 : foreign_name_ = Consume();
404 1860 : if (!Peek(')')) {
405 1784 : EXPECT_TOKEN(',');
406 1784 : if (!scanner_.IsGlobal()) {
407 0 : FAIL("Expected heap parameter");
408 : }
409 1784 : heap_name_ = Consume();
410 : }
411 : }
412 : }
413 3756 : EXPECT_TOKEN(')');
414 : }
415 :
416 : // 6.1 ValidateModule - variables
417 3668 : void AsmJsParser::ValidateModuleVars() {
418 15643 : while (Peek(TOK(var)) || Peek(TOK(const))) {
419 : bool mutable_variable = true;
420 8444 : if (Check(TOK(var))) {
421 : // Had a var.
422 : } else {
423 59 : EXPECT_TOKEN(TOK(const));
424 : mutable_variable = false;
425 : }
426 : for (;;) {
427 8866 : RECURSE(ValidateModuleVar(mutable_variable));
428 8727 : if (Check(',')) {
429 : continue;
430 : }
431 : break;
432 : }
433 8305 : SkipSemicolon();
434 : }
435 : }
436 :
437 : // 6.1 ValidateModule - one variable
438 8865 : void AsmJsParser::ValidateModuleVar(bool mutable_variable) {
439 21027 : if (!scanner_.IsGlobal()) {
440 0 : FAIL("Expected identifier");
441 : }
442 8864 : VarInfo* info = GetVarInfo(Consume());
443 8866 : if (info->kind != VarKind::kUnused) {
444 0 : FAIL("Redefinition of variable");
445 : }
446 8870 : EXPECT_TOKEN('=');
447 : double dvalue = 0.0;
448 : uint32_t uvalue = 0;
449 8862 : if (CheckForDouble(&dvalue)) {
450 : DeclareGlobal(info, mutable_variable, AsmType::Double(), kWasmF64,
451 166 : WasmInitExpr(dvalue));
452 8696 : } else if (CheckForUnsigned(&uvalue)) {
453 1448 : if (uvalue > 0x7FFFFFFF) {
454 16 : FAIL("Numeric literal out of range");
455 : }
456 : DeclareGlobal(info, mutable_variable,
457 : mutable_variable ? AsmType::Int() : AsmType::Signed(),
458 2880 : kWasmI32, WasmInitExpr(static_cast<int32_t>(uvalue)));
459 7248 : } else if (Check('-')) {
460 8 : if (CheckForDouble(&dvalue)) {
461 : DeclareGlobal(info, mutable_variable, AsmType::Double(), kWasmF64,
462 8 : WasmInitExpr(-dvalue));
463 4 : } else if (CheckForUnsigned(&uvalue)) {
464 4 : 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 12 : kWasmI32, WasmInitExpr(-static_cast<int32_t>(uvalue)));
470 : } else {
471 0 : FAIL("Expected numeric literal");
472 : }
473 7240 : } else if (Check(TOK(new))) {
474 1316 : RECURSE(ValidateModuleVarNewStdlib(info));
475 11848 : } else if (Check(stdlib_name_)) {
476 3270 : EXPECT_TOKEN('.');
477 3262 : RECURSE(ValidateModuleVarStdlib(info));
478 5316 : } else if (Peek(foreign_name_) || Peek('+')) {
479 2606 : RECURSE(ValidateModuleVarImport(info, mutable_variable));
480 52 : } else if (scanner_.IsGlobal()) {
481 38 : RECURSE(ValidateModuleVarFromGlobal(info, mutable_variable));
482 : } else {
483 28 : FAIL("Bad variable declaration");
484 : }
485 : }
486 :
487 : // 6.1 ValidateModule - global float declaration
488 38 : void AsmJsParser::ValidateModuleVarFromGlobal(VarInfo* info,
489 : bool mutable_variable) {
490 38 : VarInfo* src_info = GetVarInfo(Consume());
491 38 : if (!src_info->type->IsA(stdlib_fround_)) {
492 22 : if (src_info->mutable_variable) {
493 50 : FAIL("Can only use immutable variables in global definition");
494 : }
495 4 : if (mutable_variable) {
496 0 : FAIL("Can only define immutable variables with other immutables");
497 : }
498 12 : if (!src_info->type->IsA(AsmType::Int()) &&
499 4 : !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 4 : info->kind = VarKind::kGlobal;
504 4 : info->type = src_info->type;
505 4 : info->index = src_info->index;
506 4 : info->mutable_variable = false;
507 4 : return;
508 : }
509 16 : EXPECT_TOKEN('(');
510 : bool negate = false;
511 16 : if (Check('-')) {
512 : negate = true;
513 : }
514 : double dvalue = 0.0;
515 : uint32_t uvalue = 0;
516 16 : if (CheckForDouble(&dvalue)) {
517 12 : if (negate) {
518 4 : dvalue = -dvalue;
519 : }
520 : DeclareGlobal(info, mutable_variable, AsmType::Float(), kWasmF32,
521 24 : WasmInitExpr(static_cast<float>(dvalue)));
522 4 : } else if (CheckForUnsigned(&uvalue)) {
523 4 : dvalue = uvalue;
524 4 : if (negate) {
525 0 : dvalue = -dvalue;
526 : }
527 : DeclareGlobal(info, mutable_variable, AsmType::Float(), kWasmF32,
528 8 : WasmInitExpr(static_cast<float>(dvalue)));
529 : } else {
530 0 : FAIL("Expected numeric literal");
531 : }
532 16 : EXPECT_TOKEN(')');
533 : }
534 :
535 : // 6.1 ValidateModule - foreign imports
536 2606 : void AsmJsParser::ValidateModuleVarImport(VarInfo* info,
537 2091 : bool mutable_variable) {
538 2606 : if (Check('+')) {
539 2614 : EXPECT_TOKEN(foreign_name_);
540 170 : EXPECT_TOKEN('.');
541 170 : Vector<const char> name = CopyCurrentIdentifierString();
542 170 : AddGlobalImport(name, AsmType::Double(), kWasmF64, mutable_variable, info);
543 170 : scanner_.Next();
544 : } else {
545 2436 : EXPECT_TOKEN(foreign_name_);
546 2432 : EXPECT_TOKEN('.');
547 2432 : Vector<const char> name = CopyCurrentIdentifierString();
548 2432 : scanner_.Next();
549 2432 : if (Check('|')) {
550 341 : if (!CheckForZero()) {
551 8 : FAIL("Expected |0 type annotation for foreign integer import");
552 : }
553 337 : AddGlobalImport(name, AsmType::Int(), kWasmI32, mutable_variable, info);
554 : } else {
555 2091 : info->kind = VarKind::kImportedFunction;
556 : info->import = new (zone()->New(sizeof(FunctionImportInfo)))
557 6273 : FunctionImportInfo(name, zone());
558 2091 : info->mutable_variable = false;
559 : }
560 : }
561 : }
562 :
563 : // 6.1 ValidateModule - one variable
564 : // 9 - Standard Library - heap types
565 1316 : void AsmJsParser::ValidateModuleVarNewStdlib(VarInfo* info) {
566 5115 : EXPECT_TOKEN(stdlib_name_);
567 1266 : EXPECT_TOKEN('.');
568 1266 : 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 1266 : EXPECT_TOKEN('(');
581 1291 : EXPECT_TOKEN(heap_name_);
582 1242 : EXPECT_TOKEN(')');
583 : }
584 :
585 : // 6.1 ValidateModule - one variable
586 : // 9 - Standard Library
587 3262 : void AsmJsParser::ValidateModuleVarStdlib(VarInfo* info) {
588 3262 : if (Check(TOK(Math))) {
589 3210 : EXPECT_TOKEN('.');
590 3200 : 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 137 : 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 3063 : STDLIB_MATH_FUNCTION_LIST(V)
605 : #undef V
606 : default:
607 0 : FAIL("Invalid member of stdlib.Math");
608 : }
609 62 : } else if (Check(TOK(Infinity))) {
610 : DeclareGlobal(info, false, AsmType::Double(), kWasmF64,
611 14 : WasmInitExpr(std::numeric_limits<double>::infinity()));
612 : stdlib_uses_.Add(StandardMember::kInfinity);
613 48 : } else if (Check(TOK(NaN))) {
614 : DeclareGlobal(info, false, AsmType::Double(), kWasmF64,
615 38 : WasmInitExpr(std::numeric_limits<double>::quiet_NaN()));
616 : stdlib_uses_.Add(StandardMember::kNaN);
617 : } else {
618 20 : FAIL("Invalid member of stdlib");
619 : }
620 : }
621 :
622 : // 6.2 ValidateExport
623 2914 : void AsmJsParser::ValidateExport() {
624 : // clang-format off
625 9911 : EXPECT_TOKEN(TOK(return));
626 : // clang-format on
627 2876 : if (Check('{')) {
628 : for (;;) {
629 4570 : Vector<const char> name = CopyCurrentIdentifierString();
630 4570 : if (!scanner_.IsGlobal() && !scanner_.IsLocal()) {
631 986 : FAIL("Illegal export name");
632 : }
633 : Consume();
634 4247 : EXPECT_TOKEN(':');
635 4240 : if (!scanner_.IsGlobal()) {
636 8 : FAIL("Expected function name");
637 : }
638 4236 : VarInfo* info = GetVarInfo(Consume());
639 4236 : if (info->kind != VarKind::kFunction) {
640 0 : FAIL("Expected function");
641 : }
642 4236 : module_builder_->AddExport(name, info->function_builder);
643 4236 : if (Check(',')) {
644 1910 : if (!Peek('}')) {
645 1865 : continue;
646 : }
647 : }
648 2371 : break;
649 1865 : }
650 2371 : EXPECT_TOKEN('}');
651 : } else {
652 171 : if (!scanner_.IsGlobal()) {
653 98 : FAIL("Single function export must be a function name");
654 : }
655 122 : VarInfo* info = GetVarInfo(Consume());
656 122 : if (info->kind != VarKind::kFunction) {
657 0 : FAIL("Single function export must be a function");
658 : }
659 : module_builder_->AddExport(CStrVector(AsmJs::kSingleFunctionName),
660 244 : info->function_builder);
661 : }
662 : }
663 :
664 : // 6.3 ValidateFunctionTable
665 205 : void AsmJsParser::ValidateFunctionTable() {
666 804 : EXPECT_TOKEN(TOK(var));
667 205 : if (!scanner_.IsGlobal()) {
668 0 : FAIL("Expected table name");
669 : }
670 205 : VarInfo* table_info = GetVarInfo(Consume());
671 205 : if (table_info->kind == VarKind::kTable) {
672 193 : if (table_info->function_defined) {
673 8 : FAIL("Function table redefined");
674 : }
675 189 : table_info->function_defined = true;
676 12 : } else if (table_info->kind != VarKind::kUnused) {
677 8 : FAIL("Function table name collides");
678 : }
679 197 : EXPECT_TOKEN('=');
680 197 : EXPECT_TOKEN('[');
681 : uint64_t count = 0;
682 : for (;;) {
683 4201 : if (!scanner_.IsGlobal()) {
684 8 : FAIL("Expected function name");
685 : }
686 4197 : VarInfo* info = GetVarInfo(Consume());
687 4197 : 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 4197 : if (table_info->kind == VarKind::kTable) {
693 4193 : if (count >= static_cast<uint64_t>(table_info->mask) + 1) {
694 0 : FAIL("Exceeded function table size");
695 : }
696 4193 : if (!info->type->IsA(table_info->type)) {
697 8 : FAIL("Function table definition doesn't match use");
698 : }
699 : module_builder_->SetIndirectFunction(
700 4189 : static_cast<uint32_t>(table_info->index + count), info->index);
701 : }
702 4193 : ++count;
703 4193 : if (Check(',')) {
704 4004 : if (!Peek(']')) {
705 : continue;
706 : }
707 : }
708 : break;
709 : }
710 189 : EXPECT_TOKEN(']');
711 374 : if (table_info->kind == VarKind::kTable &&
712 185 : count != static_cast<uint64_t>(table_info->mask) + 1) {
713 0 : FAIL("Function table size does not match uses");
714 : }
715 189 : SkipSemicolon();
716 : }
717 :
718 : // 6.4 ValidateFunction
719 24634 : void AsmJsParser::ValidateFunction() {
720 38141 : EXPECT_TOKEN(TOK(function));
721 12614 : if (!scanner_.IsGlobal()) {
722 0 : FAIL("Expected function name");
723 : }
724 :
725 12614 : Vector<const char> function_name_str = CopyCurrentIdentifierString();
726 : AsmJsScanner::token_t function_name = Consume();
727 12614 : VarInfo* function_info = GetVarInfo(function_name);
728 12611 : if (function_info->kind == VarKind::kUnused) {
729 9699 : function_info->kind = VarKind::kFunction;
730 9699 : function_info->function_builder = module_builder_->AddFunction();
731 9700 : function_info->index = function_info->function_builder->func_index();
732 9700 : function_info->mutable_variable = false;
733 2912 : } else if (function_info->kind != VarKind::kFunction) {
734 8 : FAIL("Function name collides with variable");
735 2908 : } else if (function_info->function_defined) {
736 16 : FAIL("Function redefined");
737 : }
738 :
739 12600 : function_info->function_defined = true;
740 12600 : function_info->function_builder->SetName(function_name_str);
741 12595 : current_function_builder_ = function_info->function_builder;
742 12595 : return_type_ = nullptr;
743 :
744 : // Record start of the function, used as position for the stack check.
745 12595 : current_function_builder_->SetAsmFunctionStartPosition(scanner_.Position());
746 :
747 12594 : CachedVector<AsmType*> params(cached_asm_type_p_vectors_);
748 12596 : ValidateFunctionParams(¶ms);
749 :
750 : // Check against limit on number of parameters.
751 25200 : if (params.size() >= kV8MaxWasmFunctionParams) {
752 20 : FAIL("Number of parameters exceeds internal limit");
753 : }
754 :
755 12590 : CachedVector<ValueType> locals(cached_valuetype_vectors_);
756 25172 : ValidateFunctionLocals(params.size(), &locals);
757 :
758 : function_temp_locals_offset_ = static_cast<uint32_t>(
759 37752 : params.size() + locals.size());
760 12584 : function_temp_locals_used_ = 0;
761 12584 : function_temp_locals_depth_ = 0;
762 :
763 : bool last_statement_is_return = false;
764 249475 : while (!failed_ && !Peek('}')) {
765 : // clang-format off
766 : last_statement_is_return = Peek(TOK(return));
767 : // clang-format on
768 106353 : RECURSE(ValidateStatement());
769 : }
770 12300 : EXPECT_TOKEN('}');
771 :
772 12030 : if (!last_statement_is_return) {
773 2219 : if (return_type_ == nullptr) {
774 1808 : return_type_ = AsmType::Void();
775 411 : } else if (!return_type_->IsA(AsmType::Void())) {
776 8 : 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 12026 : FunctionSig* sig = ConvertSignature(return_type_, params);
784 12025 : current_function_builder_->SetSignature(sig);
785 567987 : for (auto local : locals) {
786 543939 : current_function_builder_->AddLocal(local);
787 : }
788 : // Add bonus temps.
789 1588 : for (int i = 0; i < function_temp_locals_used_; ++i) {
790 1588 : current_function_builder_->AddLocal(kWasmI32);
791 : }
792 :
793 : // Check against limit on number of local variables.
794 24048 : if (locals.size() + function_temp_locals_used_ > kV8MaxWasmFunctionLocals) {
795 10 : FAIL("Number of local variables exceeds internal limit");
796 : }
797 :
798 : // End function
799 12019 : current_function_builder_->Emit(kExprEnd);
800 :
801 : // Record (or validate) function type.
802 24040 : AsmType* function_type = AsmType::Function(zone(), return_type_);
803 45081 : for (auto t : params) {
804 : function_type->AsFunctionType()->AddArgument(t);
805 : }
806 12019 : function_info = GetVarInfo(function_name);
807 12021 : if (function_info->type->IsA(AsmType::None())) {
808 : DCHECK_EQ(function_info->kind, VarKind::kFunction);
809 9066 : function_info->type = function_type;
810 2955 : } else if (!function_type->IsA(function_info->type)) {
811 : // TODO(bradnelson): Should IsExactly be used here?
812 8 : FAIL("Function definition doesn't match use");
813 : }
814 :
815 12017 : scanner_.ResetLocals();
816 : local_var_info_.clear();
817 : }
818 :
819 : // 6.4 ValidateFunction
820 12596 : 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 134009 : scanner_.EnterLocalScope();
825 12710 : EXPECT_TOKEN('(');
826 : CachedVector<AsmJsScanner::token_t> function_parameters(
827 12603 : cached_token_t_vectors_);
828 88355 : while (!failed_ && !Peek(')')) {
829 31579 : if (!scanner_.IsLocal()) {
830 0 : FAIL("Expected parameter name");
831 : }
832 63156 : function_parameters.push_back(Consume());
833 31577 : if (!Peek(')')) {
834 21109 : EXPECT_TOKEN(',');
835 : }
836 : }
837 12598 : EXPECT_TOKEN(')');
838 : scanner_.EnterGlobalScope();
839 12601 : EXPECT_TOKEN('{');
840 : // 5.1 Parameter Type Annotations
841 56640 : for (auto p : function_parameters) {
842 31646 : EXPECT_TOKEN(p);
843 31467 : EXPECT_TOKEN('=');
844 31468 : VarInfo* info = GetVarInfo(p);
845 31468 : if (info->kind != VarKind::kUnused) {
846 0 : FAIL("Duplicate parameter name");
847 : }
848 31466 : if (Check(p)) {
849 19345 : EXPECT_TOKEN('|');
850 19330 : if (!CheckForZero()) {
851 16 : FAIL("Bad integer parameter annotation.");
852 : }
853 19322 : info->kind = VarKind::kLocal;
854 19322 : info->type = AsmType::Int();
855 50765 : info->index = static_cast<uint32_t>(params->size());
856 38643 : params->push_back(AsmType::Int());
857 12130 : } else if (Check('+')) {
858 11323 : EXPECT_TOKEN(p);
859 11314 : info->kind = VarKind::kLocal;
860 11314 : info->type = AsmType::Double();
861 11314 : info->index = static_cast<uint32_t>(params->size());
862 22629 : params->push_back(AsmType::Double());
863 : } else {
864 1618 : if (!scanner_.IsGlobal() ||
865 1614 : !GetVarInfo(Consume())->type->IsA(stdlib_fround_)) {
866 8 : FAIL("Expected fround");
867 : }
868 807 : EXPECT_TOKEN('(');
869 807 : EXPECT_TOKEN(p);
870 807 : EXPECT_TOKEN(')');
871 807 : info->kind = VarKind::kLocal;
872 807 : info->type = AsmType::Float();
873 807 : info->index = static_cast<uint32_t>(params->size());
874 1614 : params->push_back(AsmType::Float());
875 : }
876 31443 : SkipSemicolon();
877 : }
878 : }
879 :
880 : // 6.4 ValidateFunction - locals
881 12583 : void AsmJsParser::ValidateFunctionLocals(size_t param_count,
882 : ZoneVector<ValueType>* locals) {
883 : DCHECK(locals->empty());
884 : // Local Variables.
885 532058 : while (Peek(TOK(var))) {
886 544329 : scanner_.EnterLocalScope();
887 506912 : EXPECT_TOKEN(TOK(var));
888 : scanner_.EnterGlobalScope();
889 : for (;;) {
890 544240 : if (!scanner_.IsLocal()) {
891 0 : FAIL("Expected local variable identifier");
892 : }
893 544240 : VarInfo* info = GetVarInfo(Consume());
894 544240 : if (info->kind != VarKind::kUnused) {
895 0 : FAIL("Duplicate local variable name");
896 : }
897 : // Store types.
898 544240 : EXPECT_TOKEN('=');
899 : double dvalue = 0.0;
900 : uint32_t uvalue = 0;
901 544240 : if (Check('-')) {
902 36 : if (CheckForDouble(&dvalue)) {
903 16 : info->kind = VarKind::kLocal;
904 16 : info->type = AsmType::Double();
905 544235 : info->index = static_cast<uint32_t>(param_count + locals->size());
906 32 : locals->push_back(kWasmF64);
907 16 : current_function_builder_->EmitF64Const(-dvalue);
908 16 : current_function_builder_->EmitSetLocal(info->index);
909 20 : } else if (CheckForUnsigned(&uvalue)) {
910 20 : if (uvalue > 0x7FFFFFFF) {
911 0 : FAIL("Numeric literal out of range");
912 : }
913 20 : info->kind = VarKind::kLocal;
914 20 : info->type = AsmType::Int();
915 20 : info->index = static_cast<uint32_t>(param_count + locals->size());
916 40 : locals->push_back(kWasmI32);
917 20 : int32_t value = -static_cast<int32_t>(uvalue);
918 20 : current_function_builder_->EmitI32Const(value);
919 20 : current_function_builder_->EmitSetLocal(info->index);
920 : } else {
921 0 : FAIL("Expected variable initial value");
922 : }
923 544204 : } else if (scanner_.IsGlobal()) {
924 48 : VarInfo* sinfo = GetVarInfo(Consume());
925 48 : if (sinfo->kind == VarKind::kGlobal) {
926 12 : if (sinfo->mutable_variable) {
927 0 : FAIL("Initializing from global requires const variable");
928 : }
929 12 : info->kind = VarKind::kLocal;
930 12 : info->type = sinfo->type;
931 12 : info->index = static_cast<uint32_t>(param_count + locals->size());
932 12 : if (sinfo->type->IsA(AsmType::Int())) {
933 8 : locals->push_back(kWasmI32);
934 8 : } else if (sinfo->type->IsA(AsmType::Float())) {
935 8 : locals->push_back(kWasmF32);
936 4 : } else if (sinfo->type->IsA(AsmType::Double())) {
937 8 : locals->push_back(kWasmF64);
938 : } else {
939 0 : FAIL("Bad local variable definition");
940 : }
941 : current_function_builder_->EmitWithI32V(kExprGetGlobal,
942 12 : VarIndex(sinfo));
943 12 : current_function_builder_->EmitSetLocal(info->index);
944 36 : } else if (sinfo->type->IsA(stdlib_fround_)) {
945 36 : EXPECT_TOKEN('(');
946 : bool negate = false;
947 36 : if (Check('-')) {
948 : negate = true;
949 : }
950 : double dvalue = 0.0;
951 36 : if (CheckForDouble(&dvalue)) {
952 20 : info->kind = VarKind::kLocal;
953 20 : info->type = AsmType::Float();
954 20 : info->index = static_cast<uint32_t>(param_count + locals->size());
955 40 : locals->push_back(kWasmF32);
956 20 : if (negate) {
957 0 : dvalue = -dvalue;
958 : }
959 20 : current_function_builder_->EmitF32Const(dvalue);
960 20 : current_function_builder_->EmitSetLocal(info->index);
961 16 : } else if (CheckForUnsigned(&uvalue)) {
962 12 : if (uvalue > 0x7FFFFFFF) {
963 0 : FAIL("Numeric literal out of range");
964 : }
965 12 : info->kind = VarKind::kLocal;
966 12 : info->type = AsmType::Float();
967 12 : info->index = static_cast<uint32_t>(param_count + locals->size());
968 24 : locals->push_back(kWasmF32);
969 : int32_t value = static_cast<int32_t>(uvalue);
970 12 : if (negate) {
971 0 : value = -value;
972 : }
973 12 : float fvalue = static_cast<float>(value);
974 12 : current_function_builder_->EmitF32Const(fvalue);
975 12 : current_function_builder_->EmitSetLocal(info->index);
976 : } else {
977 8 : FAIL("Expected variable initial value");
978 : }
979 32 : EXPECT_TOKEN(')');
980 : } else {
981 0 : FAIL("expected fround or const global");
982 : }
983 544156 : } else if (CheckForDouble(&dvalue)) {
984 3782 : info->kind = VarKind::kLocal;
985 3782 : info->type = AsmType::Double();
986 3782 : info->index = static_cast<uint32_t>(param_count + locals->size());
987 7564 : locals->push_back(kWasmF64);
988 3782 : current_function_builder_->EmitF64Const(dvalue);
989 3782 : current_function_builder_->EmitSetLocal(info->index);
990 540374 : } else if (CheckForUnsigned(&uvalue)) {
991 540357 : info->kind = VarKind::kLocal;
992 540357 : info->type = AsmType::Int();
993 540357 : info->index = static_cast<uint32_t>(param_count + locals->size());
994 1080714 : locals->push_back(kWasmI32);
995 540357 : int32_t value = static_cast<int32_t>(uvalue);
996 540357 : current_function_builder_->EmitI32Const(value);
997 540357 : current_function_builder_->EmitSetLocal(info->index);
998 : } else {
999 34 : FAIL("Expected variable initial value");
1000 : }
1001 544219 : if (!Peek(',')) {
1002 : break;
1003 : }
1004 : scanner_.EnterLocalScope();
1005 37328 : EXPECT_TOKEN(',');
1006 : scanner_.EnterGlobalScope();
1007 37328 : }
1008 506891 : SkipSemicolon();
1009 : }
1010 : }
1011 :
1012 : // 6.5 ValidateStatement
1013 523691 : void AsmJsParser::ValidateStatement() {
1014 523691 : call_coercion_ = nullptr;
1015 523691 : if (Peek('{')) {
1016 93478 : RECURSE(Block());
1017 430213 : } else if (Peek(';')) {
1018 1185 : RECURSE(EmptyStatement());
1019 429028 : } else if (Peek(TOK(if))) {
1020 58030 : RECURSE(IfStatement());
1021 : // clang-format off
1022 370998 : } else if (Peek(TOK(return))) {
1023 : // clang-format on
1024 34992 : RECURSE(ReturnStatement());
1025 336006 : } else if (IterationStatement()) {
1026 : // Handled in IterationStatement.
1027 321985 : } else if (Peek(TOK(break))) {
1028 24930 : RECURSE(BreakStatement());
1029 297055 : } else if (Peek(TOK(continue))) {
1030 1082 : RECURSE(ContinueStatement());
1031 295973 : } else if (Peek(TOK(switch))) {
1032 617 : RECURSE(SwitchStatement());
1033 : } else {
1034 295356 : RECURSE(ExpressionStatement());
1035 : }
1036 : }
1037 :
1038 : // 6.5.1 Block
1039 93478 : void AsmJsParser::Block() {
1040 93478 : bool can_break_to_block = pending_label_ != 0;
1041 93478 : if (can_break_to_block) {
1042 16 : Begin(pending_label_);
1043 : }
1044 93478 : pending_label_ = 0;
1045 186932 : EXPECT_TOKEN('{');
1046 882450 : while (!failed_ && !Peek('}')) {
1047 301032 : RECURSE(ValidateStatement());
1048 : }
1049 93454 : EXPECT_TOKEN('}');
1050 93454 : if (can_break_to_block) {
1051 : End();
1052 : }
1053 : }
1054 :
1055 : // 6.5.2 ExpressionStatement
1056 295356 : void AsmJsParser::ExpressionStatement() {
1057 295356 : if (scanner_.IsGlobal() || scanner_.IsLocal()) {
1058 : // NOTE: Both global or local identifiers can also be used as labels.
1059 295301 : scanner_.Next();
1060 295299 : if (Peek(':')) {
1061 2529 : scanner_.Rewind();
1062 2529 : RECURSE(LabelledStatement());
1063 : return;
1064 : }
1065 292770 : scanner_.Rewind();
1066 : }
1067 : AsmType* ret;
1068 292827 : RECURSE(ret = ValidateExpression());
1069 292675 : if (!ret->IsA(AsmType::Void())) {
1070 269568 : current_function_builder_->Emit(kExprDrop);
1071 : }
1072 292675 : SkipSemicolon();
1073 : }
1074 :
1075 : // 6.5.3 EmptyStatement
1076 1185 : void AsmJsParser::EmptyStatement() { EXPECT_TOKEN(';'); }
1077 :
1078 : // 6.5.4 IfStatement
1079 58030 : void AsmJsParser::IfStatement() {
1080 116028 : EXPECT_TOKEN(TOK(if));
1081 58030 : EXPECT_TOKEN('(');
1082 58030 : RECURSE(Expression(AsmType::Int()));
1083 57998 : EXPECT_TOKEN(')');
1084 57998 : current_function_builder_->EmitWithU8(kExprIf, kLocalVoid);
1085 : BareBegin();
1086 57998 : RECURSE(ValidateStatement());
1087 57974 : if (Check(TOK(else))) {
1088 21271 : current_function_builder_->Emit(kExprElse);
1089 21271 : RECURSE(ValidateStatement());
1090 : }
1091 57974 : current_function_builder_->Emit(kExprEnd);
1092 : BareEnd();
1093 : }
1094 :
1095 : // 6.5.5 ReturnStatement
1096 34991 : void AsmJsParser::ReturnStatement() {
1097 : // clang-format off
1098 35037 : EXPECT_TOKEN(TOK(return));
1099 : // clang-format on
1100 34991 : if (!Peek(';') && !Peek('}')) {
1101 : // TODO(bradnelson): See if this can be factored out.
1102 : AsmType* ret;
1103 28726 : RECURSE(ret = Expression(return_type_));
1104 28602 : if (ret->IsA(AsmType::Double())) {
1105 949 : return_type_ = AsmType::Double();
1106 27652 : } else if (ret->IsA(AsmType::Float())) {
1107 177 : return_type_ = AsmType::Float();
1108 27474 : } else if (ret->IsA(AsmType::Signed())) {
1109 27432 : return_type_ = AsmType::Signed();
1110 : } else {
1111 84 : FAIL("Invalid return type");
1112 : }
1113 6265 : } else if (return_type_ == nullptr) {
1114 2819 : return_type_ = AsmType::Void();
1115 3446 : } else if (!return_type_->IsA(AsmType::Void())) {
1116 8 : FAIL("Invalid void return type");
1117 : }
1118 34819 : current_function_builder_->Emit(kExprReturn);
1119 34821 : SkipSemicolon();
1120 : }
1121 :
1122 : // 6.5.6 IterationStatement
1123 336006 : bool AsmJsParser::IterationStatement() {
1124 336006 : if (Peek(TOK(while))) {
1125 5127 : WhileStatement();
1126 330879 : } else if (Peek(TOK(do))) {
1127 8749 : DoStatement();
1128 322130 : } else if (Peek(TOK(for))) {
1129 145 : ForStatement();
1130 : } else {
1131 : return false;
1132 : }
1133 : return true;
1134 : }
1135 :
1136 : // 6.5.6 IterationStatement - while
1137 5127 : void AsmJsParser::WhileStatement() {
1138 : // a: block {
1139 5127 : Begin(pending_label_);
1140 : // b: loop {
1141 5127 : Loop(pending_label_);
1142 5127 : pending_label_ = 0;
1143 10238 : EXPECT_TOKEN(TOK(while));
1144 5127 : EXPECT_TOKEN('(');
1145 5127 : RECURSE(Expression(AsmType::Int()));
1146 5111 : EXPECT_TOKEN(')');
1147 : // if (!CONDITION) break a;
1148 5111 : current_function_builder_->Emit(kExprI32Eqz);
1149 5111 : current_function_builder_->EmitWithU8(kExprBrIf, 1);
1150 : // BODY
1151 5111 : RECURSE(ValidateStatement());
1152 : // continue b;
1153 5107 : current_function_builder_->EmitWithU8(kExprBr, 0);
1154 : End();
1155 : // }
1156 : // }
1157 : End();
1158 : }
1159 :
1160 : // 6.5.6 IterationStatement - do
1161 8749 : void AsmJsParser::DoStatement() {
1162 : // a: block {
1163 8749 : Begin(pending_label_);
1164 : // b: loop {
1165 8749 : Loop();
1166 : // c: block { // but treated like loop so continue works
1167 8749 : BareBegin(BlockKind::kLoop, pending_label_);
1168 8749 : current_function_builder_->EmitWithU8(kExprBlock, kLocalVoid);
1169 8749 : pending_label_ = 0;
1170 34984 : EXPECT_TOKEN(TOK(do));
1171 : // BODY
1172 8749 : RECURSE(ValidateStatement());
1173 8749 : EXPECT_TOKEN(TOK(while));
1174 : End();
1175 : // } // end c
1176 8749 : EXPECT_TOKEN('(');
1177 8749 : RECURSE(Expression(AsmType::Int()));
1178 : // if (!CONDITION) break a;
1179 8737 : current_function_builder_->Emit(kExprI32Eqz);
1180 8737 : current_function_builder_->EmitWithU8(kExprBrIf, 1);
1181 : // continue b;
1182 8737 : current_function_builder_->EmitWithU8(kExprBr, 0);
1183 8737 : EXPECT_TOKEN(')');
1184 : // } // end b
1185 : End();
1186 : // } // end a
1187 : End();
1188 8737 : SkipSemicolon();
1189 : }
1190 :
1191 : // 6.5.6 IterationStatement - for
1192 145 : void AsmJsParser::ForStatement() {
1193 778 : EXPECT_TOKEN(TOK(for));
1194 145 : EXPECT_TOKEN('(');
1195 145 : if (!Peek(';')) {
1196 : AsmType* ret;
1197 120 : RECURSE(ret = Expression(nullptr));
1198 112 : if (!ret->IsA(AsmType::Void())) {
1199 112 : current_function_builder_->Emit(kExprDrop);
1200 : }
1201 : }
1202 137 : EXPECT_TOKEN(';');
1203 : // a: block {
1204 137 : Begin(pending_label_);
1205 : // b: loop {
1206 137 : Loop();
1207 : // c: block { // but treated like loop so continue works
1208 137 : BareBegin(BlockKind::kLoop, pending_label_);
1209 137 : current_function_builder_->EmitWithU8(kExprBlock, kLocalVoid);
1210 137 : pending_label_ = 0;
1211 137 : if (!Peek(';')) {
1212 : // if (!CONDITION) break a;
1213 116 : RECURSE(Expression(AsmType::Int()));
1214 104 : current_function_builder_->Emit(kExprI32Eqz);
1215 104 : current_function_builder_->EmitWithU8(kExprBrIf, 2);
1216 : }
1217 125 : EXPECT_TOKEN(';');
1218 : // Race past INCREMENT
1219 : size_t increment_position = scanner_.Position();
1220 125 : ScanToClosingParenthesis();
1221 125 : EXPECT_TOKEN(')');
1222 : // BODY
1223 125 : RECURSE(ValidateStatement());
1224 : // } // end c
1225 : End();
1226 : // INCREMENT
1227 : size_t end_position = scanner_.Position();
1228 121 : scanner_.Seek(increment_position);
1229 121 : if (!Peek(')')) {
1230 100 : RECURSE(Expression(nullptr));
1231 : // NOTE: No explicit drop because below break is an implicit drop.
1232 : }
1233 : // continue b;
1234 121 : current_function_builder_->EmitWithU8(kExprBr, 0);
1235 121 : scanner_.Seek(end_position);
1236 : // } // end b
1237 : End();
1238 : // } // end a
1239 : End();
1240 : }
1241 :
1242 : // 6.5.7 BreakStatement
1243 24930 : void AsmJsParser::BreakStatement() {
1244 24934 : EXPECT_TOKEN(TOK(break));
1245 : AsmJsScanner::token_t label_name = kTokenNone;
1246 24930 : 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 24930 : if (depth < 0) {
1252 8 : FAIL("Illegal break");
1253 : }
1254 24926 : current_function_builder_->Emit(kExprBr);
1255 24926 : current_function_builder_->EmitI32V(depth);
1256 24926 : SkipSemicolon();
1257 : }
1258 :
1259 : // 6.5.8 ContinueStatement
1260 1082 : void AsmJsParser::ContinueStatement() {
1261 1082 : EXPECT_TOKEN(TOK(continue));
1262 : AsmJsScanner::token_t label_name = kTokenNone;
1263 1082 : 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 1082 : if (depth < 0) {
1269 0 : FAIL("Illegal continue");
1270 : }
1271 1082 : current_function_builder_->EmitWithI32V(kExprBr, depth);
1272 1082 : SkipSemicolon();
1273 : }
1274 :
1275 : // 6.5.9 LabelledStatement
1276 2529 : void AsmJsParser::LabelledStatement() {
1277 : DCHECK(scanner_.IsGlobal() || scanner_.IsLocal());
1278 : // NOTE: Currently using globals/locals for labels too.
1279 2529 : if (pending_label_ != 0) {
1280 2529 : FAIL("Double label unsupported");
1281 : }
1282 2529 : pending_label_ = scanner_.Token();
1283 2529 : scanner_.Next();
1284 2529 : EXPECT_TOKEN(':');
1285 2529 : RECURSE(ValidateStatement());
1286 : }
1287 :
1288 : // 6.5.10 SwitchStatement
1289 617 : void AsmJsParser::SwitchStatement() {
1290 2458 : EXPECT_TOKEN(TOK(switch));
1291 617 : EXPECT_TOKEN('(');
1292 : AsmType* test;
1293 617 : RECURSE(test = Expression(nullptr));
1294 612 : if (!test->IsA(AsmType::Signed())) {
1295 0 : FAIL("Expected signed for switch value");
1296 : }
1297 612 : EXPECT_TOKEN(')');
1298 : uint32_t tmp = TempVariable(0);
1299 612 : current_function_builder_->EmitSetLocal(tmp);
1300 612 : Begin(pending_label_);
1301 612 : pending_label_ = 0;
1302 : // TODO(bradnelson): Make less weird.
1303 612 : CachedVector<int32_t> cases(cached_int_vectors_);
1304 612 : GatherCases(&cases);
1305 612 : EXPECT_TOKEN('{');
1306 1224 : size_t count = cases.size() + 1;
1307 21214 : for (size_t i = 0; i < count; ++i) {
1308 : BareBegin(BlockKind::kOther);
1309 20602 : current_function_builder_->EmitWithU8(kExprBlock, kLocalVoid);
1310 : }
1311 : int table_pos = 0;
1312 21214 : for (auto c : cases) {
1313 19990 : current_function_builder_->EmitGetLocal(tmp);
1314 19990 : current_function_builder_->EmitI32Const(c);
1315 19990 : current_function_builder_->Emit(kExprI32Eq);
1316 19990 : current_function_builder_->EmitWithI32V(kExprBrIf, table_pos++);
1317 : }
1318 612 : current_function_builder_->EmitWithI32V(kExprBr, table_pos++);
1319 41800 : while (!failed_ && Peek(TOK(case))) {
1320 19994 : current_function_builder_->Emit(kExprEnd);
1321 : BareEnd();
1322 19994 : RECURSE(ValidateCase());
1323 : }
1324 600 : current_function_builder_->Emit(kExprEnd);
1325 : BareEnd();
1326 600 : if (Peek(TOK(default))) {
1327 584 : RECURSE(ValidateDefault());
1328 : }
1329 600 : EXPECT_TOKEN('}');
1330 : End();
1331 : }
1332 :
1333 : // 6.6. ValidateCase
1334 19994 : void AsmJsParser::ValidateCase() {
1335 39988 : EXPECT_TOKEN(TOK(case));
1336 : bool negate = false;
1337 19994 : if (Check('-')) {
1338 : negate = true;
1339 : }
1340 : uint32_t uvalue;
1341 19994 : if (!CheckForUnsigned(&uvalue)) {
1342 8 : FAIL("Expected numeric literal");
1343 : }
1344 : // TODO(bradnelson): Share negation plumbing.
1345 19990 : 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 19990 : EXPECT_TOKEN(':');
1354 99804 : while (!failed_ && !Peek('}') && !Peek(TOK(case)) && !Peek(TOK(default))) {
1355 19925 : RECURSE(ValidateStatement());
1356 : }
1357 : }
1358 :
1359 : // 6.7 ValidateDefault
1360 584 : void AsmJsParser::ValidateDefault() {
1361 584 : EXPECT_TOKEN(TOK(default));
1362 584 : EXPECT_TOKEN(':');
1363 2948 : while (!failed_ && !Peek('}')) {
1364 598 : RECURSE(ValidateStatement());
1365 : }
1366 : }
1367 :
1368 : // 6.8 ValidateExpression
1369 293265 : AsmType* AsmJsParser::ValidateExpression() {
1370 : AsmType* ret;
1371 293265 : RECURSEn(ret = Expression(nullptr));
1372 293111 : return ret;
1373 : }
1374 :
1375 : // 6.8.1 Expression
1376 542526 : AsmType* AsmJsParser::Expression(AsmType* expected) {
1377 : AsmType* a;
1378 : for (;;) {
1379 548852 : RECURSEn(a = AssignmentExpression());
1380 545227 : if (Peek(',')) {
1381 3159 : if (a->IsA(AsmType::None())) {
1382 0 : FAILn("Expected actual type");
1383 : }
1384 3159 : if (!a->IsA(AsmType::Void())) {
1385 3094 : current_function_builder_->Emit(kExprDrop);
1386 : }
1387 3159 : EXPECT_TOKENn(',');
1388 : continue;
1389 : }
1390 : break;
1391 : }
1392 542068 : if (expected != nullptr && !a->IsA(expected)) {
1393 16 : FAILn("Unexpected type");
1394 : }
1395 3159 : return a;
1396 : }
1397 :
1398 : // 6.8.2 NumericLiteral
1399 726091 : AsmType* AsmJsParser::NumericLiteral() {
1400 726091 : call_coercion_ = nullptr;
1401 : double dvalue = 0.0;
1402 : uint32_t uvalue = 0;
1403 726092 : if (CheckForDouble(&dvalue)) {
1404 5584 : current_function_builder_->EmitF64Const(dvalue);
1405 5584 : return AsmType::Double();
1406 720516 : } else if (CheckForUnsigned(&uvalue)) {
1407 720477 : if (uvalue <= 0x7FFFFFFF) {
1408 720332 : current_function_builder_->EmitI32Const(static_cast<int32_t>(uvalue));
1409 720332 : return AsmType::FixNum();
1410 : } else {
1411 145 : current_function_builder_->EmitI32Const(static_cast<int32_t>(uvalue));
1412 146 : return AsmType::Unsigned();
1413 : }
1414 : } else {
1415 39 : FAILn("Expected numeric literal.");
1416 : }
1417 : }
1418 :
1419 : // 6.8.3 Identifier
1420 496286 : AsmType* AsmJsParser::Identifier() {
1421 496286 : call_coercion_ = nullptr;
1422 496337 : if (scanner_.IsLocal()) {
1423 477508 : VarInfo* info = GetVarInfo(Consume());
1424 477507 : if (info->kind != VarKind::kLocal) {
1425 0 : FAILn("Undefined local variable");
1426 : }
1427 477507 : current_function_builder_->EmitGetLocal(info->index);
1428 477508 : return info->type;
1429 18780 : } else if (scanner_.IsGlobal()) {
1430 18780 : VarInfo* info = GetVarInfo(Consume());
1431 18780 : if (info->kind != VarKind::kGlobal) {
1432 102 : FAILn("Undefined global variable");
1433 : }
1434 18729 : current_function_builder_->EmitWithI32V(kExprGetGlobal, VarIndex(info));
1435 18729 : return info->type;
1436 : }
1437 0 : UNREACHABLE();
1438 : }
1439 :
1440 : // 6.8.4 CallExpression
1441 1570396 : AsmType* AsmJsParser::CallExpression() {
1442 : AsmType* ret;
1443 1806658 : if (scanner_.IsGlobal() &&
1444 236263 : GetVarInfo(scanner_.Token())->type->IsA(stdlib_fround_)) {
1445 437 : ValidateFloatCoercion();
1446 437 : return AsmType::Float();
1447 1805783 : } else if (scanner_.IsGlobal() &&
1448 235825 : GetVarInfo(scanner_.Token())->type->IsA(AsmType::Heap())) {
1449 169658 : RECURSEn(ret = MemberExpression());
1450 1400300 : } else if (Peek('(')) {
1451 130527 : RECURSEn(ret = ParenthesizedExpression());
1452 1269773 : } else if (PeekCall()) {
1453 47387 : RECURSEn(ret = ValidateCall());
1454 1222384 : } else if (scanner_.IsLocal() || scanner_.IsGlobal()) {
1455 496286 : RECURSEn(ret = Identifier());
1456 : } else {
1457 726098 : RECURSEn(ret = NumericLiteral());
1458 : }
1459 1569685 : return ret;
1460 : }
1461 :
1462 : // 6.8.5 MemberExpression
1463 169658 : AsmType* AsmJsParser::MemberExpression() {
1464 169658 : call_coercion_ = nullptr;
1465 169658 : RECURSEn(ValidateHeapAccess());
1466 : DCHECK_NOT_NULL(heap_access_type_);
1467 169629 : if (Peek('=')) {
1468 65899 : inside_heap_assignment_ = true;
1469 65899 : 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 103730 : STDLIB_ARRAY_TYPE_LIST(V)
1477 : #undef V
1478 0 : FAILn("Expected valid heap load");
1479 : }
1480 : }
1481 :
1482 : // 6.8.6 AssignmentExpression
1483 929678 : AsmType* AsmJsParser::AssignmentExpression() {
1484 : AsmType* ret;
1485 1170417 : if (scanner_.IsGlobal() &&
1486 240680 : GetVarInfo(scanner_.Token())->type->IsA(AsmType::Heap())) {
1487 156013 : RECURSEn(ret = ConditionalExpression());
1488 155979 : if (Peek('=')) {
1489 65900 : if (!inside_heap_assignment_) {
1490 0 : FAILn("Invalid assignment target");
1491 : }
1492 65900 : inside_heap_assignment_ = false;
1493 : DCHECK_NOT_NULL(heap_access_type_);
1494 65900 : AsmType* heap_type = heap_access_type_;
1495 65900 : EXPECT_TOKENn('=');
1496 : AsmType* value;
1497 65900 : RECURSEn(value = AssignmentExpression());
1498 65896 : if (!value->IsA(ret)) {
1499 0 : FAILn("Illegal type stored to heap view");
1500 : }
1501 69396 : if (heap_type->IsA(AsmType::Float32Array()) &&
1502 3500 : value->IsA(AsmType::DoubleQ())) {
1503 : // Assignment to a float32 heap can be used to convert doubles.
1504 3496 : current_function_builder_->Emit(kExprF32ConvertF64);
1505 : }
1506 68514 : if (heap_type->IsA(AsmType::Float64Array()) &&
1507 2617 : value->IsA(AsmType::FloatQ())) {
1508 : // Assignment to a float64 heap can be used to convert floats.
1509 8 : 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 65897 : STDLIB_ARRAY_TYPE_LIST(V)
1518 : #undef V
1519 : }
1520 773666 : } else if (scanner_.IsLocal() || scanner_.IsGlobal()) {
1521 : bool is_local = scanner_.IsLocal();
1522 564002 : VarInfo* info = GetVarInfo(scanner_.Token());
1523 : USE(is_local);
1524 564002 : ret = info->type;
1525 564002 : scanner_.Next();
1526 564002 : 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 201151 : if (info->kind == VarKind::kUnused) {
1530 26 : FAILn("Undeclared assignment target");
1531 : }
1532 201138 : if (!info->mutable_variable) {
1533 66 : FAILn("Expected mutable variable in assignment");
1534 : }
1535 : DCHECK(is_local ? info->kind == VarKind::kLocal
1536 : : info->kind == VarKind::kGlobal);
1537 : AsmType* value;
1538 201105 : RECURSEn(value = AssignmentExpression());
1539 201063 : if (!value->IsA(ret)) {
1540 24 : FAILn("Type mismatch in assignment");
1541 : }
1542 201051 : if (info->kind == VarKind::kLocal) {
1543 179424 : current_function_builder_->EmitTeeLocal(info->index);
1544 21627 : } else if (info->kind == VarKind::kGlobal) {
1545 21627 : current_function_builder_->EmitWithU32V(kExprSetGlobal, VarIndex(info));
1546 21627 : current_function_builder_->EmitWithU32V(kExprGetGlobal, VarIndex(info));
1547 : } else {
1548 0 : UNREACHABLE();
1549 : }
1550 201051 : return ret;
1551 : }
1552 362851 : scanner_.Rewind();
1553 362849 : RECURSEn(ret = ConditionalExpression());
1554 : } else {
1555 209664 : RECURSEn(ret = ConditionalExpression());
1556 : }
1557 662219 : return ret;
1558 : }
1559 :
1560 : // 6.8.7 UnaryExpression
1561 1595988 : AsmType* AsmJsParser::UnaryExpression() {
1562 : AsmType* ret;
1563 1595989 : if (Check('-')) {
1564 : uint32_t uvalue;
1565 5619 : if (CheckForUnsigned(&uvalue)) {
1566 : // TODO(bradnelson): was supposed to be 0x7FFFFFFF, check errata.
1567 4625 : if (uvalue <= 0x80000000) {
1568 : current_function_builder_->EmitI32Const(
1569 9250 : base::NegateWithWraparound(static_cast<int32_t>(uvalue)));
1570 : } else {
1571 14614 : FAILn("Integer numeric literal out of range.");
1572 : }
1573 : ret = AsmType::Signed();
1574 : } else {
1575 994 : RECURSEn(ret = UnaryExpression());
1576 994 : if (ret->IsA(AsmType::Int())) {
1577 : TemporaryVariableScope tmp(this);
1578 5 : current_function_builder_->EmitSetLocal(tmp.get());
1579 5 : current_function_builder_->EmitI32Const(0);
1580 5 : current_function_builder_->EmitGetLocal(tmp.get());
1581 5 : current_function_builder_->Emit(kExprI32Sub);
1582 : ret = AsmType::Intish();
1583 989 : } else if (ret->IsA(AsmType::DoubleQ())) {
1584 984 : current_function_builder_->Emit(kExprF64Neg);
1585 : ret = AsmType::Double();
1586 5 : } else if (ret->IsA(AsmType::FloatQ())) {
1587 5 : current_function_builder_->Emit(kExprF32Neg);
1588 : ret = AsmType::Floatish();
1589 : } else {
1590 0 : FAILn("expected int/double?/float?");
1591 : }
1592 : }
1593 1590370 : } else if (Peek('+')) {
1594 14606 : call_coercion_ = AsmType::Double();
1595 14606 : call_coercion_position_ = scanner_.Position();
1596 14606 : scanner_.Next(); // Done late for correct position.
1597 14606 : RECURSEn(ret = UnaryExpression());
1598 : // TODO(bradnelson): Generalize.
1599 14579 : if (ret->IsA(AsmType::Signed())) {
1600 972 : current_function_builder_->Emit(kExprF64SConvertI32);
1601 : ret = AsmType::Double();
1602 13606 : } else if (ret->IsA(AsmType::Unsigned())) {
1603 201 : current_function_builder_->Emit(kExprF64UConvertI32);
1604 : ret = AsmType::Double();
1605 13406 : } else if (ret->IsA(AsmType::DoubleQ())) {
1606 : ret = AsmType::Double();
1607 5937 : } else if (ret->IsA(AsmType::FloatQ())) {
1608 5929 : current_function_builder_->Emit(kExprF64ConvertF32);
1609 : ret = AsmType::Double();
1610 : } else {
1611 16 : FAILn("expected signed/unsigned/double?/float?");
1612 : }
1613 1575764 : } else if (Check('!')) {
1614 4223 : RECURSEn(ret = UnaryExpression());
1615 4223 : if (!ret->IsA(AsmType::Int())) {
1616 0 : FAILn("expected int");
1617 : }
1618 4223 : current_function_builder_->Emit(kExprI32Eqz);
1619 1571541 : } else if (Check('~')) {
1620 1145 : if (Check('~')) {
1621 383 : RECURSEn(ret = UnaryExpression());
1622 383 : if (ret->IsA(AsmType::Double())) {
1623 375 : current_function_builder_->Emit(kExprI32AsmjsSConvertF64);
1624 8 : } else if (ret->IsA(AsmType::FloatQ())) {
1625 8 : current_function_builder_->Emit(kExprI32AsmjsSConvertF32);
1626 : } else {
1627 0 : FAILn("expected double or float?");
1628 : }
1629 : ret = AsmType::Signed();
1630 : } else {
1631 762 : RECURSEn(ret = UnaryExpression());
1632 762 : if (!ret->IsA(AsmType::Intish())) {
1633 0 : FAILn("operator ~ expects intish");
1634 : }
1635 762 : current_function_builder_->EmitI32Const(0xFFFFFFFF);
1636 762 : current_function_builder_->Emit(kExprI32Xor);
1637 : ret = AsmType::Signed();
1638 : }
1639 : } else {
1640 1570396 : RECURSEn(ret = CallExpression());
1641 : }
1642 1595680 : return ret;
1643 : }
1644 :
1645 : // 6.8.8 MultiplicativeExpression
1646 1582074 : AsmType* AsmJsParser::MultiplicativeExpression() {
1647 : AsmType* a;
1648 : uint32_t uvalue;
1649 1582076 : if (CheckForUnsignedBelow(0x100000, &uvalue)) {
1650 713661 : if (Check('*')) {
1651 : AsmType* a;
1652 17 : RECURSEn(a = UnaryExpression());
1653 9 : if (!a->IsA(AsmType::Int())) {
1654 0 : FAILn("Expected int");
1655 : }
1656 9 : int32_t value = static_cast<int32_t>(uvalue);
1657 9 : current_function_builder_->EmitI32Const(value);
1658 9 : current_function_builder_->Emit(kExprI32Mul);
1659 9 : return AsmType::Intish();
1660 : } else {
1661 713652 : scanner_.Rewind();
1662 713648 : RECURSEn(a = UnaryExpression());
1663 : }
1664 868415 : } else if (Check('-')) {
1665 22001 : if (CheckForUnsignedBelow(0x100000, &uvalue)) {
1666 16721 : int32_t value = -static_cast<int32_t>(uvalue);
1667 16721 : current_function_builder_->EmitI32Const(value);
1668 16721 : 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 5280 : scanner_.Rewind();
1680 5280 : RECURSEn(a = UnaryExpression());
1681 : }
1682 : } else {
1683 846414 : RECURSEn(a = UnaryExpression());
1684 : }
1685 : for (;;) {
1686 1591451 : if (Check('*')) {
1687 : uint32_t uvalue;
1688 12776 : if (Check('-')) {
1689 49 : if (CheckForUnsigned(&uvalue)) {
1690 8 : if (uvalue >= 0x100000) {
1691 0 : FAILn("Constant multiple out of range");
1692 : }
1693 8 : if (!a->IsA(AsmType::Int())) {
1694 8 : FAILn("Integer multiply of expects int");
1695 : }
1696 4 : int32_t value = -static_cast<int32_t>(uvalue);
1697 4 : current_function_builder_->EmitI32Const(value);
1698 4 : current_function_builder_->Emit(kExprI32Mul);
1699 4 : return AsmType::Intish();
1700 : }
1701 41 : scanner_.Rewind();
1702 12727 : } else if (CheckForUnsigned(&uvalue)) {
1703 5021 : if (uvalue >= 0x100000) {
1704 0 : FAILn("Constant multiple out of range");
1705 : }
1706 5021 : if (!a->IsA(AsmType::Int())) {
1707 8 : FAILn("Integer multiply of expects int");
1708 : }
1709 5017 : int32_t value = static_cast<int32_t>(uvalue);
1710 5017 : current_function_builder_->EmitI32Const(value);
1711 5017 : current_function_builder_->Emit(kExprI32Mul);
1712 5017 : return AsmType::Intish();
1713 : }
1714 : AsmType* b;
1715 7747 : RECURSEn(b = UnaryExpression());
1716 7747 : if (a->IsA(AsmType::DoubleQ()) && b->IsA(AsmType::DoubleQ())) {
1717 7742 : current_function_builder_->Emit(kExprF64Mul);
1718 : a = AsmType::Double();
1719 5 : } else if (a->IsA(AsmType::FloatQ()) && b->IsA(AsmType::FloatQ())) {
1720 5 : current_function_builder_->Emit(kExprF32Mul);
1721 : a = AsmType::Floatish();
1722 : } else {
1723 0 : FAILn("expected doubles or floats");
1724 : }
1725 1578674 : } else if (Check('/')) {
1726 : AsmType* b;
1727 1291 : RECURSEn(b = UnaryExpression());
1728 1291 : if (a->IsA(AsmType::DoubleQ()) && b->IsA(AsmType::DoubleQ())) {
1729 511 : current_function_builder_->Emit(kExprF64Div);
1730 : a = AsmType::Double();
1731 780 : } else if (a->IsA(AsmType::FloatQ()) && b->IsA(AsmType::FloatQ())) {
1732 5 : current_function_builder_->Emit(kExprF32Div);
1733 : a = AsmType::Floatish();
1734 775 : } else if (a->IsA(AsmType::Signed()) && b->IsA(AsmType::Signed())) {
1735 591 : current_function_builder_->Emit(kExprI32AsmjsDivS);
1736 : a = AsmType::Intish();
1737 184 : } else if (a->IsA(AsmType::Unsigned()) && b->IsA(AsmType::Unsigned())) {
1738 183 : current_function_builder_->Emit(kExprI32AsmjsDivU);
1739 : a = AsmType::Intish();
1740 : } else {
1741 0 : FAILn("expected doubles or floats");
1742 : }
1743 1577380 : } else if (Check('%')) {
1744 : AsmType* b;
1745 627 : RECURSEn(b = UnaryExpression());
1746 628 : if (a->IsA(AsmType::DoubleQ()) && b->IsA(AsmType::DoubleQ())) {
1747 20 : current_function_builder_->Emit(kExprF64Mod);
1748 : a = AsmType::Double();
1749 608 : } else if (a->IsA(AsmType::Signed()) && b->IsA(AsmType::Signed())) {
1750 392 : current_function_builder_->Emit(kExprI32AsmjsRemS);
1751 : a = AsmType::Intish();
1752 216 : } else if (a->IsA(AsmType::Unsigned()) && b->IsA(AsmType::Unsigned())) {
1753 216 : 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 1419609 : AsmType* AsmJsParser::AdditiveExpression() {
1767 : AsmType* a;
1768 1419633 : RECURSEn(a = MultiplicativeExpression());
1769 : int n = 0;
1770 : for (;;) {
1771 1581761 : if (Check('+')) {
1772 : AsmType* b;
1773 152274 : RECURSEn(b = MultiplicativeExpression());
1774 152270 : if (a->IsA(AsmType::Double()) && b->IsA(AsmType::Double())) {
1775 4538 : current_function_builder_->Emit(kExprF64Add);
1776 : a = AsmType::Double();
1777 147732 : } else if (a->IsA(AsmType::FloatQ()) && b->IsA(AsmType::FloatQ())) {
1778 21 : current_function_builder_->Emit(kExprF32Add);
1779 : a = AsmType::Floatish();
1780 147711 : } else if (a->IsA(AsmType::Int()) && b->IsA(AsmType::Int())) {
1781 134232 : current_function_builder_->Emit(kExprI32Add);
1782 : a = AsmType::Intish();
1783 : n = 2;
1784 13478 : } 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 13454 : ++n;
1788 13454 : if (n > (1 << 20)) {
1789 0 : FAILn("more than 2^20 additive values");
1790 : }
1791 13454 : current_function_builder_->Emit(kExprI32Add);
1792 : } else {
1793 48 : FAILn("illegal types for +");
1794 : }
1795 1429486 : } else if (Check('-')) {
1796 : AsmType* b;
1797 10194 : RECURSEn(b = MultiplicativeExpression());
1798 10194 : if (a->IsA(AsmType::Double()) && b->IsA(AsmType::Double())) {
1799 3400 : current_function_builder_->Emit(kExprF64Sub);
1800 : a = AsmType::Double();
1801 6794 : } else if (a->IsA(AsmType::FloatQ()) && b->IsA(AsmType::FloatQ())) {
1802 5 : current_function_builder_->Emit(kExprF32Sub);
1803 : a = AsmType::Floatish();
1804 6789 : } else if (a->IsA(AsmType::Int()) && b->IsA(AsmType::Int())) {
1805 6479 : current_function_builder_->Emit(kExprI32Sub);
1806 : a = AsmType::Intish();
1807 : n = 2;
1808 310 : } 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 310 : ++n;
1812 310 : if (n > (1 << 20)) {
1813 0 : FAILn("more than 2^20 additive values");
1814 : }
1815 310 : 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 1219568 : AsmType* AsmJsParser::ShiftExpression() {
1828 : AsmType* a = nullptr;
1829 2948221 : RECURSEn(a = AdditiveExpression());
1830 1219256 : 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 1419293 : switch (scanner_.Token()) {
1835 : case TOK(SAR): {
1836 154761 : EXPECT_TOKENn(TOK(SAR));
1837 154763 : 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 309526 : if (a->IsA(AsmType::Intish()) && CheckForUnsigned(&shift_imm)) {
1845 : old_pos = scanner_.Position();
1846 154680 : old_code = current_function_builder_->GetPosition();
1847 154680 : scanner_.Rewind();
1848 : imm = true;
1849 : }
1850 : AsmType* b = nullptr;
1851 154763 : RECURSEn(b = AdditiveExpression());
1852 : // Check for `a >> n:NumericLiteral` pattern.
1853 309443 : if (imm && old_pos == scanner_.Position()) {
1854 154672 : heap_access_shift_position_ = old_code;
1855 154672 : heap_access_shift_value_ = shift_imm;
1856 : }
1857 154763 : if (!(a->IsA(AsmType::Intish()) && b->IsA(AsmType::Intish()))) {
1858 0 : FAILn("Expected intish for operator >>.");
1859 : }
1860 154763 : 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 21621 : HANDLE_CASE(SHL, I32Shl, "<<", Signed);
1878 23652 : HANDLE_CASE(SHR, I32ShrU, ">>>", Unsigned);
1879 : #undef HANDLE_CASE
1880 : default:
1881 : return a;
1882 : }
1883 : }
1884 : }
1885 :
1886 : // 6.8.11 RelationalExpression
1887 1044389 : AsmType* AsmJsParser::RelationalExpression() {
1888 : AsmType* a = nullptr;
1889 1044429 : RECURSEn(a = ShiftExpression());
1890 : for (;;) {
1891 1068836 : 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 12022 : HANDLE_CASE('<', I32LtS, I32LtU, F64Lt, F32Lt, "<");
1913 2328 : HANDLE_CASE(TOK(LE), I32LeS, I32LeU, F64Le, F32Le, "<=");
1914 7852 : HANDLE_CASE('>', I32GtS, I32GtU, F64Gt, F32Gt, ">");
1915 2636 : 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 1000551 : AsmType* AsmJsParser::EqualityExpression() {
1925 : AsmType* a = nullptr;
1926 1000567 : RECURSEn(a = RelationalExpression());
1927 : for (;;) {
1928 1044020 : 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 30967 : HANDLE_CASE(TOK(EQ), I32Eq, I32Eq, F64Eq, F32Eq, "==");
1950 12888 : 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 980644 : AsmType* AsmJsParser::BitwiseANDExpression() {
1960 : AsmType* a = nullptr;
1961 980648 : RECURSEn(a = EqualityExpression());
1962 996048 : while (Check('&')) {
1963 : AsmType* b = nullptr;
1964 15779 : RECURSEn(b = EqualityExpression());
1965 15779 : if (a->IsA(AsmType::Intish()) && b->IsA(AsmType::Intish())) {
1966 15775 : current_function_builder_->Emit(kExprI32And);
1967 : a = AsmType::Signed();
1968 : } else {
1969 8 : FAILn("Expected intish for operator &.");
1970 : }
1971 : }
1972 : return a;
1973 : }
1974 :
1975 : // 6.8.14 BitwiseXORExpression
1976 979577 : AsmType* AsmJsParser::BitwiseXORExpression() {
1977 : AsmType* a = nullptr;
1978 979577 : RECURSEn(a = BitwiseANDExpression());
1979 980268 : while (Check('^')) {
1980 : AsmType* b = nullptr;
1981 1068 : RECURSEn(b = BitwiseANDExpression());
1982 1068 : if (a->IsA(AsmType::Intish()) && b->IsA(AsmType::Intish())) {
1983 1068 : 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 728517 : AsmType* AsmJsParser::BitwiseORExpression() {
1994 : AsmType* a = nullptr;
1995 1213779 : call_coercion_deferred_position_ = scanner_.Position();
1996 728517 : RECURSEn(a = BitwiseXORExpression());
1997 979184 : 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 251066 : AsmType::IsExactly(call_coercion_deferred_, AsmType::Signed());
2004 251065 : 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 251065 : if (a->IsA(AsmType::Intish()) && CheckForZero()) {
2010 : old_pos = scanner_.Position();
2011 242621 : old_code = current_function_builder_->GetPosition();
2012 242621 : scanner_.Rewind();
2013 : zero = true;
2014 : }
2015 251066 : RECURSEn(b = BitwiseXORExpression());
2016 : // Handle |0 specially.
2017 493685 : if (zero && old_pos == scanner_.Position()) {
2018 242542 : current_function_builder_->DeleteCodeAfter(old_code);
2019 : a = AsmType::Signed();
2020 242543 : continue;
2021 : }
2022 : // Anything not matching |0 breaks the lookahead in {ValidateCall}.
2023 8522 : if (requires_zero) {
2024 24 : FAILn("Expected |0 type annotation for call");
2025 : }
2026 8510 : if (a->IsA(AsmType::Intish()) && b->IsA(AsmType::Intish())) {
2027 8502 : current_function_builder_->Emit(kExprI32Ior);
2028 : a = AsmType::Signed();
2029 : } else {
2030 16 : FAILn("Expected intish for operator |.");
2031 : }
2032 : }
2033 : DCHECK_NULL(call_coercion_deferred_);
2034 : return a;
2035 : }
2036 :
2037 : // 6.8.16 ConditionalExpression
2038 728526 : AsmType* AsmJsParser::ConditionalExpression() {
2039 : AsmType* test = nullptr;
2040 735846 : RECURSEn(test = BitwiseORExpression());
2041 728120 : if (Check('?')) {
2042 7320 : if (!test->IsA(AsmType::Int())) {
2043 0 : FAILn("Expected int in condition of ternary operator.");
2044 : }
2045 7320 : current_function_builder_->EmitWithU8(kExprIf, kLocalI32);
2046 7320 : size_t fixup = current_function_builder_->GetPosition() -
2047 7320 : 1; // Assumes encoding knowledge.
2048 : AsmType* cons = nullptr;
2049 7320 : RECURSEn(cons = AssignmentExpression());
2050 7320 : current_function_builder_->Emit(kExprElse);
2051 7320 : EXPECT_TOKENn(':');
2052 : AsmType* alt = nullptr;
2053 7320 : RECURSEn(alt = AssignmentExpression());
2054 7320 : current_function_builder_->Emit(kExprEnd);
2055 7320 : if (cons->IsA(AsmType::Int()) && alt->IsA(AsmType::Int())) {
2056 6714 : current_function_builder_->FixupByte(fixup, kLocalI32);
2057 6714 : return AsmType::Int();
2058 606 : } else if (cons->IsA(AsmType::Double()) && alt->IsA(AsmType::Double())) {
2059 606 : current_function_builder_->FixupByte(fixup, kLocalF64);
2060 606 : 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 130527 : AsmType* AsmJsParser::ParenthesizedExpression() {
2074 130527 : call_coercion_ = nullptr;
2075 : AsmType* ret;
2076 260956 : EXPECT_TOKENn('(');
2077 130528 : RECURSEn(ret = Expression(nullptr));
2078 130429 : EXPECT_TOKENn(')');
2079 130431 : return ret;
2080 : }
2081 :
2082 : // 6.9 ValidateCall
2083 94739 : AsmType* AsmJsParser::ValidateCall() {
2084 47387 : AsmType* return_type = call_coercion_;
2085 47387 : call_coercion_ = nullptr;
2086 176032 : size_t call_pos = scanner_.Position();
2087 47387 : size_t to_number_pos = call_coercion_position_;
2088 47387 : 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 47387 : base::Optional<TemporaryVariableScope> tmp;
2096 47387 : if (Check('[')) {
2097 4129 : RECURSEn(EqualityExpression());
2098 4129 : EXPECT_TOKENn('&');
2099 : uint32_t mask = 0;
2100 4129 : if (!CheckForUnsigned(&mask)) {
2101 0 : FAILn("Expected mask literal");
2102 : }
2103 8258 : if (!base::bits::IsPowerOfTwo(mask + 1)) {
2104 10 : FAILn("Expected power of 2 mask");
2105 : }
2106 4124 : current_function_builder_->EmitI32Const(mask);
2107 4124 : current_function_builder_->Emit(kExprI32And);
2108 4124 : EXPECT_TOKENn(']');
2109 4124 : VarInfo* function_info = GetVarInfo(function_name);
2110 4124 : if (function_info->kind == VarKind::kUnused) {
2111 219 : uint32_t index = module_builder_->AllocateIndirectFunctions(mask + 1);
2112 219 : if (index == std::numeric_limits<uint32_t>::max()) {
2113 20 : FAILn("Exceeded maximum function table size");
2114 : }
2115 209 : function_info->kind = VarKind::kTable;
2116 209 : function_info->mask = mask;
2117 209 : function_info->index = index;
2118 209 : function_info->mutable_variable = false;
2119 : } else {
2120 3905 : if (function_info->kind != VarKind::kTable) {
2121 24 : FAILn("Expected call table");
2122 : }
2123 3893 : if (function_info->mask != mask) {
2124 0 : FAILn("Mask size mismatch");
2125 : }
2126 : }
2127 4102 : current_function_builder_->EmitI32Const(function_info->index);
2128 4102 : current_function_builder_->Emit(kExprI32Add);
2129 : // We have to use a temporary for the correct order of evaluation.
2130 4102 : tmp.emplace(this);
2131 8204 : 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 43258 : VarInfo* function_info = GetVarInfo(function_name);
2136 43258 : if (function_info->kind == VarKind::kUnused) {
2137 2932 : function_info->kind = VarKind::kFunction;
2138 2932 : function_info->function_builder = module_builder_->AddFunction();
2139 2932 : function_info->index = function_info->function_builder->func_index();
2140 2932 : function_info->mutable_variable = false;
2141 : } else {
2142 40326 : if (function_info->kind != VarKind::kFunction &&
2143 : function_info->kind < VarKind::kImportedFunction) {
2144 8 : FAILn("Expected function as call target");
2145 : }
2146 : }
2147 : }
2148 :
2149 : // Parse argument list and gather types.
2150 47356 : CachedVector<AsmType*> param_types(cached_asm_type_p_vectors_);
2151 : CachedVector<AsmType*> param_specific_types(cached_asm_type_p_vectors_);
2152 47360 : EXPECT_TOKENn('(');
2153 197053 : while (!failed_ && !Peek(')')) {
2154 : AsmType* t;
2155 102350 : RECURSEn(t = AssignmentExpression());
2156 102339 : param_specific_types.push_back(t);
2157 102340 : if (t->IsA(AsmType::Int())) {
2158 199272 : param_types.push_back(AsmType::Int());
2159 2705 : } else if (t->IsA(AsmType::Float())) {
2160 384 : param_types.push_back(AsmType::Float());
2161 2513 : } else if (t->IsA(AsmType::Double())) {
2162 5026 : param_types.push_back(AsmType::Double());
2163 : } else {
2164 0 : FAILn("Bad function argument type");
2165 : }
2166 102341 : if (!Peek(')')) {
2167 59417 : EXPECT_TOKENn(',');
2168 : }
2169 : }
2170 47352 : EXPECT_TOKENn(')');
2171 :
2172 : // Reload {VarInfo} after parsing arguments as table might have grown.
2173 47352 : 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 115649 : if (allow_peek && Peek('|') &&
2192 91309 : function_info->kind <= VarKind::kImportedFunction &&
2193 4 : (return_type == nullptr || return_type->IsA(AsmType::Float()))) {
2194 : DCHECK_NULL(call_coercion_deferred_);
2195 21520 : call_coercion_deferred_ = AsmType::Signed();
2196 : to_number_pos = scanner_.Position();
2197 : return_type = AsmType::Signed();
2198 25832 : } 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 47352 : AsmType* function_type = AsmType::Function(zone(), return_type);
2205 197058 : for (auto t : param_types) {
2206 : function_type->AsFunctionType()->AddArgument(t);
2207 : }
2208 47352 : FunctionSig* sig = ConvertSignature(return_type, param_types);
2209 47352 : 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 47352 : if (function_info->kind == VarKind::kImportedFunction) {
2215 23747 : for (auto t : param_specific_types) {
2216 7965 : if (!t->IsA(AsmType::Extern())) {
2217 0 : FAILn("Imported function args must be type extern");
2218 : }
2219 : }
2220 7891 : 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 7891 : auto it = function_info->import->cache.find(*sig);
2227 7891 : if (it != function_info->import->cache.end()) {
2228 7027 : index = it->second;
2229 : DCHECK(function_info->function_defined);
2230 : } else {
2231 : index =
2232 864 : module_builder_->AddImport(function_info->import->function_name, sig);
2233 1728 : function_info->import->cache[*sig] = index;
2234 864 : function_info->function_defined = true;
2235 : }
2236 7891 : current_function_builder_->AddAsmWasmOffset(call_pos, to_number_pos);
2237 7891 : current_function_builder_->EmitWithU32V(kExprCallFunction, index);
2238 39461 : } else if (function_info->kind > VarKind::kImportedFunction) {
2239 2083 : AsmCallableType* callable = function_info->type->AsCallableType();
2240 2083 : if (!callable) {
2241 0 : FAILn("Expected callable function");
2242 : }
2243 : // TODO(bradnelson): Refactor AsmType to not need this.
2244 2083 : if (callable->CanBeInvokedWith(return_type, param_specific_types)) {
2245 : // Return type ok.
2246 1091 : } else if (callable->CanBeInvokedWith(AsmType::Float(),
2247 1091 : param_specific_types)) {
2248 : return_type = AsmType::Float();
2249 1083 : } else if (callable->CanBeInvokedWith(AsmType::Floatish(),
2250 1083 : param_specific_types)) {
2251 : return_type = AsmType::Floatish();
2252 995 : } else if (callable->CanBeInvokedWith(AsmType::Double(),
2253 995 : param_specific_types)) {
2254 : return_type = AsmType::Double();
2255 995 : } else if (callable->CanBeInvokedWith(AsmType::Signed(),
2256 995 : param_specific_types)) {
2257 : return_type = AsmType::Signed();
2258 30 : } else if (callable->CanBeInvokedWith(AsmType::Unsigned(),
2259 30 : param_specific_types)) {
2260 : return_type = AsmType::Unsigned();
2261 : } else {
2262 36 : FAILn("Function use doesn't match definition");
2263 : }
2264 2065 : 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 19 : 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 62 : STDLIB_MATH_FUNCTION_CEIL_LIKE_LIST(V)
2282 : #undef V
2283 : case VarKind::kMathMin:
2284 : case VarKind::kMathMax:
2285 108 : if (param_specific_types[0]->IsA(AsmType::Double())) {
2286 120 : for (size_t i = 1; i < param_specific_types.size(); ++i) {
2287 40 : if (function_info->kind == VarKind::kMathMin) {
2288 20 : current_function_builder_->Emit(kExprF64Min);
2289 : } else {
2290 20 : current_function_builder_->Emit(kExprF64Max);
2291 : }
2292 : }
2293 68 : } 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 156 : for (size_t i = 1; i < param_specific_types.size(); ++i) {
2297 52 : if (function_info->kind == VarKind::kMathMin) {
2298 26 : current_function_builder_->Emit(kExprF32Min);
2299 : } else {
2300 26 : current_function_builder_->Emit(kExprF32Max);
2301 : }
2302 : }
2303 16 : } else if (param_specific_types[0]->IsA(AsmType::Signed())) {
2304 : TemporaryVariableScope tmp_x(this);
2305 : TemporaryVariableScope tmp_y(this);
2306 64 : for (size_t i = 1; i < param_specific_types.size(); ++i) {
2307 16 : current_function_builder_->EmitSetLocal(tmp_x.get());
2308 16 : current_function_builder_->EmitTeeLocal(tmp_y.get());
2309 16 : current_function_builder_->EmitGetLocal(tmp_x.get());
2310 16 : if (function_info->kind == VarKind::kMathMin) {
2311 8 : current_function_builder_->Emit(kExprI32GeS);
2312 : } else {
2313 8 : current_function_builder_->Emit(kExprI32LeS);
2314 : }
2315 16 : current_function_builder_->EmitWithU8(kExprIf, kLocalI32);
2316 16 : current_function_builder_->EmitGetLocal(tmp_x.get());
2317 16 : current_function_builder_->Emit(kExprElse);
2318 16 : current_function_builder_->EmitGetLocal(tmp_y.get());
2319 16 : current_function_builder_->Emit(kExprEnd);
2320 : }
2321 : } else {
2322 0 : UNREACHABLE();
2323 : }
2324 : break;
2325 :
2326 : case VarKind::kMathAbs:
2327 104 : if (param_specific_types[0]->IsA(AsmType::Signed())) {
2328 : TemporaryVariableScope tmp(this);
2329 12 : current_function_builder_->EmitTeeLocal(tmp.get());
2330 12 : current_function_builder_->EmitGetLocal(tmp.get());
2331 12 : current_function_builder_->EmitI32Const(31);
2332 12 : current_function_builder_->Emit(kExprI32ShrS);
2333 12 : current_function_builder_->EmitTeeLocal(tmp.get());
2334 12 : current_function_builder_->Emit(kExprI32Xor);
2335 12 : current_function_builder_->EmitGetLocal(tmp.get());
2336 12 : current_function_builder_->Emit(kExprI32Sub);
2337 92 : } else if (param_specific_types[0]->IsA(AsmType::DoubleQ())) {
2338 70 : current_function_builder_->Emit(kExprF64Abs);
2339 22 : } else if (param_specific_types[0]->IsA(AsmType::FloatQ())) {
2340 22 : 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 37378 : if (function_info->type->IsA(AsmType::None())) {
2358 3204 : function_info->type = function_type;
2359 : } else {
2360 34174 : AsmCallableType* callable = function_info->type->AsCallableType();
2361 68348 : if (!callable ||
2362 34174 : !callable->CanBeInvokedWith(return_type, param_specific_types)) {
2363 16 : FAILn("Function use doesn't match definition");
2364 : }
2365 : }
2366 37370 : if (function_info->kind == VarKind::kTable) {
2367 8196 : current_function_builder_->EmitGetLocal(tmp->get());
2368 4098 : current_function_builder_->AddAsmWasmOffset(call_pos, to_number_pos);
2369 4098 : current_function_builder_->Emit(kExprCallIndirect);
2370 4098 : current_function_builder_->EmitU32V(signature_index);
2371 4098 : current_function_builder_->EmitU32V(0); // table index
2372 : } else {
2373 33272 : current_function_builder_->AddAsmWasmOffset(call_pos, to_number_pos);
2374 33272 : current_function_builder_->Emit(kExprCallFunction);
2375 33272 : current_function_builder_->EmitDirectCallIndex(function_info->index);
2376 : }
2377 : }
2378 :
2379 47326 : return return_type;
2380 : }
2381 :
2382 : // 6.9 ValidateCall - helper
2383 1269771 : bool AsmJsParser::PeekCall() {
2384 1354041 : if (!scanner_.IsGlobal()) {
2385 : return false;
2386 : }
2387 66167 : if (GetVarInfo(scanner_.Token())->kind == VarKind::kFunction) {
2388 : return true;
2389 : }
2390 35811 : if (GetVarInfo(scanner_.Token())->kind >= VarKind::kImportedFunction) {
2391 : return true;
2392 : }
2393 48459 : if (GetVarInfo(scanner_.Token())->kind == VarKind::kUnused ||
2394 22626 : GetVarInfo(scanner_.Token())->kind == VarKind::kTable) {
2395 7104 : scanner_.Next();
2396 7104 : if (Peek('(') || Peek('[')) {
2397 7053 : scanner_.Rewind();
2398 7053 : return true;
2399 : }
2400 51 : scanner_.Rewind();
2401 : }
2402 : return false;
2403 : }
2404 :
2405 : // 6.10 ValidateHeapAccess
2406 169658 : void AsmJsParser::ValidateHeapAccess() {
2407 169658 : VarInfo* info = GetVarInfo(Consume());
2408 169658 : int32_t size = info->type->ElementSizeInBytes();
2409 337190 : EXPECT_TOKEN('[');
2410 : uint32_t offset;
2411 169660 : 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 17892 : if (offset > 0x7FFFFFFF ||
2416 8944 : static_cast<uint64_t>(offset) * static_cast<uint64_t>(size) >
2417 : 0x7FFFFFFF) {
2418 8 : FAIL("Heap access out of range");
2419 : }
2420 8944 : if (Check(']')) {
2421 : current_function_builder_->EmitI32Const(
2422 2129 : static_cast<uint32_t>(offset * size));
2423 : // NOTE: This has to happen here to work recursively.
2424 2129 : heap_access_type_ = info->type;
2425 2129 : return;
2426 : } else {
2427 6815 : scanner_.Rewind();
2428 : }
2429 : }
2430 : AsmType* index_type;
2431 322264 : if (info->type->IsA(AsmType::Int8Array()) ||
2432 154737 : info->type->IsA(AsmType::Uint8Array())) {
2433 17143 : RECURSE(index_type = Expression(nullptr));
2434 : } else {
2435 150383 : RECURSE(index_type = ShiftExpression());
2436 150384 : if (heap_access_shift_position_ == kNoHeapAccessShift) {
2437 32 : FAIL("Expected shift of word size");
2438 : }
2439 150368 : if (heap_access_shift_value_ > 3) {
2440 16 : FAIL("Expected valid heap access shift");
2441 : }
2442 150360 : 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 150360 : current_function_builder_->DeleteCodeAfter(heap_access_shift_position_);
2447 : // Mask bottom bits to match asm.js behavior.
2448 150359 : current_function_builder_->EmitI32Const(~(size - 1));
2449 150360 : current_function_builder_->Emit(kExprI32And);
2450 : }
2451 167502 : if (!index_type->IsA(AsmType::Intish())) {
2452 0 : FAIL("Expected intish index");
2453 : }
2454 167503 : EXPECT_TOKEN(']');
2455 : // NOTE: This has to happen here to work recursively.
2456 167501 : heap_access_type_ = info->type;
2457 : }
2458 :
2459 : // 6.11 ValidateFloatCoercion
2460 437 : void AsmJsParser::ValidateFloatCoercion() {
2461 2185 : if (!scanner_.IsGlobal() ||
2462 437 : !GetVarInfo(scanner_.Token())->type->IsA(stdlib_fround_)) {
2463 0 : FAIL("Expected fround");
2464 : }
2465 437 : scanner_.Next();
2466 437 : EXPECT_TOKEN('(');
2467 437 : 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 437 : call_coercion_position_ = scanner_.Position();
2471 : AsmType* ret;
2472 437 : RECURSE(ret = ValidateExpression());
2473 437 : if (ret->IsA(AsmType::Floatish())) {
2474 : // Do nothing, as already a float.
2475 108 : } else if (ret->IsA(AsmType::DoubleQ())) {
2476 84 : current_function_builder_->Emit(kExprF32ConvertF64);
2477 24 : } else if (ret->IsA(AsmType::Signed())) {
2478 16 : current_function_builder_->Emit(kExprF32SConvertI32);
2479 8 : } else if (ret->IsA(AsmType::Unsigned())) {
2480 8 : current_function_builder_->Emit(kExprF32UConvertI32);
2481 : } else {
2482 0 : FAIL("Illegal conversion to float");
2483 : }
2484 437 : EXPECT_TOKEN(')');
2485 : }
2486 :
2487 125 : void AsmJsParser::ScanToClosingParenthesis() {
2488 : int depth = 0;
2489 : for (;;) {
2490 587 : if (Peek('(')) {
2491 64 : ++depth;
2492 523 : } else if (Peek(')')) {
2493 189 : --depth;
2494 189 : if (depth < 0) {
2495 : break;
2496 : }
2497 334 : } else if (Peek(AsmJsScanner::kEndOfInput)) {
2498 : break;
2499 : }
2500 462 : scanner_.Next();
2501 462 : }
2502 125 : }
2503 :
2504 612 : void AsmJsParser::GatherCases(ZoneVector<int32_t>* cases) {
2505 612 : size_t start = scanner_.Position();
2506 : int depth = 0;
2507 : for (;;) {
2508 464828 : if (Peek('{')) {
2509 12034 : ++depth;
2510 452794 : } else if (Peek('}')) {
2511 12026 : --depth;
2512 12026 : if (depth <= 0) {
2513 : break;
2514 : }
2515 440768 : } else if (depth == 1 && Peek(TOK(case))) {
2516 19994 : scanner_.Next();
2517 : uint32_t uvalue;
2518 : bool negate = false;
2519 19994 : if (Check('-')) negate = true;
2520 19994 : if (!CheckForUnsigned(&uvalue)) {
2521 : break;
2522 : }
2523 19990 : int32_t value = static_cast<int32_t>(uvalue);
2524 : DCHECK_IMPLIES(negate && uvalue == 0x80000000, value == kMinInt);
2525 19990 : if (negate && value != kMinInt) {
2526 4362 : value = -value;
2527 : }
2528 19990 : cases->push_back(value);
2529 420774 : } else if (Peek(AsmJsScanner::kEndOfInput) ||
2530 : Peek(AsmJsScanner::kParseError)) {
2531 : break;
2532 : }
2533 464216 : scanner_.Next();
2534 464216 : }
2535 612 : scanner_.Seek(start);
2536 612 : }
2537 :
2538 : } // namespace wasm
2539 : } // namespace internal
2540 178779 : } // namespace v8
2541 :
2542 : #undef RECURSE
|