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