1 // Copyright 2016 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 SRC_ASMJS_ASM_TYPER_H_
6 #define SRC_ASMJS_ASM_TYPER_H_
7 
8 #include <cstdint>
9 #include <string>
10 #include <unordered_set>
11 
12 #include "src/allocation.h"
13 #include "src/asmjs/asm-types.h"
14 #include "src/ast/ast-type-bounds.h"
15 #include "src/ast/ast-types.h"
16 #include "src/ast/ast.h"
17 #include "src/effects.h"
18 #include "src/type-info.h"
19 #include "src/zone/zone-containers.h"
20 #include "src/zone/zone.h"
21 
22 namespace v8 {
23 namespace internal {
24 namespace wasm {
25 
26 class AsmType;
27 class AsmTyperHarnessBuilder;
28 
29 class AsmTyper final {
30  public:
31   enum StandardMember {
32     kHeap = -4,
33     kFFI = -3,
34     kStdlib = -2,
35     kModule = -1,
36     kNone = 0,
37     kInfinity,
38     kNaN,
39     kMathAcos,
40     kMathAsin,
41     kMathAtan,
42     kMathCos,
43     kMathSin,
44     kMathTan,
45     kMathExp,
46     kMathLog,
47     kMathCeil,
48     kMathFloor,
49     kMathSqrt,
50     kMathAbs,
51     kMathClz32,
52     kMathMin,
53     kMathMax,
54     kMathAtan2,
55     kMathPow,
56     kMathImul,
57     kMathFround,
58     kMathE,
59     kMathLN10,
60     kMathLN2,
61     kMathLOG2E,
62     kMathLOG10E,
63     kMathPI,
64     kMathSQRT1_2,
65     kMathSQRT2,
66   };
67 
68   ~AsmTyper() = default;
69   AsmTyper(Isolate* isolate, Zone* zone, Script* script, FunctionLiteral* root);
70 
71   bool Validate();
72 
error_message()73   const char* error_message() const { return error_message_; }
74 
75   AsmType* TypeOf(AstNode* node) const;
76   AsmType* TypeOf(Variable* v) const;
77   StandardMember VariableAsStandardMember(Variable* var);
78 
79   typedef std::unordered_set<StandardMember, std::hash<int> > StdlibSet;
80 
StdlibUses()81   StdlibSet StdlibUses() const { return stdlib_uses_; }
82 
83   // Each FFI import has a usage-site signature associated with it.
84   struct FFIUseSignature {
85     Variable* var;
86     ZoneVector<AsmType*> arg_types_;
87     AsmType* return_type_;
FFIUseSignatureFFIUseSignature88     FFIUseSignature(Variable* v, Zone* zone)
89         : var(v), arg_types_(zone), return_type_(nullptr) {}
90   };
91 
FFIUseSignatures()92   const ZoneVector<FFIUseSignature>& FFIUseSignatures() {
93     return ffi_use_signatures_;
94   }
95 
96  private:
97   friend class v8::internal::wasm::AsmTyperHarnessBuilder;
98 
99   class VariableInfo : public ZoneObject {
100    public:
101     enum Mutability {
102       kInvalidMutability,
103       kLocal,
104       kMutableGlobal,
105       // *VIOLATION* We support const variables in asm.js, as per the
106       //
107       // https://discourse.wicg.io/t/allow-const-global-variables/684
108       //
109       // Global const variables are treated as if they were numeric literals,
110       // and can be used anywhere a literal can be used.
111       kConstGlobal,
112       kImmutableGlobal,
113     };
114 
VariableInfo(AsmType * t)115     explicit VariableInfo(AsmType* t) : type_(t) {}
116 
117     VariableInfo* Clone(Zone* zone) const;
118 
IsMutable()119     bool IsMutable() const {
120       return mutability_ == kLocal || mutability_ == kMutableGlobal;
121     }
122 
IsGlobal()123     bool IsGlobal() const {
124       return mutability_ == kImmutableGlobal || mutability_ == kConstGlobal ||
125              mutability_ == kMutableGlobal;
126     }
127 
IsStdlib()128     bool IsStdlib() const { return standard_member_ == kStdlib; }
IsFFI()129     bool IsFFI() const { return standard_member_ == kFFI; }
IsHeap()130     bool IsHeap() const { return standard_member_ == kHeap; }
131 
MarkDefined()132     void MarkDefined() { missing_definition_ = false; }
133     void FirstForwardUseIs(VariableProxy* var);
134 
standard_member()135     StandardMember standard_member() const { return standard_member_; }
set_standard_member(StandardMember standard_member)136     void set_standard_member(StandardMember standard_member) {
137       standard_member_ = standard_member;
138     }
139 
type()140     AsmType* type() const { return type_; }
set_type(AsmType * type)141     void set_type(AsmType* type) { type_ = type; }
142 
mutability()143     Mutability mutability() const { return mutability_; }
set_mutability(Mutability mutability)144     void set_mutability(Mutability mutability) { mutability_ = mutability; }
145 
missing_definition()146     bool missing_definition() const { return missing_definition_; }
147 
first_forward_use()148     VariableProxy* first_forward_use() const { return first_forward_use_; }
149 
150     static VariableInfo* ForSpecialSymbol(Zone* zone,
151                                           StandardMember standard_member);
152 
153    private:
154     AsmType* type_;
155     StandardMember standard_member_ = kNone;
156     Mutability mutability_ = kInvalidMutability;
157     // missing_definition_ is set to true for forward definition - i.e., use
158     // before definition.
159     bool missing_definition_ = false;
160     // first_forward_use_ holds the AST node that first referenced this
161     // VariableInfo. Used for error messages.
162     VariableProxy* first_forward_use_ = nullptr;
163   };
164 
165   // RAII-style manager for the in_function_ member variable.
166   struct FunctionScope {
FunctionScopeFunctionScope167     explicit FunctionScope(AsmTyper* typer) : typer_(typer) {
168       DCHECK(!typer_->in_function_);
169       typer_->in_function_ = true;
170       typer_->local_scope_.Clear();
171       typer_->return_type_ = AsmType::None();
172     }
173 
~FunctionScopeFunctionScope174     ~FunctionScope() {
175       DCHECK(typer_->in_function_);
176       typer_->in_function_ = false;
177     }
178 
179     AsmTyper* typer_;
180   };
181 
182   // FlattenedStatements is an iterator class for ZoneList<Statement*> that
183   // flattens the Block construct in the AST. This is here because we need it in
184   // the tests.
185   class FlattenedStatements {
186    public:
187     explicit FlattenedStatements(Zone* zone, ZoneList<Statement*>* s);
188     Statement* Next();
189 
190    private:
191     struct Context {
ContextContext192       explicit Context(ZoneList<Statement*>* s) : statements_(s) {}
193       ZoneList<Statement*>* statements_;
194       int next_index_ = 0;
195     };
196 
197     ZoneVector<Context> context_stack_;
198 
199     DISALLOW_IMPLICIT_CONSTRUCTORS(FlattenedStatements);
200   };
201 
202   using ObjectTypeMap = ZoneMap<std::string, VariableInfo*>;
203   void InitializeStdlib();
204   void SetTypeOf(AstNode* node, AsmType* type);
205 
206   void AddForwardReference(VariableProxy* proxy, VariableInfo* info);
207   bool AddGlobal(Variable* global, VariableInfo* info);
208   bool AddLocal(Variable* global, VariableInfo* info);
209   // Used for 5.5 GlobalVariableTypeAnnotations
210   VariableInfo* ImportLookup(Property* expr);
211   // 3.3 Environment Lookup
212   // NOTE: In the spec, the lookup function's prototype is
213   //
214   //   Lookup(Delta, Gamma, x)
215   //
216   // Delta is the global_scope_ member, and Gamma, local_scope_.
217   VariableInfo* Lookup(Variable* variable) const;
218 
219   // All of the ValidateXXX methods below return AsmType::None() in case of
220   // validation failure.
221 
222   // 6.1 ValidateModule
223   AsmType* ValidateModule(FunctionLiteral* fun);
224   AsmType* ValidateGlobalDeclaration(Assignment* assign);
225   // 6.2 ValidateExport
226   AsmType* ExportType(VariableProxy* fun_export);
227   AsmType* ValidateExport(ReturnStatement* exports);
228   // 6.3 ValidateFunctionTable
229   AsmType* ValidateFunctionTable(Assignment* assign);
230   // 6.4 ValidateFunction
231   AsmType* ValidateFunction(FunctionDeclaration* fun_decl);
232   // 6.5 ValidateStatement
233   AsmType* ValidateStatement(Statement* statement);
234   // 6.5.1 BlockStatement
235   AsmType* ValidateBlockStatement(Block* block);
236   // 6.5.2 ExpressionStatement
237   AsmType* ValidateExpressionStatement(ExpressionStatement* expr);
238   // 6.5.3 EmptyStatement
239   AsmType* ValidateEmptyStatement(EmptyStatement* empty);
240   // 6.5.4 IfStatement
241   AsmType* ValidateIfStatement(IfStatement* if_stmt);
242   // 6.5.5 ReturnStatement
243   AsmType* ValidateReturnStatement(ReturnStatement* ret_stmt);
244   // 6.5.6 IterationStatement
245   // 6.5.6.a WhileStatement
246   AsmType* ValidateWhileStatement(WhileStatement* while_stmt);
247   // 6.5.6.b DoWhileStatement
248   AsmType* ValidateDoWhileStatement(DoWhileStatement* do_while);
249   // 6.5.6.c ForStatement
250   AsmType* ValidateForStatement(ForStatement* for_stmt);
251   // 6.5.7 BreakStatement
252   AsmType* ValidateBreakStatement(BreakStatement* brk_stmt);
253   // 6.5.8 ContinueStatement
254   AsmType* ValidateContinueStatement(ContinueStatement* cont_stmt);
255   // 6.5.9 LabelledStatement
256   // NOTE: we don't need to handle these: Labelled statements are
257   // BreakableStatements in our AST, but BreakableStatement is not a concrete
258   // class -- and we're handling all of BreakableStatement's subclasses.
259   // 6.5.10 SwitchStatement
260   AsmType* ValidateSwitchStatement(SwitchStatement* stmt);
261   // 6.6 ValidateCase
262   AsmType* ValidateCase(CaseClause* label, int32_t* case_lbl);
263   // 6.7 ValidateDefault
264   AsmType* ValidateDefault(CaseClause* label);
265   // 6.8 ValidateExpression
266   AsmType* ValidateExpression(Expression* expr);
267   AsmType* ValidateCompareOperation(CompareOperation* cmp);
268   AsmType* ValidateBinaryOperation(BinaryOperation* binop);
269   // 6.8.1 Expression
270   AsmType* ValidateCommaExpression(BinaryOperation* comma);
271   // 6.8.2 NumericLiteral
272   AsmType* ValidateNumericLiteral(Literal* literal);
273   // 6.8.3 Identifier
274   AsmType* ValidateIdentifier(VariableProxy* proxy);
275   // 6.8.4 CallExpression
276   AsmType* ValidateCallExpression(Call* call);
277   // 6.8.5 MemberExpression
278   AsmType* ValidateMemberExpression(Property* prop);
279   // 6.8.6 AssignmentExpression
280   AsmType* ValidateAssignmentExpression(Assignment* assignment);
281   // 6.8.7 UnaryExpression
282   AsmType* ValidateUnaryExpression(UnaryOperation* unop);
283   // 6.8.8 MultiplicativeExpression
284   AsmType* ValidateMultiplicativeExpression(BinaryOperation* binop);
285   // 6.8.9 AdditiveExpression
286   AsmType* ValidateAdditiveExpression(BinaryOperation* binop,
287                                       uint32_t intish_count);
288   // 6.8.10 ShiftExpression
289   AsmType* ValidateShiftExpression(BinaryOperation* binop);
290   // 6.8.11 RelationalExpression
291   AsmType* ValidateRelationalExpression(CompareOperation* cmpop);
292   // 6.8.12 EqualityExpression
293   AsmType* ValidateEqualityExpression(CompareOperation* cmpop);
294   // 6.8.13 BitwiseANDExpression
295   AsmType* ValidateBitwiseANDExpression(BinaryOperation* binop);
296   // 6.8.14 BitwiseXORExpression
297   AsmType* ValidateBitwiseXORExpression(BinaryOperation* binop);
298   // 6.8.15 BitwiseORExpression
299   AsmType* ValidateBitwiseORExpression(BinaryOperation* binop);
300   // 6.8.16 ConditionalExpression
301   AsmType* ValidateConditionalExpression(Conditional* cond);
302   // 6.9 ValidateCall
303   AsmType* ValidateCall(AsmType* return_type, Call* call);
304   // 6.10 ValidateHeapAccess
305   enum HeapAccessType { LoadFromHeap, StoreToHeap };
306   AsmType* ValidateHeapAccess(Property* heap, HeapAccessType access_type);
307   // 6.11 ValidateFloatCoercion
308   bool IsCallToFround(Call* call);
309   AsmType* ValidateFloatCoercion(Call* call);
310 
311   // 5.1 ParameterTypeAnnotations
312   AsmType* ParameterTypeAnnotations(Variable* parameter,
313                                     Expression* annotation);
314   // 5.2 ReturnTypeAnnotations
315   AsmType* ReturnTypeAnnotations(ReturnStatement* statement);
316   // 5.4 VariableTypeAnnotations
317   // 5.5 GlobalVariableTypeAnnotations
318   AsmType* VariableTypeAnnotations(
319       Expression* initializer,
320       VariableInfo::Mutability global = VariableInfo::kLocal);
321   AsmType* ImportExpression(Property* import);
322   AsmType* NewHeapView(CallNew* new_heap_view);
323 
324   Isolate* isolate_;
325   Zone* zone_;
326   Script* script_;
327   FunctionLiteral* root_;
328   bool in_function_ = false;
329 
330   AsmType* return_type_ = nullptr;
331 
332   ZoneVector<VariableInfo*> forward_definitions_;
333   ZoneVector<FFIUseSignature> ffi_use_signatures_;
334   ObjectTypeMap stdlib_types_;
335   ObjectTypeMap stdlib_math_types_;
336 
337   // The ASM module name. This member is used to prevent globals from redefining
338   // the module name.
339   VariableInfo* module_info_;
340   Handle<String> module_name_;
341 
342   // 3 Environments
343   ZoneHashMap global_scope_;  // 3.1 Global environment
344   ZoneHashMap local_scope_;   // 3.2 Variable environment
345 
346   std::uintptr_t stack_limit_;
347   bool stack_overflow_ = false;
348   ZoneMap<AstNode*, AsmType*> node_types_;
349   static const int kErrorMessageLimit = 100;
350   AsmType* fround_type_;
351   AsmType* ffi_type_;
352   char error_message_[kErrorMessageLimit];
353   StdlibSet stdlib_uses_;
354 
355   DISALLOW_IMPLICIT_CONSTRUCTORS(AsmTyper);
356 };
357 
358 }  // namespace wasm
359 }  // namespace internal
360 }  // namespace v8
361 
362 #endif  // SRC_ASMJS_ASM_TYPER_H_
363