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