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