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