Line data Source code
1 : // Copyright 2017 the V8 project authors. All rights reserved.
2 : // Use of this source code is governed by a BSD-style license that can be
3 : // found in the LICENSE file.
4 :
5 : #ifndef V8_ASMJS_ASM_PARSER_H_
6 : #define V8_ASMJS_ASM_PARSER_H_
7 :
8 : #include <string>
9 : #include <vector>
10 :
11 : #include "src/asmjs/asm-scanner.h"
12 : #include "src/asmjs/asm-typer.h"
13 : #include "src/asmjs/asm-types.h"
14 : #include "src/wasm/wasm-module-builder.h"
15 : #include "src/zone/zone-containers.h"
16 :
17 : namespace v8 {
18 : namespace internal {
19 : namespace wasm {
20 :
21 : // A custom parser + validator + wasm converter for asm.js:
22 : // http://asmjs.org/spec/latest/
23 : // This parser intentionally avoids the portion of JavaScript parsing
24 : // that are not required to determine if code is valid asm.js code.
25 : // * It is mostly one pass.
26 : // * It bails out on unexpected input.
27 : // * It assumes strict ordering insofar as permitted by asm.js validation rules.
28 : // * It relies on a custom scanner that provides de-duped identifiers in two
29 : // scopes (local + module wide).
30 702326 : class AsmJsParser {
31 : public:
32 : explicit AsmJsParser(Isolate* isolate, Zone* zone, Handle<Script> script,
33 : int start, int end);
34 : bool Run();
35 : const char* failure_message() const { return failure_message_; }
36 : int failure_location() const { return failure_location_; }
37 : WasmModuleBuilder* module_builder() { return module_builder_; }
38 : const AsmTyper::StdlibSet* stdlib_uses() const { return &stdlib_uses_; }
39 :
40 : private:
41 : // clang-format off
42 : enum class VarKind {
43 : kUnused,
44 : kLocal,
45 : kGlobal,
46 : kSpecial,
47 : kFunction,
48 : kTable,
49 : kImportedFunction,
50 : #define V(_unused0, Name, _unused1, _unused2) kMath##Name,
51 : STDLIB_MATH_FUNCTION_LIST(V)
52 : #undef V
53 : #define V(Name, _unused1) kMath##Name,
54 : STDLIB_MATH_VALUE_LIST(V)
55 : #undef V
56 : };
57 : // clang-format on
58 :
59 : struct FunctionImportInfo {
60 : Vector<const char> function_name;
61 : WasmModuleBuilder::SignatureMap cache;
62 : };
63 :
64 : struct VarInfo {
65 : AsmType* type;
66 : WasmFunctionBuilder* function_builder;
67 : FunctionImportInfo* import;
68 : int32_t mask;
69 : uint32_t index;
70 : VarKind kind;
71 : bool mutable_variable;
72 : bool function_defined;
73 :
74 : VarInfo();
75 : };
76 :
77 : struct GlobalImport {
78 : Vector<const char> import_name;
79 : ValueType value_type;
80 : VarInfo* var_info;
81 : };
82 :
83 : enum class BlockKind { kRegular, kLoop, kOther };
84 :
85 : struct BlockInfo {
86 : BlockKind kind;
87 : AsmJsScanner::token_t label;
88 : };
89 :
90 : // Helper class to make {TempVariable} safe for nesting.
91 : class TemporaryVariableScope;
92 :
93 : Zone* zone_;
94 : AsmJsScanner scanner_;
95 : WasmModuleBuilder* module_builder_;
96 : WasmFunctionBuilder* current_function_builder_;
97 : AsmType* return_type_;
98 : uintptr_t stack_limit_;
99 : AsmTyper::StdlibSet stdlib_uses_;
100 : ZoneVector<VarInfo> global_var_info_;
101 : ZoneVector<VarInfo> local_var_info_;
102 :
103 : int function_temp_locals_offset_;
104 : int function_temp_locals_used_;
105 : int function_temp_locals_depth_;
106 :
107 : // Error Handling related
108 : bool failed_;
109 : const char* failure_message_;
110 : int failure_location_;
111 :
112 : // Module Related.
113 : AsmJsScanner::token_t stdlib_name_;
114 : AsmJsScanner::token_t foreign_name_;
115 : AsmJsScanner::token_t heap_name_;
116 :
117 : static const AsmJsScanner::token_t kTokenNone = 0;
118 :
119 : // Track if parsing a heap assignment.
120 : bool inside_heap_assignment_;
121 : AsmType* heap_access_type_;
122 :
123 : ZoneVector<BlockInfo> block_stack_;
124 :
125 : // Types used for stdlib function and their set up.
126 : AsmType* stdlib_dq2d_;
127 : AsmType* stdlib_dqdq2d_;
128 : AsmType* stdlib_fq2f_;
129 : AsmType* stdlib_i2s_;
130 : AsmType* stdlib_ii2s_;
131 : AsmType* stdlib_minmax_;
132 : AsmType* stdlib_abs_;
133 : AsmType* stdlib_ceil_like_;
134 : AsmType* stdlib_fround_;
135 :
136 : // When making calls, the return type is needed to lookup signatures.
137 : // For `+callsite(..)` or `fround(callsite(..))` use this value to pass
138 : // along the coercion.
139 : AsmType* call_coercion_;
140 :
141 : // The source position associated with the above {call_coercion}.
142 : size_t call_coercion_position_;
143 :
144 : // When making calls, the coercion can also appear in the source stream
145 : // syntactically "behind" the call site. For `callsite(..)|0` use this
146 : // value to flag that such a coercion must happen.
147 : AsmType* call_coercion_deferred_;
148 :
149 : // The source position at which requesting a deferred coercion via the
150 : // aforementioned {call_coercion_deferred} is allowed.
151 : size_t call_coercion_deferred_position_;
152 :
153 : // Used to track the last label we've seen so it can be matched to later
154 : // statements it's attached to.
155 : AsmJsScanner::token_t pending_label_;
156 :
157 : // Global imports. The list of imported variables that are copied during
158 : // module instantiation into a corresponding global variable.
159 : ZoneLinkedList<GlobalImport> global_imports_;
160 :
161 : Zone* zone() { return zone_; }
162 :
163 : inline bool Peek(AsmJsScanner::token_t token) {
164 1267765 : return scanner_.Token() == token;
165 : }
166 :
167 : inline bool Check(AsmJsScanner::token_t token) {
168 2205445 : if (scanner_.Token() == token) {
169 153485 : scanner_.Next();
170 : return true;
171 : } else {
172 : return false;
173 : }
174 : }
175 :
176 33116 : inline bool CheckForZero() {
177 33116 : if (scanner_.IsUnsigned() && scanner_.AsUnsigned() == 0) {
178 31998 : scanner_.Next();
179 31998 : return true;
180 : } else {
181 : return false;
182 : }
183 : }
184 :
185 : inline bool CheckForDouble(double* value) {
186 78619 : if (scanner_.IsDouble()) {
187 : *value = scanner_.AsDouble();
188 1464 : scanner_.Next();
189 : return true;
190 : } else {
191 : return false;
192 : }
193 : }
194 :
195 : inline bool CheckForUnsigned(uint32_t* value) {
196 127128 : if (scanner_.IsUnsigned()) {
197 : *value = scanner_.AsUnsigned();
198 104364 : scanner_.Next();
199 : return true;
200 : } else {
201 : return false;
202 : }
203 : }
204 :
205 : inline bool CheckForUnsignedBelow(uint32_t limit, uint32_t* value) {
206 181871 : if (scanner_.IsUnsigned() && scanner_.AsUnsigned() < limit) {
207 : *value = scanner_.AsUnsigned();
208 71524 : scanner_.Next();
209 : return true;
210 : } else {
211 : return false;
212 : }
213 : }
214 :
215 : inline AsmJsScanner::token_t Consume() {
216 30289 : AsmJsScanner::token_t ret = scanner_.Token();
217 320605 : scanner_.Next();
218 : return ret;
219 : }
220 :
221 : void SkipSemicolon();
222 :
223 : VarInfo* GetVarInfo(AsmJsScanner::token_t token);
224 : uint32_t VarIndex(VarInfo* info);
225 : void DeclareGlobal(VarInfo* info, bool mutable_variable, AsmType* type,
226 : ValueType vtype,
227 : const WasmInitExpr& init = WasmInitExpr());
228 : void DeclareStdlibFunc(VarInfo* info, VarKind kind, AsmType* type);
229 : void AddGlobalImport(Vector<const char> name, AsmType* type, ValueType vtype,
230 : bool mutable_variable, VarInfo* info);
231 :
232 : // Allocates a temporary local variable. The given {index} is absolute within
233 : // the function body, consider using {TemporaryVariableScope} when nesting.
234 : uint32_t TempVariable(int index);
235 :
236 : // Preserves a copy of the scanner's current identifier string in the zone.
237 : Vector<const char> CopyCurrentIdentifierString();
238 :
239 : // Use to set up block stack layers (including synthetic ones for if-else).
240 : // Begin/Loop/End below are implemented with these plus code generation.
241 : void BareBegin(BlockKind kind = BlockKind::kOther,
242 : AsmJsScanner::token_t label = 0);
243 : void BareEnd();
244 : int FindContinueLabelDepth(AsmJsScanner::token_t label);
245 : int FindBreakLabelDepth(AsmJsScanner::token_t label);
246 :
247 : // Use to set up actual wasm blocks/loops.
248 : void Begin(AsmJsScanner::token_t label = 0);
249 : void Loop(AsmJsScanner::token_t label = 0);
250 : void End();
251 :
252 : void InitializeStdlibTypes();
253 :
254 : FunctionSig* ConvertSignature(AsmType* return_type,
255 : const std::vector<AsmType*>& params);
256 :
257 : // 6.1 ValidateModule
258 : void ValidateModule();
259 : void ValidateModuleParameters();
260 : void ValidateModuleVars();
261 : void ValidateModuleVar(bool mutable_variable);
262 : bool ValidateModuleVarImport(VarInfo* info, bool mutable_variable);
263 : void ValidateModuleVarStdlib(VarInfo* info);
264 : void ValidateModuleVarNewStdlib(VarInfo* info);
265 : void ValidateModuleVarFromGlobal(VarInfo* info, bool mutable_variable);
266 :
267 : void ValidateExport(); // 6.2 ValidateExport
268 : void ValidateFunctionTable(); // 6.3 ValidateFunctionTable
269 : void ValidateFunction(); // 6.4 ValidateFunction
270 : void ValidateFunctionParams(std::vector<AsmType*>* params);
271 : void ValidateFunctionLocals(size_t param_count,
272 : std::vector<ValueType>* locals);
273 : void ValidateStatement(); // ValidateStatement
274 : void Block(); // 6.5.1 Block
275 : void ExpressionStatement(); // 6.5.2 ExpressionStatement
276 : void EmptyStatement(); // 6.5.3 EmptyStatement
277 : void IfStatement(); // 6.5.4 IfStatement
278 : void ReturnStatement(); // 6.5.5 ReturnStatement
279 : bool IterationStatement(); // 6.5.6 IterationStatement
280 : void WhileStatement(); // 6.5.6 IterationStatement - while
281 : void DoStatement(); // 6.5.6 IterationStatement - do
282 : void ForStatement(); // 6.5.6 IterationStatement - for
283 : void BreakStatement(); // 6.5.7 BreakStatement
284 : void ContinueStatement(); // 6.5.8 ContinueStatement
285 : void LabelledStatement(); // 6.5.9 LabelledStatement
286 : void SwitchStatement(); // 6.5.10 SwitchStatement
287 : void ValidateCase(); // 6.6. ValidateCase
288 : void ValidateDefault(); // 6.7 ValidateDefault
289 : AsmType* ValidateExpression(); // 6.8 ValidateExpression
290 : AsmType* Expression(AsmType* expect); // 6.8.1 Expression
291 : AsmType* NumericLiteral(); // 6.8.2 NumericLiteral
292 : AsmType* Identifier(); // 6.8.3 Identifier
293 : AsmType* CallExpression(); // 6.8.4 CallExpression
294 : AsmType* MemberExpression(); // 6.8.5 MemberExpression
295 : AsmType* AssignmentExpression(); // 6.8.6 AssignmentExpression
296 : AsmType* UnaryExpression(); // 6.8.7 UnaryExpression
297 : AsmType* MultiplicativeExpression(); // 6.8.8 MultiplicativeExpression
298 : AsmType* AdditiveExpression(); // 6.8.9 AdditiveExpression
299 : AsmType* ShiftExpression(); // 6.8.10 ShiftExpression
300 : AsmType* RelationalExpression(); // 6.8.11 RelationalExpression
301 : AsmType* EqualityExpression(); // 6.8.12 EqualityExpression
302 : AsmType* BitwiseANDExpression(); // 6.8.13 BitwiseANDExpression
303 : AsmType* BitwiseXORExpression(); // 6.8.14 BitwiseXORExpression
304 : AsmType* BitwiseORExpression(); // 6.8.15 BitwiseORExpression
305 : AsmType* ConditionalExpression(); // 6.8.16 ConditionalExpression
306 : AsmType* ParenthesizedExpression(); // 6.8.17 ParenthesiedExpression
307 : AsmType* ValidateCall(); // 6.9 ValidateCall
308 : bool PeekCall(); // 6.9 ValidateCall - helper
309 : void ValidateHeapAccess(); // 6.10 ValidateHeapAccess
310 : void ValidateFloatCoercion(); // 6.11 ValidateFloatCoercion
311 :
312 : // Used as part of {ForStatement}. Scans forward to the next `)` in order to
313 : // skip over the third expression in a for-statement. This is one piece that
314 : // makes this parser not be a pure single-pass.
315 : void ScanToClosingParenthesis();
316 :
317 : // Used as part of {SwitchStatement}. Collects all case labels in the current
318 : // switch-statement, then resets the scanner position. This is one piece that
319 : // makes this parser not be a pure single-pass.
320 : void GatherCases(std::vector<int32_t>* cases);
321 : };
322 :
323 : } // namespace wasm
324 : } // namespace internal
325 : } // namespace v8
326 :
327 : #endif // V8_ASMJS_ASM_PARSER_H_
|