asm-typer.h 13.4 KB
Newer Older
jpp's avatar
jpp committed
1 2 3 4 5 6 7 8 9
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef SRC_ASMJS_ASM_TYPER_H_
#define SRC_ASMJS_ASM_TYPER_H_

#include <cstdint>
#include <string>
10
#include <unordered_map>
11
#include <unordered_set>
jpp's avatar
jpp committed
12 13 14 15

#include "src/allocation.h"
#include "src/asmjs/asm-types.h"
#include "src/ast/ast-type-bounds.h"
16
#include "src/ast/ast-types.h"
jpp's avatar
jpp committed
17 18
#include "src/ast/ast.h"
#include "src/effects.h"
19
#include "src/messages.h"
jpp's avatar
jpp committed
20
#include "src/type-info.h"
21 22
#include "src/zone/zone-containers.h"
#include "src/zone/zone.h"
jpp's avatar
jpp committed
23 24 25 26 27

namespace v8 {
namespace internal {
namespace wasm {

28
class AsmType;
jpp's avatar
jpp committed
29
class AsmTyperHarnessBuilder;
30
class SourceLayoutTracker;
jpp's avatar
jpp committed
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53

class AsmTyper final {
 public:
  enum StandardMember {
    kHeap = -4,
    kFFI = -3,
    kStdlib = -2,
    kModule = -1,
    kNone = 0,
    kInfinity,
    kNaN,
    kMathAcos,
    kMathAsin,
    kMathAtan,
    kMathCos,
    kMathSin,
    kMathTan,
    kMathExp,
    kMathLog,
    kMathCeil,
    kMathFloor,
    kMathSqrt,
    kMathAbs,
54
    kMathClz32,
jpp's avatar
jpp committed
55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
    kMathMin,
    kMathMax,
    kMathAtan2,
    kMathPow,
    kMathImul,
    kMathFround,
    kMathE,
    kMathLN10,
    kMathLN2,
    kMathLOG2E,
    kMathLOG10E,
    kMathPI,
    kMathSQRT1_2,
    kMathSQRT2,
  };

  ~AsmTyper() = default;
72 73
  AsmTyper(Isolate* isolate, Zone* zone, Handle<Script> script,
           FunctionLiteral* root);
jpp's avatar
jpp committed
74 75

  bool Validate();
76 77 78 79 80
  // Do asm.js validation in phases (to interleave with conversion to wasm).
  bool ValidateBeforeFunctionsPhase();
  bool ValidateInnerFunction(FunctionDeclaration* decl);
  bool ValidateAfterFunctionsPhase();
  void ClearFunctionNodeTypes();
jpp's avatar
jpp committed
81

82 83
  Handle<JSMessageObject> error_message() const { return error_message_; }
  const MessageLocation* message_location() const { return &message_location_; }
jpp's avatar
jpp committed
84 85

  AsmType* TypeOf(AstNode* node) const;
86
  AsmType* TypeOf(Variable* v) const;
jpp's avatar
jpp committed
87 88
  StandardMember VariableAsStandardMember(Variable* var);

89 90 91 92
  // Allow the asm-wasm-builder to trigger failures (for interleaved
  // validating).
  AsmType* FailWithMessage(const char* text);

93 94 95 96
  typedef std::unordered_set<StandardMember, std::hash<int> > StdlibSet;

  StdlibSet StdlibUses() const { return stdlib_uses_; }

97 98 99 100 101 102 103 104 105 106 107 108 109
  // Each FFI import has a usage-site signature associated with it.
  struct FFIUseSignature {
    Variable* var;
    ZoneVector<AsmType*> arg_types_;
    AsmType* return_type_;
    FFIUseSignature(Variable* v, Zone* zone)
        : var(v), arg_types_(zone), return_type_(nullptr) {}
  };

  const ZoneVector<FFIUseSignature>& FFIUseSignatures() {
    return ffi_use_signatures_;
  }

jpp's avatar
jpp committed
110 111 112 113 114 115 116 117 118
 private:
  friend class v8::internal::wasm::AsmTyperHarnessBuilder;

  class VariableInfo : public ZoneObject {
   public:
    enum Mutability {
      kInvalidMutability,
      kLocal,
      kMutableGlobal,
119 120 121 122 123 124 125
      // *VIOLATION* We support const variables in asm.js, as per the
      //
      // https://discourse.wicg.io/t/allow-const-global-variables/684
      //
      // Global const variables are treated as if they were numeric literals,
      // and can be used anywhere a literal can be used.
      kConstGlobal,
jpp's avatar
jpp committed
126 127 128 129 130 131 132 133 134 135 136 137
      kImmutableGlobal,
    };

