Bug Summary

File:out/../deps/v8/src/asmjs/asm-parser.cc
Warning:line 1374, column 5
Value stored to 'value' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

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