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