    explicit VariableInfo(AsmType* t) : type_(t) {}

    VariableInfo* Clone(Zone* zone) const;

    bool IsMutable() const {
      return mutability_ == kLocal || mutability_ == kMutableGlobal;
    }

    bool IsGlobal() const {
138 139
      return mutability_ == kImmutableGlobal || mutability_ == kConstGlobal ||
             mutability_ == kMutableGlobal;
jpp's avatar
jpp committed
140 141 142 143 144 145 146
    }

    bool IsStdlib() const { return standard_member_ == kStdlib; }
    bool IsFFI() const { return standard_member_ == kFFI; }
    bool IsHeap() const { return standard_member_ == kHeap; }

    void MarkDefined() { missing_definition_ = false; }
147
    void SetFirstForwardUse(const MessageLocation& source_location);
jpp's avatar
jpp committed
148 149 150 151 152 153 154 155 156 157 158 159 160 161

    StandardMember standard_member() const { return standard_member_; }
    void set_standard_member(StandardMember standard_member) {
      standard_member_ = standard_member;
    }

    AsmType* type() const { return type_; }
    void set_type(AsmType* type) { type_ = type; }

    Mutability mutability() const { return mutability_; }
    void set_mutability(Mutability mutability) { mutability_ = mutability; }

    bool missing_definition() const { return missing_definition_; }

162
    const MessageLocation* source_location() { return &source_location_; }
jpp's avatar
jpp committed
163

164 165 166
    static VariableInfo* ForSpecialSymbol(Zone* zone,
                                          StandardMember standard_member);

jpp's avatar
jpp committed
167
   private:
168
    AsmType* type_;
jpp's avatar
jpp committed
169 170 171 172 173
    StandardMember standard_member_ = kNone;
    Mutability mutability_ = kInvalidMutability;
    // missing_definition_ is set to true for forward definition - i.e., use
    // before definition.
    bool missing_definition_ = false;
174 175
    // Used for error messages.
    MessageLocation source_location_;
jpp's avatar
jpp committed
176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214
  };

  // RAII-style manager for the in_function_ member variable.
  struct FunctionScope {
    explicit FunctionScope(AsmTyper* typer) : typer_(typer) {
      DCHECK(!typer_->in_function_);
      typer_->in_function_ = true;
      typer_->local_scope_.Clear();
      typer_->return_type_ = AsmType::None();
    }

    ~FunctionScope() {
      DCHECK(typer_->in_function_);
      typer_->in_function_ = false;
    }

    AsmTyper* typer_;
  };

  // FlattenedStatements is an iterator class for ZoneList<Statement*> that
  // flattens the Block construct in the AST. This is here because we need it in
  // the tests.
  class FlattenedStatements {
   public:
    explicit FlattenedStatements(Zone* zone, ZoneList<Statement*>* s);
    Statement* Next();

   private:
    struct Context {
      explicit Context(ZoneList<Statement*>* s) : statements_(s) {}
      ZoneList<Statement*>* statements_;
      int next_index_ = 0;
    };

    ZoneVector<Context> context_stack_;

    DISALLOW_IMPLICIT_CONSTRUCTORS(FlattenedStatements);
  };

215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248
  class SourceLayoutTracker {
   public:
    SourceLayoutTracker() = default;
    bool IsValid() const;
    void AddUseAsm(const AstNode& node) { use_asm_.AddNewElement(node); }
    void AddGlobal(const AstNode& node) { globals_.AddNewElement(node); }
    void AddFunction(const AstNode& node) { functions_.AddNewElement(node); }
    void AddTable(const AstNode& node) { tables_.AddNewElement(node); }
    void AddExport(const AstNode& node) { exports_.AddNewElement(node); }

   private:
    class Section {
     public:
      Section() = default;
      Section(const Section&) = default;
      Section& operator=(const Section&) = default;

      void AddNewElement(const AstNode& node);
      bool IsPrecededBy(const Section& other) const;

     private:
      int start_ = kNoSourcePosition;
      int end_ = kNoSourcePosition;
    };

    Section use_asm_;
    Section globals_;
    Section functions_;
    Section tables_;
    Section exports_;

    DISALLOW_COPY_AND_ASSIGN(SourceLayoutTracker);
  };

jpp's avatar
jpp committed
249 250 251 252 253 254 255 256 257 258 259 260 261 262 263
  using ObjectTypeMap = ZoneMap<std::string, VariableInfo*>;
  void InitializeStdlib();
  void SetTypeOf(AstNode* node, AsmType* type);

