Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(165)

Side by Side Diff: src/asmjs/asm-parser.cc

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

Powered by Google App Engine
This is Rietveld 408576698