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