  void AddForwardReference(VariableProxy* proxy, VariableInfo* info);
  bool AddGlobal(Variable* global, VariableInfo* info);
  bool AddLocal(Variable* global, VariableInfo* info);
  // Used for 5.5 GlobalVariableTypeAnnotations
  VariableInfo* ImportLookup(Property* expr);
  // 3.3 Environment Lookup
  // NOTE: In the spec, the lookup function's prototype is
  //
  //   Lookup(Delta, Gamma, x)
  //
  // Delta is the global_scope_ member, and Gamma, local_scope_.
264
  VariableInfo* Lookup(Variable* variable) const;
jpp's avatar
jpp committed
265 266 267 268 269

  // All of the ValidateXXX methods below return AsmType::None() in case of
  // validation failure.

  // 6.1 ValidateModule
270 271 272 273
  AsmType* ValidateModuleBeforeFunctionsPhase(FunctionLiteral* fun);
  AsmType* ValidateModuleFunction(FunctionDeclaration* fun_decl);
  AsmType* ValidateModuleFunctions(FunctionLiteral* fun);
  AsmType* ValidateModuleAfterFunctionsPhase(FunctionLiteral* fun);
jpp's avatar
jpp committed
274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367
  AsmType* ValidateGlobalDeclaration(Assignment* assign);
  // 6.2 ValidateExport
  AsmType* ExportType(VariableProxy* fun_export);
  AsmType* ValidateExport(ReturnStatement* exports);
  // 6.3 ValidateFunctionTable
  AsmType* ValidateFunctionTable(Assignment* assign);
  // 6.4 ValidateFunction
  AsmType* ValidateFunction(FunctionDeclaration* fun_decl);
  // 6.5 ValidateStatement
  AsmType* ValidateStatement(Statement* statement);
  // 6.5.1 BlockStatement
  AsmType* ValidateBlockStatement(Block* block);
  // 6.5.2 ExpressionStatement
  AsmType* ValidateExpressionStatement(ExpressionStatement* expr);
  // 6.5.3 EmptyStatement
  AsmType* ValidateEmptyStatement(EmptyStatement* empty);
  // 6.5.4 IfStatement
  AsmType* ValidateIfStatement(IfStatement* if_stmt);
  // 6.5.5 ReturnStatement
  AsmType* ValidateReturnStatement(ReturnStatement* ret_stmt);
  // 6.5.6 IterationStatement
  // 6.5.6.a WhileStatement
  AsmType* ValidateWhileStatement(WhileStatement* while_stmt);
  // 6.5.6.b DoWhileStatement
  AsmType* ValidateDoWhileStatement(DoWhileStatement* do_while);
  // 6.5.6.c ForStatement
  AsmType* ValidateForStatement(ForStatement* for_stmt);
  // 6.5.7 BreakStatement
  AsmType* ValidateBreakStatement(BreakStatement* brk_stmt);
  // 6.5.8 ContinueStatement
  AsmType* ValidateContinueStatement(ContinueStatement* cont_stmt);
  // 6.5.9 LabelledStatement
  // NOTE: we don't need to handle these: Labelled statements are
  // BreakableStatements in our AST, but BreakableStatement is not a concrete
  // class -- and we're handling all of BreakableStatement's subclasses.
  // 6.5.10 SwitchStatement
  AsmType* ValidateSwitchStatement(SwitchStatement* stmt);
  // 6.6 ValidateCase
  AsmType* ValidateCase(CaseClause* label, int32_t* case_lbl);
  // 6.7 ValidateDefault
  AsmType* ValidateDefault(CaseClause* label);
  // 6.8 ValidateExpression
  AsmType* ValidateExpression(Expression* expr);
  AsmType* ValidateCompareOperation(CompareOperation* cmp);
  AsmType* ValidateBinaryOperation(BinaryOperation* binop);
  // 6.8.1 Expression
  AsmType* ValidateCommaExpression(BinaryOperation* comma);
  // 6.8.2 NumericLiteral
  AsmType* ValidateNumericLiteral(Literal* literal);
  // 6.8.3 Identifier
  AsmType* ValidateIdentifier(VariableProxy* proxy);
  // 6.8.4 CallExpression
  AsmType* ValidateCallExpression(Call* call);
  // 6.8.5 MemberExpression
  AsmType* ValidateMemberExpression(Property* prop);
  // 6.8.6 AssignmentExpression
  AsmType* ValidateAssignmentExpression(Assignment* assignment);
  // 6.8.7 UnaryExpression
  AsmType* ValidateUnaryExpression(UnaryOperation* unop);
  // 6.8.8 MultiplicativeExpression
  AsmType* ValidateMultiplicativeExpression(BinaryOperation* binop);
  // 6.8.9 AdditiveExpression
  AsmType* ValidateAdditiveExpression(BinaryOperation* binop,
                                      uint32_t intish_count);
  // 6.8.10 ShiftExpression
  AsmType* ValidateShiftExpression(BinaryOperation* binop);
  // 6.8.11 RelationalExpression
  AsmType* ValidateRelationalExpression(CompareOperation* cmpop);
  // 6.8.12 EqualityExpression
  AsmType* ValidateEqualityExpression(CompareOperation* cmpop);
  // 6.8.13 BitwiseANDExpression
  AsmType* ValidateBitwiseANDExpression(BinaryOperation* binop);
  // 6.8.14 BitwiseXORExpression
  AsmType* ValidateBitwiseXORExpression(BinaryOperation* binop);
  // 6.8.15 BitwiseORExpression
  AsmType* ValidateBitwiseORExpression(BinaryOperation* binop);
  // 6.8.16 ConditionalExpression
  AsmType* ValidateConditionalExpression(Conditional* cond);
  // 6.9 ValidateCall
  AsmType* ValidateCall(AsmType* return_type, Call* call);
  // 6.10 ValidateHeapAccess
  enum HeapAccessType { LoadFromHeap, StoreToHeap };
  AsmType* ValidateHeapAccess(Property* heap, HeapAccessType access_type);
  // 6.11 ValidateFloatCoercion
  bool IsCallToFround(Call* call);
  AsmType* ValidateFloatCoercion(Call* call);

