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 351158 : AsmJsParser::AsmJsParser(Isolate* isolate, Zone* zone, Handle<Script> script,
73 : int start, int end)
74 : : zone_(zone),
75 351164 : module_builder_(new (zone) WasmModuleBuilder(zone)),
76 : return_type_(nullptr),
77 351161 : 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 1404642 : global_imports_(zone) {
92 351162 : InitializeStdlibTypes();
93 : Handle<String> source(String::cast(script->source()), isolate);
94 : std::unique_ptr<Utf16CharacterStream> stream(
95 351164 : ScannerStream::For(source, start, end));
96 702328 : scanner_.SetStream(std::move(stream));
97 351164 : }
98 :
99 4213958 : void AsmJsParser::InitializeStdlibTypes() {
100 : auto* d = AsmType::Double();
101 : auto* dq = AsmType::DoubleQ();
102 351162 : stdlib_dq2d_ = AsmType::Function(zone(), d);
103 : stdlib_dq2d_->AsFunctionType()->AddArgument(dq);
104 :
105 351164 : stdlib_dqdq2d_ = AsmType::Function(zone(), d);
106 : stdlib_dqdq2d_->AsFunctionType()->AddArgument(dq);
107 351164 : stdlib_dqdq2d_->AsFunctionType()->AddArgument(dq);
108 :
109 : auto* f = AsmType::Float();
110 : auto* fq = AsmType::FloatQ();
111 351164 : stdlib_fq2f_ = AsmType::Function(zone(), f);
112 : stdlib_fq2f_->AsFunctionType()->AddArgument(fq);
113 :
114 : auto* s = AsmType::Signed();
115 351164 : auto* s2s = AsmType::Function(zone(), s);
116 : s2s->AsFunctionType()->AddArgument(s);
117 :
118 : auto* i = AsmType::Int();
119 351162 : stdlib_i2s_ = AsmType::Function(zone_, s);
120 : stdlib_i2s_->AsFunctionType()->AddArgument(i);
121 :
122 351164 : stdlib_ii2s_ = AsmType::Function(zone(), s);
123 : stdlib_ii2s_->AsFunctionType()->AddArgument(i);
124 351164 : stdlib_ii2s_->AsFunctionType()->AddArgument(i);
125 :
126 351164 : 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 351162 : auto* minmax_f = AsmType::MinMaxType(zone(), f, f);
130 351160 : auto* minmax_i = AsmType::MinMaxType(zone(), s, i);
131 351163 : stdlib_minmax_ = AsmType::OverloadedFunction(zone());
132 351163 : stdlib_minmax_->AsOverloadedFunctionType()->AddOverload(minmax_i);
133 702330 : stdlib_minmax_->AsOverloadedFunctionType()->AddOverload(minmax_f);
134 702328 : stdlib_minmax_->AsOverloadedFunctionType()->AddOverload(minmax_d);
135 :
136 351163 : stdlib_abs_ = AsmType::OverloadedFunction(zone());
137 351168 : stdlib_abs_->AsOverloadedFunctionType()->AddOverload(s2s);
138 702328 : stdlib_abs_->AsOverloadedFunctionType()->AddOverload(stdlib_dq2d_);
139 702328 : stdlib_abs_->AsOverloadedFunctionType()->AddOverload(stdlib_fq2f_);
140 :
141 351164 : stdlib_ceil_like_ = AsmType::OverloadedFunction(zone());
142 702326 : stdlib_ceil_like_->AsOverloadedFunctionType()->AddOverload(stdlib_dq2d_);
143 702328 : stdlib_ceil_like_->AsOverloadedFunctionType()->AddOverload(stdlib_fq2f_);
144 :
145 351164 : stdlib_fround_ = AsmType::FroundType(zone());
146 351164 : }
147 :
148 7506 : FunctionSig* AsmJsParser::ConvertSignature(
149 15012 : AsmType* return_type, const std::vector<AsmType*>& params) {
150 : FunctionSig::Builder sig_builder(
151 7506 : zone(), !return_type->IsA(AsmType::Void()) ? 1 : 0, params.size());
152 29952 : 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 7506 : 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 7506 : return sig_builder.Build();
175 : }
176 :
177 351161 : bool AsmJsParser::Run() {
178 351161 : ValidateModule();
179 351164 : 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 15373 : function_defined(false) {}
208 :
209 278189 : wasm::AsmJsParser::VarInfo* AsmJsParser::GetVarInfo(
210 : AsmJsScanner::token_t token) {
211 278189 : if (AsmJsScanner::IsGlobal(token)) {
212 448500 : size_t old = global_var_info_.size();
213 : size_t index = AsmJsScanner::GlobalIndex(token);
214 299000 : size_t sz = std::max(old, index + 1);
215 149500 : if (sz != old) {
216 4651 : 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 7674 : Vector<const char> AsmJsParser::CopyCurrentIdentifierString() {
274 3837 : const std::string& str = scanner_.GetIdentifierString();
275 : char* buffer = zone()->NewArray<char>(str.size());
276 3837 : str.copy(buffer, str.size());
277 3837 : return Vector<const char>(buffer, static_cast<int>(str.size()));
278 : }
279 :
280 52220 : void AsmJsParser::SkipSemicolon() {
281 52220 : 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 351711 : void AsmJsParser::ValidateModule() {
341 1047002 : RECURSE(ValidateModuleParameters());
342 179643 : EXPECT_TOKEN('{');
343 340817 : EXPECT_TOKEN(TOK(UseAsm));
344 909 : SkipSemicolon();
345 909 : RECURSE(ValidateModuleVars());
346 2940 : while (Peek(TOK(function))) {
347 2265 : RECURSE(ValidateFunction());
348 : }
349 713 : while (Peek(TOK(var))) {
350 60 : RECURSE(ValidateFunctionTable());
351 : }
352 653 : RECURSE(ValidateExport());
353 :
354 : // Check that all functions were eventually defined.
355 6909 : for (auto& info : global_var_info_) {
356 5793 : if (info.kind == VarKind::kFunction && !info.function_defined) {
357 20 : FAIL("Undefined function");
358 : }
359 5783 : 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 549 : WasmFunctionBuilder* start = module_builder_->AddFunction();
366 549 : module_builder_->MarkStartFunction(start);
367 1783 : 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 549 : start->Emit(kExprEnd);
375 : FunctionSig::Builder b(zone(), 0, 0);
376 549 : start->SetSignature(b.Build());
377 : }
378 :
379 : // 6.1 ValidateModule - parameters
380 351161 : void AsmJsParser::ValidateModuleParameters() {
381 611901 : EXPECT_TOKEN('(');
382 254592 : stdlib_name_ = 0;
383 254592 : foreign_name_ = 0;
384 254592 : heap_name_ = 0;
385 254592 : if (!Peek(')')) {
386 189136 : if (!scanner_.IsGlobal()) {
387 144022 : FAIL("Expected stdlib parameter");
388 : }
389 117125 : stdlib_name_ = Consume();
390 117125 : if (!Peek(')')) {
391 81562 : EXPECT_TOKEN(',');
392 79732 : if (!scanner_.IsGlobal()) {
393 122 : FAIL("Expected foreign parameter");
394 : }
395 79671 : foreign_name_ = Consume();
396 79671 : if (!Peek(')')) {
397 17865 : EXPECT_TOKEN(',');
398 17529 : if (!scanner_.IsGlobal()) {
399 72 : FAIL("Expected heap parameter");
400 : }
401 17493 : heap_name_ = Consume();
402 : }
403 : }
404 : }
405 187549 : EXPECT_TOKEN(')');
406 : }
407 :
408 : // 6.1 ValidateModule - variables
409 909 : void AsmJsParser::ValidateModuleVars() {
410 4011 : 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 : uint32_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 612 : 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 : uint32_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 653 : void AsmJsParser::ValidateExport() {
617 : // clang-format off
618 2209 : EXPECT_TOKEN(TOK(return));
619 : // clang format on
620 643 : if (Check('{')) {
621 : for (;;) {
622 995 : Vector<const char> name = CopyCurrentIdentifierString();
623 995 : if (!scanner_.IsGlobal() && !scanner_.IsLocal()) {
624 197 : FAIL("Illegal export name");
625 : }
626 : Consume();
627 931 : EXPECT_TOKEN(':');
628 929 : if (!scanner_.IsGlobal()) {
629 2 : FAIL("Expected function name");
630 : }
631 928 : VarInfo* info = GetVarInfo(Consume());
632 928 : if (info->kind != VarKind::kFunction) {
633 0 : FAIL("Expected function");
634 : }
635 928 : info->function_builder->ExportAs(name);
636 928 : if (Check(',')) {
637 389 : if (!Peek('}')) {
638 378 : continue;
639 : }
640 : }
641 550 : break;
642 378 : }
643 550 : 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 4330 : void AsmJsParser::ValidateFunction() {
714 6883 : EXPECT_TOKEN(TOK(function));
715 2265 : if (!scanner_.IsGlobal()) {
716 0 : FAIL("Expected function name");
717 : }
718 :
719 2265 : Vector<const char> function_name_str = CopyCurrentIdentifierString();
720 : AsmJsScanner::token_t function_name = Consume();
721 2265 : VarInfo* function_info = GetVarInfo(function_name);
722 2265 : if (function_info->kind == VarKind::kUnused) {
723 1840 : function_info->kind = VarKind::kFunction;
724 1840 : function_info->function_builder = module_builder_->AddFunction();
725 1840 : 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 2250 : function_info->function_defined = true;
733 2250 : function_info->function_builder->SetName(function_name_str);
734 2250 : current_function_builder_ = function_info->function_builder;
735 2250 : return_type_ = nullptr;
736 :
737 : // Record start of the function, used as position for the stack check.
738 2250 : int start_position = static_cast<int>(scanner_.Position());
739 2250 : current_function_builder_->SetAsmFunctionStartPosition(start_position);
740 :
741 : std::vector<AsmType*> params;
742 2250 : ValidateFunctionParams(¶ms);
743 : std::vector<ValueType> locals;
744 4500 : ValidateFunctionLocals(params.size(), &locals);
745 :
746 : function_temp_locals_offset_ = static_cast<uint32_t>(
747 6750 : params.size() + locals.size());
748 2250 : function_temp_locals_used_ = 0;
749 2250 : function_temp_locals_depth_ = 0;
750 :
751 31989 : while (!failed_ && !Peek('}')) {
752 12786 : RECURSE(ValidateStatement());
753 : }
754 2139 : EXPECT_TOKEN('}');
755 :
756 2065 : if (return_type_ == nullptr) {
757 379 : 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 2065 : FunctionSig* sig = ConvertSignature(return_type_, params);
763 2065 : if (sig == nullptr) {
764 0 : FAIL("Invalid function signature in declaration");
765 : }
766 2065 : current_function_builder_->SetSignature(sig);
767 9238 : 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 2065 : current_function_builder_->Emit(kExprEnd);
777 :
778 : // Record (or validate) function type.
779 4130 : AsmType* function_type = AsmType::Function(zone(), return_type_);
780 7263 : for (auto t : params) {
781 : function_type->AsFunctionType()->AddArgument(t);
782 : }
783 2065 : function_info = GetVarInfo(function_name);
784 2065 : if (function_info->type->IsA(AsmType::None())) {
785 : DCHECK(function_info->kind == VarKind::kFunction);
786 1644 : 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 2058 : scanner_.ResetLocals();
793 : local_var_info_.clear();
794 : }
795 :
796 : // 6.4 ValidateFunction
797 5595 : 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 17331 : scanner_.EnterLocalScope();
802 2280 : EXPECT_TOKEN('(');
803 : std::vector<AsmJsScanner::token_t> function_parameters;
804 11258 : 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 2250 : EXPECT_TOKEN(')');
814 : scanner_.EnterGlobalScope();
815 2250 : EXPECT_TOKEN('{');
816 : // 5.1 Parameter Type Annotations
817 7845 : 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 2250 : void AsmJsParser::ValidateFunctionLocals(
857 5186 : size_t param_count, std::vector<ValueType>* locals) {
858 : // Local Variables.
859 5516 : 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 : uint32_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 : 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 63700 : void AsmJsParser::ValidateStatement() {
988 63700 : call_coercion_ = nullptr;
989 63700 : if (Peek('{')) {
990 11044 : RECURSE(Block());
991 52656 : } else if (Peek(';')) {
992 7 : RECURSE(EmptyStatement());
993 52649 : } else if (Peek(TOK(if))) {
994 6800 : RECURSE(IfStatement());
995 : // clang-format off
996 45849 : } else if (Peek(TOK(return))) {
997 : // clang-format on
998 5894 : 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 5894 : void AsmJsParser::ReturnStatement() {
1071 : // clang-format off
1072 5907 : EXPECT_TOKEN(TOK(return ));
1073 : // clang-format on
1074 5894 : if (!Peek(';') && !Peek('}')) {
1075 : // TODO(bradnelson): See if this can be factored out.
1076 : AsmType* ret;
1077 5163 : 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 : uint32_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 67885 : AsmType* AsmJsParser::Expression(AsmType* expected) {
1337 : AsmType* a;
1338 : for (;;) {
1339 69147 : 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 71123 : AsmType* AsmJsParser::NumericLiteral() {
1360 71123 : call_coercion_ = nullptr;
1361 : double dvalue = 0.0;
1362 : uint32_t uvalue = 0;
1363 71123 : if (CheckForDouble(&dvalue)) {
1364 829 : current_function_builder_->EmitF64Const(dvalue);
1365 829 : return AsmType::Double();
1366 70294 : } 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 : } else if (uvalue <= 0xffffffff) {
1371 27 : current_function_builder_->EmitI32Const(static_cast<int32_t>(uvalue));
1372 27 : return AsmType::Unsigned();
1373 : } else {
1374 8 : FAILn("Integer numeric literal out of range.");
1375 : }
1376 : } else {
1377 16 : 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 176536 : AsmType* AsmJsParser::CallExpression() {
1405 : AsmType* ret;
1406 204568 : if (scanner_.IsGlobal() &&
1407 28032 : GetVarInfo(scanner_.Token())->type->IsA(stdlib_fround_)) {
1408 77 : ValidateFloatCoercion();
1409 77 : return AsmType::Float();
1410 204414 : } else if (scanner_.IsGlobal() &&
1411 27955 : GetVarInfo(scanner_.Token())->type->IsA(AsmType::Heap())) {
1412 20985 : RECURSEn(ret = MemberExpression());
1413 155474 : } else if (Peek('(')) {
1414 16724 : RECURSEn(ret = ParenthesizedExpression());
1415 138750 : } else if (PeekCall()) {
1416 5446 : RECURSEn(ret = ValidateCall());
1417 133304 : } else if (scanner_.IsLocal() || scanner_.IsGlobal()) {
1418 62181 : RECURSEn(ret = Identifier());
1419 : } else {
1420 71123 : 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 115243 : AsmType* AsmJsParser::AssignmentExpression() {
1447 : AsmType* ret;
1448 143661 : 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 95781 : } 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 27363 : RECURSEn(ret = ConditionalExpression());
1514 : }
1515 82410 : return ret;
1516 : }
1517 :
1518 : // 6.8.7 UnaryExpression
1519 180664 : AsmType* AsmJsParser::UnaryExpression() {
1520 : AsmType* ret;
1521 180664 : if (Check('-')) {
1522 : uint32_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 179589 : } 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 177358 : } 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 176682 : } 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 176536 : RECURSEn(ret = CallExpression());
1598 : }
1599 180522 : return ret;
1600 : }
1601 :
1602 : // 6.8.8 MultiplicativeExpression
1603 178497 : AsmType* AsmJsParser::MultiplicativeExpression() {
1604 : uint32_t uvalue;
1605 178497 : 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 : int32_t value = static_cast<int32_t>(uvalue);
1613 2 : current_function_builder_->EmitI32Const(value);
1614 2 : current_function_builder_->Emit(kExprI32Mul);
1615 2 : return AsmType::Intish();
1616 : }
1617 69179 : scanner_.Rewind();
1618 109316 : } else if (Check('-')) {
1619 3374 : if (CheckForUnsignedBelow(0x100000, &uvalue)) {
1620 2343 : int32_t value = -static_cast<int32_t>(uvalue);
1621 2343 : current_function_builder_->EmitI32Const(value);
1622 2343 : if (Check('*')) {
1623 : AsmType* a;
1624 0 : RECURSEn(a = UnaryExpression());
1625 0 : if (!a->IsA(AsmType::Int())) {
1626 0 : FAILn("Expected int");
1627 : }
1628 0 : current_function_builder_->Emit(kExprI32Mul);
1629 0 : return AsmType::Intish();
1630 : }
1631 : return AsmType::Signed();
1632 : }
1633 1031 : scanner_.Rewind();
1634 : }
1635 : AsmType* a;
1636 176152 : RECURSEn(a = UnaryExpression());
1637 : for (;;) {
1638 177575 : if (Check('*')) {
1639 : uint32_t uvalue;
1640 1912 : if (Check('-')) {
1641 3 : if (CheckForUnsigned(&uvalue)) {
1642 2 : if (uvalue >= 0x100000) {
1643 0 : FAILn("Constant multiple out of range");
1644 : }
1645 2 : if (!a->IsA(AsmType::Int())) {
1646 2 : FAILn("Integer multiply of expects int");
1647 : }
1648 1 : int32_t value = -static_cast<int32_t>(uvalue);
1649 1 : current_function_builder_->EmitI32Const(value);
1650 1 : current_function_builder_->Emit(kExprI32Mul);
1651 1 : return AsmType::Intish();
1652 : }
1653 1 : scanner_.Rewind();
1654 1909 : } else if (CheckForUnsigned(&uvalue)) {
1655 629 : if (uvalue >= 0x100000) {
1656 0 : FAILn("Constant multiple out of range");
1657 : }
1658 629 : if (!a->IsA(AsmType::Int())) {
1659 2 : FAILn("Integer multiply of expects int");
1660 : }
1661 628 : int32_t value = static_cast<int32_t>(uvalue);
1662 628 : current_function_builder_->EmitI32Const(value);
1663 628 : current_function_builder_->Emit(kExprI32Mul);
1664 628 : return AsmType::Intish();
1665 : }
1666 : AsmType* b;
1667 1281 : RECURSEn(b = UnaryExpression());
1668 1281 : if (a->IsA(AsmType::DoubleQ()) && b->IsA(AsmType::DoubleQ())) {
1669 1280 : current_function_builder_->Emit(kExprF64Mul);
1670 : a = AsmType::Double();
1671 1 : } else if (a->IsA(AsmType::FloatQ()) && b->IsA(AsmType::FloatQ())) {
1672 1 : current_function_builder_->Emit(kExprF32Mul);
1673 : a = AsmType::Floatish();
1674 : } else {
1675 0 : FAILn("expected doubles or floats");
1676 : }
1677 175663 : } else if (Check('/')) {
1678 : AsmType* b;
1679 145 : RECURSEn(b = MultiplicativeExpression());
1680 145 : if (a->IsA(AsmType::DoubleQ()) && b->IsA(AsmType::DoubleQ())) {
1681 68 : current_function_builder_->Emit(kExprF64Div);
1682 : a = AsmType::Double();
1683 77 : } else if (a->IsA(AsmType::FloatQ()) && b->IsA(AsmType::FloatQ())) {
1684 1 : current_function_builder_->Emit(kExprF32Div);
1685 : a = AsmType::Floatish();
1686 76 : } else if (a->IsA(AsmType::Signed()) && b->IsA(AsmType::Signed())) {
1687 50 : current_function_builder_->Emit(kExprI32AsmjsDivS);
1688 : a = AsmType::Intish();
1689 26 : } else if (a->IsA(AsmType::Unsigned()) && b->IsA(AsmType::Unsigned())) {
1690 26 : current_function_builder_->Emit(kExprI32AsmjsDivU);
1691 : a = AsmType::Intish();
1692 : } else {
1693 0 : FAILn("expected doubles or floats");
1694 : }
1695 175518 : } else if (Check('%')) {
1696 : AsmType* b;
1697 109 : RECURSEn(b = MultiplicativeExpression());
1698 109 : if (a->IsA(AsmType::DoubleQ()) && b->IsA(AsmType::DoubleQ())) {
1699 4 : current_function_builder_->Emit(kExprF64Mod);
1700 : a = AsmType::Double();
1701 105 : } else if (a->IsA(AsmType::Signed()) && b->IsA(AsmType::Signed())) {
1702 70 : current_function_builder_->Emit(kExprI32AsmjsRemS);
1703 : a = AsmType::Intish();
1704 35 : } else if (a->IsA(AsmType::Unsigned()) && b->IsA(AsmType::Unsigned())) {
1705 35 : current_function_builder_->Emit(kExprI32AsmjsRemU);
1706 : a = AsmType::Intish();
1707 : } else {
1708 0 : FAILn("expected doubles or floats");
1709 : }
1710 : } else {
1711 : break;
1712 : }
1713 : }
1714 : return a;
1715 : }
1716 :
1717 : // 6.8.9 AdditiveExpression
1718 157107 : AsmType* AsmJsParser::AdditiveExpression() {
1719 : AsmType* a;
1720 157144 : RECURSEn(a = MultiplicativeExpression());
1721 : int n = 0;
1722 : for (;;) {
1723 178092 : if (Check('+')) {
1724 : AsmType* b;
1725 19629 : RECURSEn(b = MultiplicativeExpression());
1726 19628 : if (a->IsA(AsmType::Double()) && b->IsA(AsmType::Double())) {
1727 749 : current_function_builder_->Emit(kExprF64Add);
1728 : a = AsmType::Double();
1729 18879 : } else if (a->IsA(AsmType::FloatQ()) && b->IsA(AsmType::FloatQ())) {
1730 5 : current_function_builder_->Emit(kExprF32Add);
1731 : a = AsmType::Floatish();
1732 18874 : } else if (a->IsA(AsmType::Int()) && b->IsA(AsmType::Int())) {
1733 16921 : current_function_builder_->Emit(kExprI32Add);
1734 : a = AsmType::Intish();
1735 : n = 2;
1736 1953 : } else if (a->IsA(AsmType::Intish()) && b->IsA(AsmType::Intish())) {
1737 : // TODO(bradnelson): b should really only be Int.
1738 : // specialize intish to capture count.
1739 1916 : ++n;
1740 1916 : if (n > (1 << 20)) {
1741 0 : FAILn("more than 2^20 additive values");
1742 : }
1743 1916 : current_function_builder_->Emit(kExprI32Add);
1744 : } else {
1745 74 : FAILn("illegal types for +");
1746 : }
1747 158463 : } else if (Check('-')) {
1748 : AsmType* b;
1749 1507 : RECURSEn(b = MultiplicativeExpression());
1750 1507 : if (a->IsA(AsmType::Double()) && b->IsA(AsmType::Double())) {
1751 585 : current_function_builder_->Emit(kExprF64Sub);
1752 : a = AsmType::Double();
1753 922 : } else if (a->IsA(AsmType::FloatQ()) && b->IsA(AsmType::FloatQ())) {
1754 1 : current_function_builder_->Emit(kExprF32Sub);
1755 : a = AsmType::Floatish();
1756 921 : } else if (a->IsA(AsmType::Int()) && b->IsA(AsmType::Int())) {
1757 880 : current_function_builder_->Emit(kExprI32Sub);
1758 : a = AsmType::Intish();
1759 : n = 2;
1760 41 : } else if (a->IsA(AsmType::Intish()) && b->IsA(AsmType::Intish())) {
1761 : // TODO(bradnelson): b should really only be Int.
1762 : // specialize intish to capture count.
1763 41 : ++n;
1764 41 : if (n > (1 << 20)) {
1765 0 : FAILn("more than 2^20 additive values");
1766 : }
1767 41 : current_function_builder_->Emit(kExprI32Sub);
1768 : } else {
1769 0 : FAILn("illegal types for +");
1770 : }
1771 : } else {
1772 : break;
1773 : }
1774 : }
1775 : return a;
1776 : }
1777 :
1778 : // 6.8.10 ShiftExpression
1779 132263 : AsmType* AsmJsParser::ShiftExpression() {
1780 : AsmType* a = nullptr;
1781 132263 : RECURSEn(a = AdditiveExpression());
1782 : for (;;) {
1783 138517 : switch (scanner_.Token()) {
1784 : // TODO(bradnelson): Implement backtracking to avoid emitting code
1785 : // for the x >>> 0 case (similar to what's there for |0).
1786 : #define HANDLE_CASE(op, opcode, name, result) \
1787 : case TOK(op): { \
1788 : EXPECT_TOKENn(TOK(op)); \
1789 : AsmType* b = nullptr; \
1790 : RECURSEn(b = AdditiveExpression()); \
1791 : if (!(a->IsA(AsmType::Intish()) && b->IsA(AsmType::Intish()))) { \
1792 : FAILn("Expected intish for operator " #name "."); \
1793 : } \
1794 : current_function_builder_->Emit(kExpr##opcode); \
1795 : a = AsmType::result(); \
1796 : continue; \
1797 : }
1798 5252 : HANDLE_CASE(SHL, I32Shl, "<<", Signed);
1799 762 : HANDLE_CASE(SAR, I32ShrS, ">>", Signed);
1800 6796 : HANDLE_CASE(SHR, I32ShrU, ">>>", Unsigned);
1801 : #undef HANDLE_CASE
1802 : default:
1803 : return a;
1804 : }
1805 : }
1806 : }
1807 :
1808 : // 6.8.11 RelationalExpression
1809 129177 : AsmType* AsmJsParser::RelationalExpression() {
1810 : AsmType* a = nullptr;
1811 129186 : RECURSEn(a = ShiftExpression());
1812 : for (;;) {
1813 132103 : switch (scanner_.Token()) {
1814 : #define HANDLE_CASE(op, sop, uop, dop, fop, name) \
1815 : case op: { \
1816 : EXPECT_TOKENn(op); \
1817 : AsmType* b = nullptr; \
1818 : RECURSEn(b = ShiftExpression()); \
1819 : if (a->IsA(AsmType::Signed()) && b->IsA(AsmType::Signed())) { \
1820 : current_function_builder_->Emit(kExpr##sop); \
1821 : } else if (a->IsA(AsmType::Unsigned()) && b->IsA(AsmType::Unsigned())) { \
1822 : current_function_builder_->Emit(kExpr##uop); \
1823 : } else if (a->IsA(AsmType::Double()) && b->IsA(AsmType::Double())) { \
1824 : current_function_builder_->Emit(kExpr##dop); \
1825 : } else if (a->IsA(AsmType::Float()) && b->IsA(AsmType::Float())) { \
1826 : current_function_builder_->Emit(kExpr##fop); \
1827 : } else { \
1828 : FAILn("Expected signed, unsigned, double, or float for operator " #name \
1829 : "."); \
1830 : } \
1831 : a = AsmType::Int(); \
1832 : continue; \
1833 : }
1834 3134 : HANDLE_CASE('<', I32LtS, I32LtU, F64Lt, F32Lt, "<");
1835 566 : HANDLE_CASE(TOK(LE), I32LeS, I32LeU, F64Le, F32Le, "<=");
1836 2081 : HANDLE_CASE('>', I32GtS, I32GtU, F64Gt, F32Gt, ">");
1837 400 : HANDLE_CASE(TOK(GE), I32GeS, I32GeU, F64Ge, F32Ge, ">=");
1838 : #undef HANDLE_CASE
1839 : default:
1840 : return a;
1841 : }
1842 : }
1843 : }
1844 :
1845 : // 6.8.12 EqualityExpression
1846 123825 : AsmType* AsmJsParser::EqualityExpression() {
1847 : AsmType* a = nullptr;
1848 123829 : RECURSEn(a = RelationalExpression());
1849 : for (;;) {
1850 129013 : switch (scanner_.Token()) {
1851 : #define HANDLE_CASE(op, sop, uop, dop, fop, name) \
1852 : case op: { \
1853 : EXPECT_TOKENn(op); \
1854 : AsmType* b = nullptr; \
1855 : RECURSEn(b = RelationalExpression()); \
1856 : if (a->IsA(AsmType::Signed()) && b->IsA(AsmType::Signed())) { \
1857 : current_function_builder_->Emit(kExpr##sop); \
1858 : } else if (a->IsA(AsmType::Unsigned()) && b->IsA(AsmType::Unsigned())) { \
1859 : current_function_builder_->Emit(kExpr##uop); \
1860 : } else if (a->IsA(AsmType::Double()) && b->IsA(AsmType::Double())) { \
1861 : current_function_builder_->Emit(kExpr##dop); \
1862 : } else if (a->IsA(AsmType::Float()) && b->IsA(AsmType::Float())) { \
1863 : current_function_builder_->Emit(kExpr##fop); \
1864 : } else { \
1865 : FAILn("Expected signed, unsigned, double, or float for operator " #name \
1866 : "."); \
1867 : } \
1868 : a = AsmType::Int(); \
1869 : continue; \
1870 : }
1871 7597 : HANDLE_CASE(TOK(EQ), I32Eq, I32Eq, F64Eq, F32Eq, "==");
1872 3111 : HANDLE_CASE(TOK(NE), I32Ne, I32Ne, F64Ne, F32Ne, "!=");
1873 : #undef HANDLE_CASE
1874 : default:
1875 : return a;
1876 : }
1877 : }
1878 : }
1879 :
1880 : // 6.8.13 BitwiseANDExpression
1881 121412 : AsmType* AsmJsParser::BitwiseANDExpression() {
1882 : AsmType* a = nullptr;
1883 121413 : RECURSEn(a = EqualityExpression());
1884 123426 : while (Check('&')) {
1885 : AsmType* b = nullptr;
1886 2179 : RECURSEn(b = EqualityExpression());
1887 2179 : if (a->IsA(AsmType::Intish()) && b->IsA(AsmType::Intish())) {
1888 2178 : current_function_builder_->Emit(kExprI32And);
1889 : a = AsmType::Signed();
1890 : } else {
1891 2 : FAILn("Expected intish for operator &.");
1892 : }
1893 : }
1894 : return a;
1895 : }
1896 :
1897 : // 6.8.14 BitwiseXORExpression
1898 121288 : AsmType* AsmJsParser::BitwiseXORExpression() {
1899 : AsmType* a = nullptr;
1900 121288 : RECURSEn(a = BitwiseANDExpression());
1901 121247 : while (Check('^')) {
1902 : AsmType* b = nullptr;
1903 124 : RECURSEn(b = BitwiseANDExpression());
1904 124 : if (a->IsA(AsmType::Intish()) && b->IsA(AsmType::Intish())) {
1905 124 : current_function_builder_->Emit(kExprI32Xor);
1906 : a = AsmType::Signed();
1907 : } else {
1908 0 : FAILn("Expected intish for operator &.");
1909 : }
1910 : }
1911 : return a;
1912 : }
1913 :
1914 : // 6.8.15 BitwiseORExpression
1915 91088 : AsmType* AsmJsParser::BitwiseORExpression() {
1916 : AsmType* a = nullptr;
1917 149259 : call_coercion_deferred_position_ = scanner_.Position();
1918 91088 : RECURSEn(a = BitwiseXORExpression());
1919 121118 : while (Check('|')) {
1920 : AsmType* b = nullptr;
1921 : // Remember whether the first operand to this OR-expression has requested
1922 : // deferred validation of the |0 annotation.
1923 : // NOTE: This has to happen here to work recursively.
1924 30200 : bool requires_zero = call_coercion_deferred_->IsExactly(AsmType::Signed());
1925 30200 : call_coercion_deferred_ = nullptr;
1926 : // TODO(bradnelson): Make it prettier.
1927 : bool zero = false;
1928 : size_t old_pos;
1929 : size_t old_code;
1930 30200 : if (a->IsA(AsmType::Intish()) && CheckForZero()) {
1931 : old_pos = scanner_.Position();
1932 29083 : old_code = current_function_builder_->GetPosition();
1933 29083 : scanner_.Rewind();
1934 : zero = true;
1935 : }
1936 30200 : RECURSEn(b = BitwiseXORExpression());
1937 : // Handle |0 specially.
1938 59283 : if (zero && old_pos == scanner_.Position()) {
1939 29068 : current_function_builder_->DeleteCodeAfter(old_code);
1940 : a = AsmType::Signed();
1941 29068 : continue;
1942 : }
1943 : // Anything not matching |0 breaks the lookahead in {ValidateCall}.
1944 1132 : if (requires_zero) {
1945 6 : FAILn("Expected |0 type annotation for call");
1946 : }
1947 1129 : if (a->IsA(AsmType::Intish()) && b->IsA(AsmType::Intish())) {
1948 1127 : current_function_builder_->Emit(kExprI32Ior);
1949 : a = AsmType::Signed();
1950 : } else {
1951 4 : FAILn("Expected intish for operator |.");
1952 : }
1953 : }
1954 : DCHECK_NULL(call_coercion_deferred_);
1955 : return a;
1956 : }
1957 :
1958 : // 6.8.16 ConditionalExpression
1959 91088 : AsmType* AsmJsParser::ConditionalExpression() {
1960 : AsmType* test = nullptr;
1961 92221 : RECURSEn(test = BitwiseORExpression());
1962 90918 : if (Check('?')) {
1963 1133 : if (!test->IsA(AsmType::Int())) {
1964 0 : FAILn("Expected int in condition of ternary operator.");
1965 : }
1966 1133 : current_function_builder_->EmitWithU8(kExprIf, kLocalI32);
1967 1133 : size_t fixup = current_function_builder_->GetPosition() -
1968 1133 : 1; // Assumes encoding knowledge.
1969 : AsmType* cons = nullptr;
1970 1133 : RECURSEn(cons = AssignmentExpression());
1971 1133 : current_function_builder_->Emit(kExprElse);
1972 1133 : EXPECT_TOKENn(':');
1973 : AsmType* alt = nullptr;
1974 1133 : RECURSEn(alt = AssignmentExpression());
1975 1133 : current_function_builder_->Emit(kExprEnd);
1976 1133 : if (cons->IsA(AsmType::Int()) && alt->IsA(AsmType::Int())) {
1977 1025 : current_function_builder_->FixupByte(fixup, kLocalI32);
1978 1025 : return AsmType::Int();
1979 108 : } else if (cons->IsA(AsmType::Double()) && alt->IsA(AsmType::Double())) {
1980 108 : current_function_builder_->FixupByte(fixup, kLocalF64);
1981 108 : return AsmType::Double();
1982 0 : } else if (cons->IsA(AsmType::Float()) && alt->IsA(AsmType::Float())) {
1983 0 : current_function_builder_->FixupByte(fixup, kLocalF32);
1984 0 : return AsmType::Float();
1985 : } else {
1986 0 : FAILn("Type mismatch in ternary operator.");
1987 : }
1988 : } else {
1989 : return test;
1990 : }
1991 : }
1992 :
1993 : // 6.8.17 ParenthesiedExpression
1994 16724 : AsmType* AsmJsParser::ParenthesizedExpression() {
1995 16724 : call_coercion_ = nullptr;
1996 : AsmType* ret;
1997 33381 : EXPECT_TOKENn('(');
1998 16724 : RECURSEn(ret = Expression(nullptr));
1999 16657 : EXPECT_TOKENn(')');
2000 16657 : return ret;
2001 : }
2002 :
2003 : // 6.9 ValidateCall
2004 16329 : AsmType* AsmJsParser::ValidateCall() {
2005 5446 : AsmType* return_type = call_coercion_;
2006 5446 : call_coercion_ = nullptr;
2007 19421 : int call_pos = static_cast<int>(scanner_.Position());
2008 5446 : int to_number_pos = static_cast<int>(call_coercion_position_);
2009 5446 : bool allow_peek = (call_coercion_deferred_position_ == scanner_.Position());
2010 : AsmJsScanner::token_t function_name = Consume();
2011 :
2012 : // Distinguish between ordinary function calls and function table calls. In
2013 : // both cases we might be seeing the {function_name} for the first time and
2014 : // hence allocate a {VarInfo} here, all subsequent uses of the same name then
2015 : // need to match the information stored at this point.
2016 : // TODO(mstarzinger): Consider using Chromiums base::Optional instead.
2017 : std::unique_ptr<TemporaryVariableScope> tmp;
2018 5446 : if (Check('[')) {
2019 234 : RECURSEn(EqualityExpression());
2020 234 : EXPECT_TOKENn('&');
2021 : uint32_t mask = 0;
2022 234 : if (!CheckForUnsigned(&mask)) {
2023 0 : FAILn("Expected mask literal");
2024 : }
2025 : // TODO(mstarzinger): Clarify and explain where this limit is coming from,
2026 : // as it is not mandated by the spec directly.
2027 234 : if (mask > 0x7fffffff) {
2028 0 : FAILn("Expected power of 2 mask");
2029 : }
2030 468 : if (!base::bits::IsPowerOfTwo32(static_cast<uint32_t>(1 + mask))) {
2031 0 : FAILn("Expected power of 2 mask");
2032 : }
2033 234 : current_function_builder_->EmitI32Const(static_cast<uint32_t>(mask));
2034 234 : current_function_builder_->Emit(kExprI32And);
2035 234 : EXPECT_TOKENn(']');
2036 234 : VarInfo* function_info = GetVarInfo(function_name);
2037 234 : if (function_info->kind == VarKind::kUnused) {
2038 60 : function_info->kind = VarKind::kTable;
2039 60 : function_info->mask = static_cast<int32_t>(mask);
2040 : function_info->index = module_builder_->AllocateIndirectFunctions(
2041 60 : static_cast<uint32_t>(mask + 1));
2042 : } else {
2043 174 : if (function_info->kind != VarKind::kTable) {
2044 6 : FAILn("Expected call table");
2045 : }
2046 171 : if (function_info->mask != static_cast<int32_t>(mask)) {
2047 0 : FAILn("Mask size mismatch");
2048 : }
2049 : }
2050 231 : current_function_builder_->EmitI32Const(function_info->index);
2051 231 : current_function_builder_->Emit(kExprI32Add);
2052 : // We have to use a temporary for the correct order of evaluation.
2053 231 : tmp.reset(new TemporaryVariableScope(this));
2054 462 : current_function_builder_->EmitSetLocal(tmp.get()->get());
2055 : // The position of function table calls is after the table lookup.
2056 231 : call_pos = static_cast<int>(scanner_.Position());
2057 : } else {
2058 5212 : VarInfo* function_info = GetVarInfo(function_name);
2059 5212 : if (function_info->kind == VarKind::kUnused) {
2060 424 : function_info->kind = VarKind::kFunction;
2061 424 : function_info->function_builder = module_builder_->AddFunction();
2062 424 : function_info->index = function_info->function_builder->func_index();
2063 : } else {
2064 4788 : if (function_info->kind != VarKind::kFunction &&
2065 : function_info->kind < VarKind::kImportedFunction) {
2066 2 : FAILn("Expected function as call target");
2067 : }
2068 : }
2069 : }
2070 :
2071 : // Parse argument list and gather types.
2072 : std::vector<AsmType*> param_types;
2073 : ZoneVector<AsmType*> param_specific_types(zone());
2074 5443 : EXPECT_TOKENn('(');
2075 22689 : while (!failed_ && !Peek(')')) {
2076 : AsmType* t;
2077 11807 : RECURSEn(t = AssignmentExpression());
2078 11807 : param_specific_types.push_back(t);
2079 11807 : if (t->IsA(AsmType::Int())) {
2080 23012 : param_types.push_back(AsmType::Int());
2081 301 : } else if (t->IsA(AsmType::Float())) {
2082 36 : param_types.push_back(AsmType::Float());
2083 283 : } else if (t->IsA(AsmType::Double())) {
2084 566 : param_types.push_back(AsmType::Double());
2085 : } else {
2086 0 : FAILn("Bad function argument type");
2087 : }
2088 11807 : if (!Peek(')')) {
2089 7036 : EXPECT_TOKENn(',');
2090 : }
2091 : }
2092 5441 : EXPECT_TOKENn(')');
2093 :
2094 : // Reload {VarInfo} after parsing arguments as table might have grown.
2095 5441 : VarInfo* function_info = GetVarInfo(function_name);
2096 :
2097 : // We potentially use lookahead in order to determine the return type in case
2098 : // it is not yet clear from the call context. Special care has to be taken to
2099 : // ensure the non-contextual lookahead is valid. The following restrictions
2100 : // substantiate the validity of the lookahead implemented below:
2101 : // - All calls (except stdlib calls) require some sort of type annotation.
2102 : // - The coercion to "signed" is part of the {BitwiseORExpression}, any
2103 : // intermittent expressions like parenthesis in `(callsite(..))|0` are
2104 : // syntactically not considered coercions.
2105 : // - The coercion to "double" as part of the {UnaryExpression} has higher
2106 : // precedence and wins in `+callsite(..)|0` cases. Only "float" return
2107 : // types are overridden in `fround(callsite(..)|0)` expressions.
2108 : // - Expected coercions to "signed" are flagged via {call_coercion_deferred}
2109 : // and later on validated as part of {BitwiseORExpression} to ensure they
2110 : // indeed apply to the current call expression.
2111 : // - The deferred validation is only allowed if {BitwiseORExpression} did
2112 : // promise to fulfill the request via {call_coercion_deferred_position}.
2113 13055 : if (allow_peek && Peek('|') &&
2114 10231 : function_info->kind <= VarKind::kImportedFunction &&
2115 1 : (return_type == nullptr || return_type->IsA(AsmType::Float()))) {
2116 : DCHECK_NULL(call_coercion_deferred_);
2117 2372 : call_coercion_deferred_ = AsmType::Signed();
2118 2372 : to_number_pos = static_cast<int>(scanner_.Position());
2119 : return_type = AsmType::Signed();
2120 3069 : } else if (return_type == nullptr) {
2121 : to_number_pos = call_pos; // No conversion.
2122 : return_type = AsmType::Void();
2123 : }
2124 :
2125 : // Compute function type and signature based on gathered types.
2126 5441 : AsmType* function_type = AsmType::Function(zone(), return_type);
2127 22689 : for (auto t : param_types) {
2128 : function_type->AsFunctionType()->AddArgument(t);
2129 : }
2130 5441 : FunctionSig* sig = ConvertSignature(return_type, param_types);
2131 5441 : if (sig == nullptr) {
2132 0 : FAILn("Invalid function signature");
2133 : }
2134 5441 : uint32_t signature_index = module_builder_->AddSignature(sig);
2135 :
2136 : // Emit actual function invocation depending on the kind. At this point we
2137 : // also determined the complete function type and can perform checking against
2138 : // the expected type or update the expected type in case of first occurrence.
2139 5441 : if (function_info->kind == VarKind::kImportedFunction) {
2140 3533 : for (auto t : param_specific_types) {
2141 1223 : if (!t->IsA(AsmType::Extern())) {
2142 0 : FAILn("Imported function args must be type extern");
2143 : }
2144 : }
2145 1155 : if (return_type->IsA(AsmType::Float())) {
2146 0 : FAILn("Imported function can't be called as float");
2147 : }
2148 : DCHECK(function_info->import != nullptr);
2149 : // TODO(bradnelson): Factor out.
2150 : uint32_t index;
2151 1155 : auto it = function_info->import->cache.find(sig);
2152 2310 : if (it != function_info->import->cache.end()) {
2153 999 : index = it->second;
2154 : } else {
2155 : index = module_builder_->AddImport(
2156 : function_info->import->function_name.start(),
2157 156 : function_info->import->function_name.length(), sig);
2158 156 : function_info->import->cache[sig] = index;
2159 : }
2160 1155 : current_function_builder_->AddAsmWasmOffset(call_pos, to_number_pos);
2161 1155 : current_function_builder_->EmitWithU32V(kExprCallFunction, index);
2162 4286 : } else if (function_info->kind > VarKind::kImportedFunction) {
2163 216 : AsmCallableType* callable = function_info->type->AsCallableType();
2164 216 : if (!callable) {
2165 0 : FAILn("Expected callable function");
2166 : }
2167 : // TODO(bradnelson): Refactor AsmType to not need this.
2168 216 : if (callable->CanBeInvokedWith(return_type, param_specific_types)) {
2169 : // Return type ok.
2170 118 : } else if (return_type->IsA(AsmType::Void()) &&
2171 : callable->CanBeInvokedWith(AsmType::Float(),
2172 59 : param_specific_types)) {
2173 : return_type = AsmType::Float();
2174 118 : } else if (return_type->IsA(AsmType::Void()) &&
2175 : callable->CanBeInvokedWith(AsmType::Double(),
2176 59 : param_specific_types)) {
2177 : return_type = AsmType::Double();
2178 112 : } else if (return_type->IsA(AsmType::Void()) &&
2179 : callable->CanBeInvokedWith(AsmType::Signed(),
2180 56 : param_specific_types)) {
2181 : return_type = AsmType::Signed();
2182 : } else {
2183 4 : FAILn("Function use doesn't match definition");
2184 : }
2185 214 : switch (function_info->kind) {
2186 : #define V(name, Name, op, sig) \
2187 : case VarKind::kMath##Name: \
2188 : current_function_builder_->Emit(op); \
2189 : break;
2190 4 : STDLIB_MATH_FUNCTION_MONOMORPHIC_LIST(V)
2191 : #undef V
2192 : #define V(name, Name, op, sig) \
2193 : case VarKind::kMath##Name: \
2194 : if (param_specific_types[0]->IsA(AsmType::DoubleQ())) { \
2195 : current_function_builder_->Emit(kExprF64##Name); \
2196 : } else if (param_specific_types[0]->IsA(AsmType::FloatQ())) { \
2197 : current_function_builder_->Emit(kExprF32##Name); \
2198 : } else { \
2199 : UNREACHABLE(); \
2200 : } \
2201 : break;
2202 8 : STDLIB_MATH_FUNCTION_CEIL_LIKE_LIST(V)
2203 : #undef V
2204 : case VarKind::kMathMin:
2205 : case VarKind::kMathMax:
2206 12 : if (param_specific_types[0]->IsA(AsmType::Double())) {
2207 12 : for (size_t i = 1; i < param_specific_types.size(); ++i) {
2208 4 : if (function_info->kind == VarKind::kMathMin) {
2209 2 : current_function_builder_->Emit(kExprF64Min);
2210 : } else {
2211 2 : current_function_builder_->Emit(kExprF64Max);
2212 : }
2213 : }
2214 8 : } else if (param_specific_types[0]->IsA(AsmType::Float())) {
2215 : // NOTE: Not technically part of the asm.js spec, but Firefox
2216 : // accepts it.
2217 12 : for (size_t i = 1; i < param_specific_types.size(); ++i) {
2218 4 : if (function_info->kind == VarKind::kMathMin) {
2219 2 : current_function_builder_->Emit(kExprF32Min);
2220 : } else {
2221 2 : current_function_builder_->Emit(kExprF32Max);
2222 : }
2223 : }
2224 4 : } else if (param_specific_types[0]->IsA(AsmType::Int())) {
2225 : TemporaryVariableScope tmp_x(this);
2226 : TemporaryVariableScope tmp_y(this);
2227 16 : for (size_t i = 1; i < param_specific_types.size(); ++i) {
2228 4 : current_function_builder_->EmitSetLocal(tmp_x.get());
2229 4 : current_function_builder_->EmitTeeLocal(tmp_y.get());
2230 4 : current_function_builder_->EmitGetLocal(tmp_x.get());
2231 4 : if (function_info->kind == VarKind::kMathMin) {
2232 2 : current_function_builder_->Emit(kExprI32GeS);
2233 : } else {
2234 2 : current_function_builder_->Emit(kExprI32LeS);
2235 : }
2236 4 : current_function_builder_->EmitWithU8(kExprIf, kLocalI32);
2237 4 : current_function_builder_->EmitGetLocal(tmp_x.get());
2238 4 : current_function_builder_->Emit(kExprElse);
2239 4 : current_function_builder_->EmitGetLocal(tmp_y.get());
2240 4 : current_function_builder_->Emit(kExprEnd);
2241 : }
2242 : } else {
2243 0 : UNREACHABLE();
2244 : }
2245 : break;
2246 :
2247 : case VarKind::kMathAbs:
2248 12 : if (param_specific_types[0]->IsA(AsmType::Signed())) {
2249 : TemporaryVariableScope tmp(this);
2250 2 : current_function_builder_->EmitTeeLocal(tmp.get());
2251 2 : current_function_builder_->Emit(kExprI32Clz);
2252 2 : current_function_builder_->EmitWithU8(kExprIf, kLocalI32);
2253 2 : current_function_builder_->EmitGetLocal(tmp.get());
2254 2 : current_function_builder_->Emit(kExprElse);
2255 2 : current_function_builder_->EmitI32Const(0);
2256 2 : current_function_builder_->EmitGetLocal(tmp.get());
2257 2 : current_function_builder_->Emit(kExprI32Sub);
2258 2 : current_function_builder_->Emit(kExprEnd);
2259 10 : } else if (param_specific_types[0]->IsA(AsmType::DoubleQ())) {
2260 8 : current_function_builder_->Emit(kExprF64Abs);
2261 2 : } else if (param_specific_types[0]->IsA(AsmType::FloatQ())) {
2262 2 : current_function_builder_->Emit(kExprF32Abs);
2263 : } else {
2264 0 : UNREACHABLE();
2265 : }
2266 : break;
2267 :
2268 : case VarKind::kMathFround:
2269 0 : if (param_specific_types[0]->IsA(AsmType::DoubleQ())) {
2270 0 : current_function_builder_->Emit(kExprF32ConvertF64);
2271 : } else {
2272 : DCHECK(param_specific_types[0]->IsA(AsmType::FloatQ()));
2273 : }
2274 : break;
2275 :
2276 : default:
2277 0 : UNREACHABLE();
2278 : }
2279 : } else {
2280 : DCHECK(function_info->kind == VarKind::kFunction ||
2281 : function_info->kind == VarKind::kTable);
2282 4070 : if (function_info->type->IsA(AsmType::None())) {
2283 496 : function_info->type = function_type;
2284 : } else {
2285 3574 : AsmCallableType* callable = function_info->type->AsCallableType();
2286 7148 : if (!callable ||
2287 3574 : !callable->CanBeInvokedWith(return_type, param_specific_types)) {
2288 28 : FAILn("Function use doesn't match definition");
2289 : }
2290 : }
2291 4056 : if (function_info->kind == VarKind::kTable) {
2292 448 : current_function_builder_->EmitGetLocal(tmp.get()->get());
2293 224 : current_function_builder_->AddAsmWasmOffset(call_pos, to_number_pos);
2294 224 : current_function_builder_->Emit(kExprCallIndirect);
2295 224 : current_function_builder_->EmitU32V(signature_index);
2296 224 : current_function_builder_->EmitU32V(0); // table index
2297 : } else {
2298 3832 : current_function_builder_->AddAsmWasmOffset(call_pos, to_number_pos);
2299 3832 : current_function_builder_->Emit(kExprCallFunction);
2300 3832 : current_function_builder_->EmitDirectCallIndex(function_info->index);
2301 : }
2302 : }
2303 :
2304 5425 : return return_type;
2305 : }
2306 :
2307 : // 6.9 ValidateCall - helper
2308 138750 : bool AsmJsParser::PeekCall() {
2309 146168 : if (!scanner_.IsGlobal()) {
2310 : return false;
2311 : }
2312 6970 : if (GetVarInfo(scanner_.Token())->kind == VarKind::kFunction) {
2313 : return true;
2314 : }
2315 3552 : if (GetVarInfo(scanner_.Token())->kind >= VarKind::kImportedFunction) {
2316 : return true;
2317 : }
2318 3866 : if (GetVarInfo(scanner_.Token())->kind == VarKind::kUnused ||
2319 1686 : GetVarInfo(scanner_.Token())->kind == VarKind::kTable) {
2320 666 : scanner_.Next();
2321 666 : if (Peek('(') || Peek('[')) {
2322 656 : scanner_.Rewind();
2323 656 : return true;
2324 : }
2325 10 : scanner_.Rewind();
2326 : }
2327 : return false;
2328 : }
2329 :
2330 : // 6.10 ValidateHeapAccess
2331 20985 : void AsmJsParser::ValidateHeapAccess() {
2332 20985 : VarInfo* info = GetVarInfo(Consume());
2333 20985 : int32_t size = info->type->ElementSizeInBytes();
2334 60020 : EXPECT_TOKEN('[');
2335 : uint32_t offset;
2336 20985 : if (CheckForUnsigned(&offset)) {
2337 : // TODO(bradnelson): Check more things.
2338 : // TODO(mstarzinger): Clarify and explain where this limit is coming from,
2339 : // as it is not mandated by the spec directly.
2340 3309 : if (offset > 0x7fffffff ||
2341 1654 : static_cast<uint64_t>(offset) * static_cast<uint64_t>(size) >
2342 : 0x7fffffff) {
2343 2 : FAIL("Heap access out of range");
2344 : }
2345 1654 : if (Check(']')) {
2346 : current_function_builder_->EmitI32Const(
2347 389 : static_cast<uint32_t>(offset * size));
2348 : // NOTE: This has to happen here to work recursively.
2349 389 : heap_access_type_ = info->type;
2350 389 : return;
2351 : } else {
2352 1265 : scanner_.Rewind();
2353 : }
2354 : }
2355 : AsmType* index_type;
2356 39518 : if (info->type->IsA(AsmType::Int8Array()) ||
2357 18923 : info->type->IsA(AsmType::Uint8Array())) {
2358 2156 : RECURSE(index_type = Expression(nullptr));
2359 : } else {
2360 18439 : RECURSE(index_type = AdditiveExpression());
2361 18439 : EXPECT_TOKEN(TOK(SAR));
2362 : uint32_t shift;
2363 18439 : if (!CheckForUnsigned(&shift)) {
2364 2 : FAIL("Expected shift of word size");
2365 : }
2366 18438 : if (shift > 3) {
2367 4 : FAIL("Expected valid heap access shift");
2368 : }
2369 18436 : if ((1 << shift) != size) {
2370 0 : FAIL("Expected heap access shift to match heap view");
2371 : }
2372 : // Mask bottom bits to match asm.js behavior.
2373 18436 : current_function_builder_->EmitI32Const(~(size - 1));
2374 18436 : current_function_builder_->Emit(kExprI32And);
2375 : }
2376 20592 : if (!index_type->IsA(AsmType::Intish())) {
2377 0 : FAIL("Expected intish index");
2378 : }
2379 20592 : EXPECT_TOKEN(']');
2380 : // NOTE: This has to happen here to work recursively.
2381 20592 : heap_access_type_ = info->type;
2382 : }
2383 :
2384 : // 6.11 ValidateFloatCoercion
2385 77 : void AsmJsParser::ValidateFloatCoercion() {
2386 385 : if (!scanner_.IsGlobal() ||
2387 77 : !GetVarInfo(scanner_.Token())->type->IsA(stdlib_fround_)) {
2388 0 : FAIL("Expected fround");
2389 : }
2390 77 : scanner_.Next();
2391 77 : EXPECT_TOKEN('(');
2392 77 : call_coercion_ = AsmType::Float();
2393 : // NOTE: The coercion position to float is not observable from JavaScript,
2394 : // because imported functions are not allowed to have float return type.
2395 77 : call_coercion_position_ = scanner_.Position();
2396 : AsmType* ret;
2397 77 : RECURSE(ret = ValidateExpression());
2398 77 : if (ret->IsA(AsmType::Floatish())) {
2399 : // Do nothing, as already a float.
2400 25 : } else if (ret->IsA(AsmType::DoubleQ())) {
2401 20 : current_function_builder_->Emit(kExprF32ConvertF64);
2402 5 : } else if (ret->IsA(AsmType::Signed())) {
2403 3 : current_function_builder_->Emit(kExprF32SConvertI32);
2404 2 : } else if (ret->IsA(AsmType::Unsigned())) {
2405 2 : current_function_builder_->Emit(kExprF32UConvertI32);
2406 : } else {
2407 0 : FAIL("Illegal conversion to float");
2408 : }
2409 77 : EXPECT_TOKEN(')');
2410 : }
2411 :
2412 26 : void AsmJsParser::ScanToClosingParenthesis() {
2413 : int depth = 0;
2414 : for (;;) {
2415 121 : if (Peek('(')) {
2416 13 : ++depth;
2417 108 : } else if (Peek(')')) {
2418 39 : --depth;
2419 39 : if (depth < 0) {
2420 : break;
2421 : }
2422 69 : } else if (Peek(AsmJsScanner::kEndOfInput)) {
2423 : break;
2424 : }
2425 95 : scanner_.Next();
2426 95 : }
2427 26 : }
2428 :
2429 86 : void AsmJsParser::GatherCases(std::vector<int32_t>* cases) {
2430 86 : size_t start = scanner_.Position();
2431 : int depth = 0;
2432 : for (;;) {
2433 55681 : if (Peek('{')) {
2434 1283 : ++depth;
2435 54398 : } else if (Peek('}')) {
2436 1282 : --depth;
2437 1282 : if (depth <= 0) {
2438 : break;
2439 : }
2440 53116 : } else if (depth == 1 && Peek(TOK(case))) {
2441 3664 : scanner_.Next();
2442 : int32_t value;
2443 : uint32_t uvalue;
2444 3664 : if (Check('-')) {
2445 874 : if (!CheckForUnsigned(&uvalue)) {
2446 : break;
2447 : }
2448 874 : value = -static_cast<int32_t>(uvalue);
2449 : } else {
2450 2790 : if (!CheckForUnsigned(&uvalue)) {
2451 : break;
2452 : }
2453 2789 : value = static_cast<int32_t>(uvalue);
2454 : }
2455 3663 : cases->push_back(value);
2456 49452 : } else if (Peek(AsmJsScanner::kEndOfInput)) {
2457 : break;
2458 : }
2459 55595 : scanner_.Next();
2460 55595 : }
2461 86 : scanner_.Seek(start);
2462 86 : }
2463 :
2464 : } // namespace wasm
2465 : } // namespace internal
2466 : } // namespace v8
|