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