  // 5.1 ParameterTypeAnnotations
  AsmType* ParameterTypeAnnotations(Variable* parameter,
                                    Expression* annotation);
  // 5.2 ReturnTypeAnnotations
  AsmType* ReturnTypeAnnotations(ReturnStatement* statement);
  // 5.4 VariableTypeAnnotations
  // 5.5 GlobalVariableTypeAnnotations
368 369 370
  AsmType* VariableTypeAnnotations(
      Expression* initializer,
      VariableInfo::Mutability global = VariableInfo::kLocal);
jpp's avatar
jpp committed
371 372 373 374 375
  AsmType* ImportExpression(Property* import);
  AsmType* NewHeapView(CallNew* new_heap_view);

  Isolate* isolate_;
  Zone* zone_;
376
  Handle<Script> script_;
jpp's avatar
jpp committed
377 378 379 380 381 382
  FunctionLiteral* root_;
  bool in_function_ = false;

  AsmType* return_type_ = nullptr;

  ZoneVector<VariableInfo*> forward_definitions_;
383
  ZoneVector<FFIUseSignature> ffi_use_signatures_;
jpp's avatar
jpp committed
384 385 386 387 388
  ObjectTypeMap stdlib_types_;
  ObjectTypeMap stdlib_math_types_;

  // The ASM module name. This member is used to prevent globals from redefining
  // the module name.
389
  VariableInfo* module_info_;
jpp's avatar
jpp committed
390 391 392 393 394 395 396 397
  Handle<String> module_name_;

  // 3 Environments
  ZoneHashMap global_scope_;  // 3.1 Global environment
  ZoneHashMap local_scope_;   // 3.2 Variable environment

  std::uintptr_t stack_limit_;
  bool stack_overflow_ = false;
398 399
  std::unordered_map<AstNode*, AsmType*> module_node_types_;
  std::unordered_map<AstNode*, AsmType*> function_node_types_;
400
  static const int kErrorMessageLimit = 128;
401
  AsmType* fround_type_;
402
  AsmType* ffi_type_;
403 404
  Handle<JSMessageObject> error_message_;
  MessageLocation message_location_;
405
  StdlibSet stdlib_uses_;
jpp's avatar
jpp committed
406

407 408 409 410
  SourceLayoutTracker source_layout_;
  ReturnStatement* module_return_;
  ZoneVector<Assignment*> function_pointer_tables_;

jpp's avatar
jpp committed
411 412 413 414 415 416 417 418
  DISALLOW_IMPLICIT_CONSTRUCTORS(AsmTyper);
};

}  // namespace wasm
}  // namespace internal
}  // namespace v8

#endif  // SRC_ASMJS_ASM_TYPER_H_