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#include "src/asmjs/asm-typer.h"
6
7#include <algorithm>
8#include <limits>
9#include <memory>
10#include <string>
11
12#include "include/v8.h"
13#include "src/v8.h"
14
15#include "src/asmjs/asm-types.h"
16#include "src/ast/ast.h"
17#include "src/ast/scopes.h"
18#include "src/base/bits.h"
19#include "src/codegen.h"
20#include "src/globals.h"
21#include "src/messages.h"
22#include "src/objects-inl.h"
23#include "src/utils.h"
24#include "src/vector.h"
25
26#define FAIL_LOCATION_RAW(location, msg)                               \
27  do {                                                                 \
28    Handle<String> message(                                            \
29        isolate_->factory()->InternalizeOneByteString(msg));           \
30    error_message_ = MessageHandler::MakeMessageObject(                \
31        isolate_, MessageTemplate::kAsmJsInvalid, (location), message, \
32        Handle<JSArray>::null());                                      \
33    error_message_->set_error_level(v8::Isolate::kMessageWarning);     \
34    message_location_ = *(location);                                   \
35    return AsmType::None();                                            \
36  } while (false)
37
38#define FAIL_RAW(node, msg)                                                \
39  do {                                                                     \
40    MessageLocation location(script_, node->position(), node->position()); \
41    FAIL_LOCATION_RAW(&location, msg);                                     \
42  } while (false)
43
44#define FAIL_LOCATION(location, msg) \
45  FAIL_LOCATION_RAW(location, STATIC_CHAR_VECTOR(msg))
46
47#define FAIL(node, msg) FAIL_RAW(node, STATIC_CHAR_VECTOR(msg))
48
49#define RECURSE(call)                                             \
50  do {                                                            \
51    if (GetCurrentStackPosition() < stack_limit_) {               \
52      stack_overflow_ = true;                                     \
53      FAIL(root_, "Stack overflow while parsing asm.js module."); \
54    }                                                             \
55                                                                  \
56    AsmType* result = (call);                                     \
57    if (stack_overflow_) {                                        \
58      return AsmType::None();                                     \
59    }                                                             \
60                                                                  \
61    if (result == AsmType::None()) {                              \
62      return AsmType::None();                                     \
63    }                                                             \
64  } while (false)
65
66namespace v8 {
67namespace internal {
68namespace wasm {
69namespace {
70static const uint32_t LargestFixNum = std::numeric_limits<int32_t>::max();
71}  // namespace
72
73using v8::internal::AstNode;
74using v8::internal::GetCurrentStackPosition;
75
76// ----------------------------------------------------------------------------
77// Implementation of AsmTyper::FlattenedStatements
78
79AsmTyper::FlattenedStatements::FlattenedStatements(Zone* zone,
80                                                   ZoneList<Statement*>* s)
81    : context_stack_(zone) {
82  context_stack_.emplace_back(Context(s));
83}
84
85Statement* AsmTyper::FlattenedStatements::Next() {
86  for (;;) {
87    if (context_stack_.empty()) {
88      return nullptr;
89    }
90
91    Context* current = &context_stack_.back();
92
93    if (current->statements_->length() <= current->next_index_) {
94      context_stack_.pop_back();
95      continue;
96    }
97
98    Statement* current_statement =
99        current->statements_->at(current->next_index_++);
100    if (current_statement->IsBlock()) {
101      context_stack_.emplace_back(
102          Context(current_statement->AsBlock()->statements()));
103      continue;
104    }
105
106    return current_statement;
107  }
108}
109
110// ----------------------------------------------------------------------------
111// Implementation of AsmTyper::SourceLayoutTracker
112
113bool AsmTyper::SourceLayoutTracker::IsValid() const {
114  const Section* kAllSections[] = {&use_asm_, &globals_, &functions_, &tables_,
115                                   &exports_};
116  for (size_t ii = 0; ii < arraysize(kAllSections); ++ii) {
117    const auto& curr_section = *kAllSections[ii];
118    for (size_t jj = ii + 1; jj < arraysize(kAllSections); ++jj) {
119      if (curr_section.IsPrecededBy(*kAllSections[jj])) {
120        return false;
121      }
122    }
123  }
124  return true;
125}
126
127void AsmTyper::SourceLayoutTracker::Section::AddNewElement(
128    const AstNode& node) {
129  const int node_pos = node.position();
130  if (start_ == kNoSourcePosition) {
131    start_ = node_pos;
132  } else {
133    start_ = std::min(start_, node_pos);
134  }
135  if (end_ == kNoSourcePosition) {
136    end_ = node_pos;
137  } else {
138    end_ = std::max(end_, node_pos);
139  }
140}
141
142bool AsmTyper::SourceLayoutTracker::Section::IsPrecededBy(
143    const Section& other) const {
144  if (start_ == kNoSourcePosition) {
145    DCHECK_EQ(end_, kNoSourcePosition);
146    return false;
147  }
148  if (other.start_ == kNoSourcePosition) {
149    DCHECK_EQ(other.end_, kNoSourcePosition);
150    return false;
151  }
152  DCHECK_LE(start_, end_);
153  DCHECK_LE(other.start_, other.end_);
154  return other.start_ <= end_;
155}
156
157// ----------------------------------------------------------------------------
158// Implementation of AsmTyper::VariableInfo
159
160AsmTyper::VariableInfo* AsmTyper::VariableInfo::ForSpecialSymbol(
161    Zone* zone, StandardMember standard_member) {
162  DCHECK(standard_member == kStdlib || standard_member == kFFI ||
163         standard_member == kHeap || standard_member == kModule);
164  auto* new_var_info = new (zone) VariableInfo(AsmType::None());
165  new_var_info->standard_member_ = standard_member;
166  new_var_info->mutability_ = kImmutableGlobal;
167  return new_var_info;
168}
169
170AsmTyper::VariableInfo* AsmTyper::VariableInfo::Clone(Zone* zone) const {
171  CHECK(standard_member_ != kNone);
172  CHECK(!type_->IsA(AsmType::None()));
173  auto* new_var_info = new (zone) VariableInfo(type_);
174  new_var_info->standard_member_ = standard_member_;
175  new_var_info->mutability_ = mutability_;
176  return new_var_info;
177}
178
179void AsmTyper::VariableInfo::SetFirstForwardUse(
180    const MessageLocation& source_location) {
181  missing_definition_ = true;
182  source_location_ = source_location;
183}
184
185// ----------------------------------------------------------------------------
186// Implementation of AsmTyper
187
188AsmTyper::AsmTyper(Isolate* isolate, Zone* zone, Handle<Script> script,
189                   FunctionLiteral* root)
190    : isolate_(isolate),
191      zone_(zone),
192      script_(script),
193      root_(root),
194      forward_definitions_(zone),
195      ffi_use_signatures_(zone),
196      stdlib_types_(zone),
197      stdlib_math_types_(zone),
198      module_info_(VariableInfo::ForSpecialSymbol(zone_, kModule)),
199      global_scope_(ZoneHashMap::kDefaultHashMapCapacity,
200                    ZoneAllocationPolicy(zone)),
201      local_scope_(ZoneHashMap::kDefaultHashMapCapacity,
202                   ZoneAllocationPolicy(zone)),
203      stack_limit_(isolate->stack_guard()->real_climit()),
204      fround_type_(AsmType::FroundType(zone_)),
205      ffi_type_(AsmType::FFIType(zone_)),
206      function_pointer_tables_(zone_) {
207  InitializeStdlib();
208}
209
210namespace {
211bool ValidAsmIdentifier(Handle<String> name) {
212  static const char* kInvalidAsmNames[] = {"eval", "arguments"};
213
214  for (size_t ii = 0; ii < arraysize(kInvalidAsmNames); ++ii) {
215    if (strcmp(name->ToCString().get(), kInvalidAsmNames[ii]) == 0) {
216      return false;
217    }
218  }
219  return true;
220}
221}  // namespace
222
223void AsmTyper::InitializeStdlib() {
224  auto* d = AsmType::Double();
225  auto* dq = AsmType::DoubleQ();
226  auto* dq2d = AsmType::Function(zone_, d);
227  dq2d->AsFunctionType()->AddArgument(dq);
228
229  auto* dqdq2d = AsmType::Function(zone_, d);
230  dqdq2d->AsFunctionType()->AddArgument(dq);
231  dqdq2d->AsFunctionType()->AddArgument(dq);
232
233  auto* f = AsmType::Float();
234  auto* fq = AsmType::FloatQ();
235  auto* fq2f = AsmType::Function(zone_, f);
236  fq2f->AsFunctionType()->AddArgument(fq);
237
238  auto* s = AsmType::Signed();
239  auto* s2s = AsmType::Function(zone_, s);
240  s2s->AsFunctionType()->AddArgument(s);
241
242  auto* i = AsmType::Int();
243  auto* i2s = AsmType::Function(zone_, s);
244  i2s->AsFunctionType()->AddArgument(i);
245
246  auto* ii2s = AsmType::Function(zone_, s);
247  ii2s->AsFunctionType()->AddArgument(i);
248  ii2s->AsFunctionType()->AddArgument(i);
249
250  auto* minmax_d = AsmType::MinMaxType(zone_, d, d);
251  // *VIOLATION* The float variant is not part of the spec, but firefox accepts
252  // it.
253  auto* minmax_f = AsmType::MinMaxType(zone_, f, f);
254  auto* minmax_i = AsmType::MinMaxType(zone_, s, i);
255  auto* minmax = AsmType::OverloadedFunction(zone_);
256  minmax->AsOverloadedFunctionType()->AddOverload(minmax_i);
257  minmax->AsOverloadedFunctionType()->AddOverload(minmax_f);
258  minmax->AsOverloadedFunctionType()->AddOverload(minmax_d);
259
260  auto* fround = fround_type_;
261
262  auto* abs = AsmType::OverloadedFunction(zone_);
263  abs->AsOverloadedFunctionType()->AddOverload(s2s);
264  abs->AsOverloadedFunctionType()->AddOverload(dq2d);
265  abs->AsOverloadedFunctionType()->AddOverload(fq2f);
266
267  auto* ceil = AsmType::OverloadedFunction(zone_);
268  ceil->AsOverloadedFunctionType()->AddOverload(dq2d);
269  ceil->AsOverloadedFunctionType()->AddOverload(fq2f);
270
271  auto* floor = ceil;
272  auto* sqrt = ceil;
273
274  struct StandardMemberInitializer {
275    const char* name;
276    StandardMember standard_member;
277    AsmType* type;
278  };
279
280  const StandardMemberInitializer stdlib[] = {{"Infinity", kInfinity, d},
281                                              {"NaN", kNaN, d},
282#define ASM_TYPED_ARRAYS(V) \
283  V(Uint8)                  \
284  V(Int8)                   \
285  V(Uint16)                 \
286  V(Int16)                  \
287  V(Uint32)                 \
288  V(Int32)                  \
289  V(Float32)                \
290  V(Float64)
291
292#define ASM_TYPED_ARRAY(TypeName) \
293  {#TypeName "Array", kNone, AsmType::TypeName##Array()},
294                                              ASM_TYPED_ARRAYS(ASM_TYPED_ARRAY)
295#undef ASM_TYPED_ARRAY
296  };
297  for (size_t ii = 0; ii < arraysize(stdlib); ++ii) {
298    stdlib_types_[stdlib[ii].name] = new (zone_) VariableInfo(stdlib[ii].type);
299    stdlib_types_[stdlib[ii].name]->set_standard_member(
300        stdlib[ii].standard_member);
301    stdlib_types_[stdlib[ii].name]->set_mutability(
302        VariableInfo::kImmutableGlobal);
303  }
304
305  const StandardMemberInitializer math[] = {
306      {"PI", kMathPI, d},
307      {"E", kMathE, d},
308      {"LN2", kMathLN2, d},
309      {"LN10", kMathLN10, d},
310      {"LOG2E", kMathLOG2E, d},
311      {"LOG10E", kMathLOG10E, d},
312      {"SQRT2", kMathSQRT2, d},
313      {"SQRT1_2", kMathSQRT1_2, d},
314      {"imul", kMathImul, ii2s},
315      {"abs", kMathAbs, abs},
316      // NOTE: clz32 should return fixnum. The current typer can only return
317      // Signed, Float, or Double, so it returns Signed in our version of
318      // asm.js.
319      {"clz32", kMathClz32, i2s},
320      {"ceil", kMathCeil, ceil},
321      {"floor", kMathFloor, floor},
322      {"fround", kMathFround, fround},
323      {"pow", kMathPow, dqdq2d},
324      {"exp", kMathExp, dq2d},
325      {"log", kMathLog, dq2d},
326      {"min", kMathMin, minmax},
327      {"max", kMathMax, minmax},
328      {"sqrt", kMathSqrt, sqrt},
329      {"cos", kMathCos, dq2d},
330      {"sin", kMathSin, dq2d},
331      {"tan", kMathTan, dq2d},
332      {"acos", kMathAcos, dq2d},
333      {"asin", kMathAsin, dq2d},
334      {"atan", kMathAtan, dq2d},
335      {"atan2", kMathAtan2, dqdq2d},
336  };
337  for (size_t ii = 0; ii < arraysize(math); ++ii) {
338    stdlib_math_types_[math[ii].name] = new (zone_) VariableInfo(math[ii].type);
339    stdlib_math_types_[math[ii].name]->set_standard_member(
340        math[ii].standard_member);
341    stdlib_math_types_[math[ii].name]->set_mutability(
342        VariableInfo::kImmutableGlobal);
343  }
344}
345
346// Used for 5.5 GlobalVariableTypeAnnotations
347AsmTyper::VariableInfo* AsmTyper::ImportLookup(Property* import) {
348  auto* obj = import->obj();
349  auto* key = import->key()->AsLiteral();
350  if (key == nullptr) {
351    return nullptr;
352  }
353
354  ObjectTypeMap* stdlib = &stdlib_types_;
355  if (auto* obj_as_property = obj->AsProperty()) {
356    // This can only be stdlib.Math
357    auto* math_name = obj_as_property->key()->AsLiteral();
358    if (math_name == nullptr || !math_name->IsPropertyName()) {
359      return nullptr;
360    }
361
362    if (!math_name->AsPropertyName()->IsUtf8EqualTo(CStrVector("Math"))) {
363      return nullptr;
364    }
365
366    auto* stdlib_var_proxy = obj_as_property->obj()->AsVariableProxy();
367    if (stdlib_var_proxy == nullptr) {
368      return nullptr;
369    }
370    obj = stdlib_var_proxy;
371    stdlib = &stdlib_math_types_;
372  }
373
374  auto* obj_as_var_proxy = obj->AsVariableProxy();
375  if (obj_as_var_proxy == nullptr) {
376    return nullptr;
377  }
378
379  auto* obj_info = Lookup(obj_as_var_proxy->var());
380  if (obj_info == nullptr) {
381    return nullptr;
382  }
383
384  if (obj_info->IsFFI()) {
385    // For FFI we can't validate import->key, so assume this is OK.
386    return obj_info;
387  }
388
389  if (!key->IsPropertyName()) {
390    return nullptr;
391  }
392
393  std::unique_ptr<char[]> aname = key->AsPropertyName()->ToCString();
394  ObjectTypeMap::iterator i = stdlib->find(std::string(aname.get()));
395  if (i == stdlib->end()) {
396    return nullptr;
397  }
398  stdlib_uses_.insert(i->second->standard_member());
399  return i->second;
400}
401
402AsmTyper::VariableInfo* AsmTyper::Lookup(Variable* variable) const {
403  const ZoneHashMap* scope = in_function_ ? &local_scope_ : &global_scope_;
404  ZoneHashMap::Entry* entry =
405      scope->Lookup(variable, ComputePointerHash(variable));
406  if (entry == nullptr && in_function_) {
407    entry = global_scope_.Lookup(variable, ComputePointerHash(variable));
408  }
409
410  if (entry == nullptr && !module_name_.is_null() &&
411      module_name_->Equals(*variable->name())) {
412    return module_info_;
413  }
414
415  return entry ? reinterpret_cast<VariableInfo*>(entry->value) : nullptr;
416}
417
418void AsmTyper::AddForwardReference(VariableProxy* proxy, VariableInfo* info) {
419  MessageLocation location(script_, proxy->position(), proxy->position());
420  info->SetFirstForwardUse(location);
421  forward_definitions_.push_back(info);
422}
423
424bool AsmTyper::AddGlobal(Variable* variable, VariableInfo* info) {
425  // We can't DCHECK(!in_function_) because function may actually install global
426  // names (forward defined functions and function tables.)
427  DCHECK(info->mutability() != VariableInfo::kInvalidMutability);
428  DCHECK(info->IsGlobal());
429  DCHECK(ValidAsmIdentifier(variable->name()));
430
431  if (!module_name_.is_null() && module_name_->Equals(*variable->name())) {
432    return false;
433  }
434
435  ZoneHashMap::Entry* entry = global_scope_.LookupOrInsert(
436      variable, ComputePointerHash(variable), ZoneAllocationPolicy(zone_));
437
438  if (entry->value != nullptr) {
439    return false;
440  }
441
442  entry->value = info;
443  return true;
444}
445
446bool AsmTyper::AddLocal(Variable* variable, VariableInfo* info) {
447  DCHECK(in_function_);
448  DCHECK(info->mutability() != VariableInfo::kInvalidMutability);
449  DCHECK(!info->IsGlobal());
450  DCHECK(ValidAsmIdentifier(variable->name()));
451
452  ZoneHashMap::Entry* entry = local_scope_.LookupOrInsert(
453      variable, ComputePointerHash(variable), ZoneAllocationPolicy(zone_));
454
455  if (entry->value != nullptr) {
456    return false;
457  }
458
459  entry->value = info;
460  return true;
461}
462
463void AsmTyper::SetTypeOf(AstNode* node, AsmType* type) {
464  DCHECK_NE(type, AsmType::None());
465  if (in_function_) {
466    DCHECK(function_node_types_.find(node) == function_node_types_.end());
467    function_node_types_.insert(std::make_pair(node, type));
468  } else {
469    DCHECK(module_node_types_.find(node) == module_node_types_.end());
470    module_node_types_.insert(std::make_pair(node, type));
471  }
472}
473
474namespace {
475bool IsLiteralDouble(Literal* literal) {
476  return literal->raw_value()->IsNumber() &&
477         literal->raw_value()->ContainsDot();
478}
479
480bool IsLiteralInt(Literal* literal) {
481  return literal->raw_value()->IsNumber() &&
482         !literal->raw_value()->ContainsDot();
483}
484
485bool IsLiteralMinus1(Literal* literal) {
486  return IsLiteralInt(literal) && literal->raw_value()->AsNumber() == -1.0;
487}
488
489bool IsLiteral1Dot0(Literal* literal) {
490  return IsLiteralDouble(literal) && literal->raw_value()->AsNumber() == 1.0;
491}
492
493bool IsLiteral0(Literal* literal) {
494  return IsLiteralInt(literal) && literal->raw_value()->AsNumber() == 0.0;
495}
496}  // namespace
497
498AsmType* AsmTyper::TypeOf(AstNode* node) const {
499  auto node_type_iter = function_node_types_.find(node);
500  if (node_type_iter != function_node_types_.end()) {
501    return node_type_iter->second;
502  }
503  node_type_iter = module_node_types_.find(node);
504  if (node_type_iter != module_node_types_.end()) {
505    return node_type_iter->second;
506  }
507
508  // Sometimes literal nodes are not added to the node_type_ map simply because
509  // their are not visited with ValidateExpression().
510  if (auto* literal = node->AsLiteral()) {
511    if (IsLiteralDouble(literal)) {
512      return AsmType::Double();
513    }
514    if (!IsLiteralInt(literal)) {
515      return AsmType::None();
516    }
517    uint32_t u;
518    if (literal->value()->ToUint32(&u)) {
519      if (u > LargestFixNum) {
520        return AsmType::Unsigned();
521      }
522      return AsmType::FixNum();
523    }
524    int32_t i;
525    if (literal->value()->ToInt32(&i)) {
526      return AsmType::Signed();
527    }
528  }
529
530  return AsmType::None();
531}
532
533AsmType* AsmTyper::TypeOf(Variable* v) const { return Lookup(v)->type(); }
534
535AsmTyper::StandardMember AsmTyper::VariableAsStandardMember(Variable* var) {
536  auto* var_info = Lookup(var);
537  if (var_info == nullptr) {
538    return kNone;
539  }
540  StandardMember member = var_info->standard_member();
541  return member;
542}
543
544AsmType* AsmTyper::FailWithMessage(const char* text) {
545  FAIL_RAW(root_, OneByteVector(text));
546}
547
548bool AsmTyper::Validate() {
549  return ValidateBeforeFunctionsPhase() &&
550         !AsmType::None()->IsExactly(ValidateModuleFunctions(root_)) &&
551         ValidateAfterFunctionsPhase();
552}
553
554bool AsmTyper::ValidateBeforeFunctionsPhase() {
555  if (!AsmType::None()->IsExactly(ValidateModuleBeforeFunctionsPhase(root_))) {
556    return true;
557  }
558  return false;
559}
560
561bool AsmTyper::ValidateInnerFunction(FunctionDeclaration* fun_decl) {
562  if (!AsmType::None()->IsExactly(ValidateModuleFunction(fun_decl))) {
563    return true;
564  }
565  return false;
566}
567
568bool AsmTyper::ValidateAfterFunctionsPhase() {
569  if (!AsmType::None()->IsExactly(ValidateModuleAfterFunctionsPhase(root_))) {
570    return true;
571  }
572  return false;
573}
574
575void AsmTyper::ClearFunctionNodeTypes() { function_node_types_.clear(); }
576
577AsmType* AsmTyper::TriggerParsingError() { FAIL(root_, "Parsing error"); }
578
579namespace {
580bool IsUseAsmDirective(Statement* first_statement) {
581  ExpressionStatement* use_asm = first_statement->AsExpressionStatement();
582  if (use_asm == nullptr) {
583    return false;
584  }
585
586  Literal* use_asm_literal = use_asm->expression()->AsLiteral();
587
588  if (use_asm_literal == nullptr) {
589    return false;
590  }
591
592  return use_asm_literal->raw_value()->AsString()->IsOneByteEqualTo("use asm");
593}
594
595Assignment* ExtractInitializerExpression(Statement* statement) {
596  auto* expr_stmt = statement->AsExpressionStatement();
597  if (expr_stmt == nullptr) {
598    // Done with initializers.
599    return nullptr;
600  }
601  auto* assign = expr_stmt->expression()->AsAssignment();
602  if (assign == nullptr) {
603    // Done with initializers.
604    return nullptr;
605  }
606  if (assign->op() != Token::INIT) {
607    // Done with initializers.
608    return nullptr;
609  }
610  return assign;
611}
612
613}  // namespace
614
615// 6.1 ValidateModule
616AsmType* AsmTyper::ValidateModuleBeforeFunctionsPhase(FunctionLiteral* fun) {
617  DeclarationScope* scope = fun->scope();
618  if (!scope->is_function_scope()) FAIL(fun, "Not at function scope.");
619  if (scope->inner_scope_calls_eval()) {
620    FAIL(fun, "Invalid asm.js module using eval.");
621  }
622  if (!ValidAsmIdentifier(fun->name()))
623    FAIL(fun, "Invalid asm.js identifier in module name.");
624  module_name_ = fun->name();
625
626  // Allowed parameters: Stdlib, FFI, Mem
627  static const int MaxModuleParameters = 3;
628  if (scope->num_parameters() > MaxModuleParameters) {
629    FAIL(fun, "asm.js modules may not have more than three parameters.");
630  }
631
632  struct {
633    StandardMember standard_member;
634  } kModuleParamInfo[3] = {
635      {kStdlib}, {kFFI}, {kHeap},
636  };
637
638  for (int ii = 0; ii < scope->num_parameters(); ++ii) {
639    Variable* param = scope->parameter(ii);
640    DCHECK(param);
641
642    if (!ValidAsmIdentifier(param->name())) {
643      FAIL(fun, "Invalid asm.js identifier in module parameter.");
644    }
645
646    auto* param_info = VariableInfo::ForSpecialSymbol(
647        zone_, kModuleParamInfo[ii].standard_member);
648
649    if (!AddGlobal(param, param_info)) {
650      FAIL(fun, "Redeclared identifier in module parameter.");
651    }
652  }
653
654  FlattenedStatements iter(zone_, fun->body());
655  auto* use_asm_directive = iter.Next();
656  if (use_asm_directive == nullptr) {
657    FAIL(fun, "Missing \"use asm\".");
658  }
659  // Check for extra assignment inserted by the parser when in this form:
660  // (function Module(a, b, c) {... })
661  ExpressionStatement* estatement = use_asm_directive->AsExpressionStatement();
662  if (estatement != nullptr) {
663    Assignment* assignment = estatement->expression()->AsAssignment();
664    if (assignment != nullptr && assignment->target()->IsVariableProxy() &&
665        assignment->target()
666            ->AsVariableProxy()
667            ->var()
668            ->is_sloppy_function_name()) {
669      use_asm_directive = iter.Next();
670    }
671  }
672  if (!IsUseAsmDirective(use_asm_directive)) {
673    FAIL(fun, "Missing \"use asm\".");
674  }
675  source_layout_.AddUseAsm(*use_asm_directive);
676  module_return_ = nullptr;
677
678  // *VIOLATION* The spec states that globals should be followed by function
679  // declarations, which should be followed by function pointer tables, followed
680  // by the module export (return) statement. Our AST might be rearraged by the
681  // parser, so we can't rely on it being in source code order.
682  while (Statement* current = iter.Next()) {
683    if (auto* assign = ExtractInitializerExpression(current)) {
684      if (assign->value()->IsArrayLiteral()) {
685        // Save function tables for later validation.
686        function_pointer_tables_.push_back(assign);
687      } else {
688        RECURSE(ValidateGlobalDeclaration(assign));
689        source_layout_.AddGlobal(*assign);
690      }
691      continue;
692    }
693
694    if (auto* current_as_return = current->AsReturnStatement()) {
695      if (module_return_ != nullptr) {
696        FAIL(fun, "Multiple export statements.");
697      }
698      module_return_ = current_as_return;
699      source_layout_.AddExport(*module_return_);
700      continue;
701    }
702
703    FAIL(current, "Invalid top-level statement in asm.js module.");
704  }
705
706  return AsmType::Int();  // Any type that is not AsmType::None();
707}
708
709AsmType* AsmTyper::ValidateModuleFunction(FunctionDeclaration* fun_decl) {
710  RECURSE(ValidateFunction(fun_decl));
711  source_layout_.AddFunction(*fun_decl);
712
713  return AsmType::Int();  // Any type that is not AsmType::None();
714}
715
716AsmType* AsmTyper::ValidateModuleFunctions(FunctionLiteral* fun) {
717  DeclarationScope* scope = fun->scope();
718  Declaration::List* decls = scope->declarations();
719  for (Declaration* decl : *decls) {
720    if (FunctionDeclaration* fun_decl = decl->AsFunctionDeclaration()) {
721      RECURSE(ValidateModuleFunction(fun_decl));
722      continue;
723    }
724  }
725
726  return AsmType::Int();  // Any type that is not AsmType::None();
727}
728
729AsmType* AsmTyper::ValidateModuleAfterFunctionsPhase(FunctionLiteral* fun) {
730  for (auto* function_table : function_pointer_tables_) {
731    RECURSE(ValidateFunctionTable(function_table));
732    source_layout_.AddTable(*function_table);
733  }
734
735  DeclarationScope* scope = fun->scope();
736  Declaration::List* decls = scope->declarations();
737  for (Declaration* decl : *decls) {
738    if (decl->IsFunctionDeclaration()) {
739      continue;
740    }
741
742    VariableDeclaration* var_decl = decl->AsVariableDeclaration();
743    if (var_decl == nullptr) {
744      FAIL(decl, "Invalid asm.js declaration.");
745    }
746
747    auto* var_proxy = var_decl->proxy();
748    if (var_proxy == nullptr) {
749      FAIL(decl, "Invalid asm.js declaration.");
750    }
751
752    if (Lookup(var_proxy->var()) == nullptr) {
753      FAIL(decl, "Global variable missing initializer in asm.js module.");
754    }
755  }
756
757  // 6.2 ValidateExport
758  if (module_return_ == nullptr) {
759    FAIL(fun, "Missing asm.js module export.");
760  }
761
762  for (auto* forward_def : forward_definitions_) {
763    if (forward_def->missing_definition()) {
764      FAIL_LOCATION(forward_def->source_location(),
765                    "Missing definition for forward declared identifier.");
766    }
767  }
768
769  RECURSE(ValidateExport(module_return_));
770
771  if (!source_layout_.IsValid()) {
772    FAIL(fun, "Invalid asm.js source code layout.");
773  }
774
775  return AsmType::Int();  // Any type that is not AsmType::None();
776}
777
778namespace {
779bool IsDoubleAnnotation(BinaryOperation* binop) {
780  // *VIOLATION* The parser replaces uses of +x with x*1.0.
781  if (binop->op() != Token::MUL) {
782    return false;
783  }
784
785  auto* right_as_literal = binop->right()->AsLiteral();
786  if (right_as_literal == nullptr) {
787    return false;
788  }
789
790  return IsLiteral1Dot0(right_as_literal);
791}
792
793bool IsIntAnnotation(BinaryOperation* binop) {
794  if (binop->op() != Token::BIT_OR) {
795    return false;
796  }
797
798  auto* right_as_literal = binop->right()->AsLiteral();
799  if (right_as_literal == nullptr) {
800    return false;
801  }
802
803  return IsLiteral0(right_as_literal);
804}
805}  // namespace
806
807AsmType* AsmTyper::ValidateGlobalDeclaration(Assignment* assign) {
808  DCHECK(!assign->is_compound());
809  if (assign->is_compound()) {
810    FAIL(assign,
811         "Compound assignment not supported when declaring global variables.");
812  }
813
814  auto* target = assign->target();
815  if (!target->IsVariableProxy()) {
816    FAIL(target, "Module assignments may only assign to globals.");
817  }
818  auto* target_variable = target->AsVariableProxy()->var();
819  auto* target_info = Lookup(target_variable);
820
821  if (target_info != nullptr) {
822    FAIL(target, "Redefined global variable.");
823  }
824
825  auto* value = assign->value();
826  // Not all types of assignment are allowed by asm.js. See
827  // 5.5 Global Variable Type Annotations.
828  bool global_variable = false;
829  if (value->IsLiteral() || value->IsCall()) {
830    AsmType* type = nullptr;
831    VariableInfo::Mutability mutability;
832    if (target_variable->mode() == CONST) {
833      mutability = VariableInfo::kConstGlobal;
834    } else {
835      mutability = VariableInfo::kMutableGlobal;
836    }
837    RECURSE(type = VariableTypeAnnotations(value, mutability));
838    target_info = new (zone_) VariableInfo(type);
839    target_info->set_mutability(mutability);
840    global_variable = true;
841  } else if (value->IsProperty()) {
842    target_info = ImportLookup(value->AsProperty());
843    if (target_info == nullptr) {
844      FAIL(assign, "Invalid import.");
845    }
846    CHECK(target_info->mutability() == VariableInfo::kImmutableGlobal);
847    if (target_info->IsFFI()) {
848      // create a new target info that represents a foreign variable.
849      target_info = new (zone_) VariableInfo(ffi_type_);
850      target_info->set_mutability(VariableInfo::kImmutableGlobal);
851    } else if (target_info->type()->IsA(AsmType::Heap())) {
852      FAIL(assign, "Heap view types can not be aliased.");
853    } else {
854      target_info = target_info->Clone(zone_);
855    }
856  } else if (value->IsBinaryOperation()) {
857    // This should either be:
858    //
859    // var <> = ffi.<>|0
860    //
861    // or
862    //
863    // var <> = +ffi.<>
864    auto* value_binop = value->AsBinaryOperation();
865    auto* left = value_binop->left();
866    AsmType* import_type = nullptr;
867
868    if (IsDoubleAnnotation(value_binop)) {
869      import_type = AsmType::Double();
870    } else if (IsIntAnnotation(value_binop)) {
871      import_type = AsmType::Int();
872    } else {
873      FAIL(value,
874           "Invalid initializer for foreign import - unrecognized annotation.");
875    }
876
877    if (!left->IsProperty()) {
878      FAIL(value,
879           "Invalid initializer for foreign import - must import member.");
880    }
881    target_info = ImportLookup(left->AsProperty());
882    if (target_info == nullptr) {
883      // TODO(jpp): this error message is innacurate: this may fail if the
884      // object lookup fails, or if the property lookup fails, or even if the
885      // import is bogus like a().c.
886      FAIL(value,
887           "Invalid initializer for foreign import - object lookup failed.");
888    }
889    CHECK(target_info->mutability() == VariableInfo::kImmutableGlobal);
890    if (!target_info->IsFFI()) {
891      FAIL(value,
892           "Invalid initializer for foreign import - object is not the ffi.");
893    }
894
895    // Create a new target info that represents the foreign import.
896    target_info = new (zone_) VariableInfo(import_type);
897    target_info->set_mutability(VariableInfo::kMutableGlobal);
898  } else if (value->IsCallNew()) {
899    AsmType* type = nullptr;
900    RECURSE(type = NewHeapView(value->AsCallNew()));
901    target_info = new (zone_) VariableInfo(type);
902    target_info->set_mutability(VariableInfo::kImmutableGlobal);
903  } else if (auto* proxy = value->AsVariableProxy()) {
904    auto* var_info = Lookup(proxy->var());
905
906    if (var_info == nullptr) {
907      FAIL(value, "Undeclared identifier in global initializer");
908    }
909
910    if (var_info->mutability() != VariableInfo::kConstGlobal) {
911      FAIL(value, "Identifier used to initialize a global must be a const");
912    }
913
914    target_info = new (zone_) VariableInfo(var_info->type());
915    if (target_variable->mode() == CONST) {
916      target_info->set_mutability(VariableInfo::kConstGlobal);
917    } else {
918      target_info->set_mutability(VariableInfo::kMutableGlobal);
919    }
920  }
921
922  if (target_info == nullptr) {
923    FAIL(assign, "Invalid global variable initializer.");
924  }
925
926  if (!ValidAsmIdentifier(target_variable->name())) {
927    FAIL(target, "Invalid asm.js identifier in global variable.");
928  }
929
930  if (!AddGlobal(target_variable, target_info)) {
931    FAIL(assign, "Redeclared global identifier.");
932  }
933
934  DCHECK(target_info->type() != AsmType::None());
935  if (!global_variable) {
936    // Global variables have their types set in VariableTypeAnnotations.
937    SetTypeOf(value, target_info->type());
938  }
939  SetTypeOf(assign, target_info->type());
940  SetTypeOf(target, target_info->type());
941  return target_info->type();
942}
943
944// 6.2 ValidateExport
945AsmType* AsmTyper::ExportType(VariableProxy* fun_export) {
946  auto* fun_info = Lookup(fun_export->var());
947  if (fun_info == nullptr) {
948    FAIL(fun_export, "Undefined identifier in asm.js module export.");
949  }
950
951  if (fun_info->standard_member() != kNone) {
952    FAIL(fun_export, "Module cannot export standard library functions.");
953  }
954
955  auto* type = fun_info->type();
956  if (type->AsFFIType() != nullptr) {
957    FAIL(fun_export, "Module cannot export foreign functions.");
958  }
959
960  if (type->AsFunctionTableType() != nullptr) {
961    FAIL(fun_export, "Module cannot export function tables.");
962  }
963
964  if (fun_info->type()->AsFunctionType() == nullptr) {
965    FAIL(fun_export, "Module export is not an asm.js function.");
966  }
967
968  if (!fun_export->var()->is_function()) {
969    FAIL(fun_export, "Module exports must be function declarations.");
970  }
971
972  return type;
973}
974
975AsmType* AsmTyper::ValidateExport(ReturnStatement* exports) {
976  // asm.js modules can export single functions, or multiple functions in an
977  // object literal.
978  if (auto* fun_export = exports->expression()->AsVariableProxy()) {
979    // Exporting single function.
980    AsmType* export_type;
981    RECURSE(export_type = ExportType(fun_export));
982    return export_type;
983  }
984
985  if (auto* obj_export = exports->expression()->AsObjectLiteral()) {
986    // Exporting object literal.
987    for (auto* prop : *obj_export->properties()) {
988      if (!prop->key()->IsLiteral()) {
989        FAIL(prop->key(),
990             "Only normal object properties may be used in the export object "
991             "literal.");
992      }
993      if (!prop->key()->AsLiteral()->IsPropertyName()) {
994        FAIL(prop->key(),
995             "Exported functions must have valid identifier names.");
996      }
997
998      auto* export_obj = prop->value()->AsVariableProxy();
999      if (export_obj == nullptr) {
1000        FAIL(prop->value(), "Exported value must be an asm.js function name.");
1001      }
1002
1003      RECURSE(ExportType(export_obj));
1004    }
1005
1006    return AsmType::Int();
1007  }
1008
1009  FAIL(exports, "Unrecognized expression in asm.js module export expression.");
1010}
1011
1012// 6.3 ValidateFunctionTable
1013AsmType* AsmTyper::ValidateFunctionTable(Assignment* assign) {
1014  if (assign->is_compound()) {
1015    FAIL(assign,
1016         "Compound assignment not supported when declaring global variables.");
1017  }
1018
1019  auto* target = assign->target();
1020  if (!target->IsVariableProxy()) {
1021    FAIL(target, "Module assignments may only assign to globals.");
1022  }
1023  auto* target_variable = target->AsVariableProxy()->var();
1024
1025  auto* value = assign->value()->AsArrayLiteral();
1026  CHECK(value != nullptr);
1027  ZoneList<Expression*>* pointers = value->values();
1028
1029  // The function table size must be n = 2 ** m, for m >= 0;
1030  // TODO(jpp): should this be capped?
1031  if (!base::bits::IsPowerOfTwo32(pointers->length())) {
1032    FAIL(assign, "Invalid length for function pointer table.");
1033  }
1034
1035  AsmType* table_element_type = nullptr;
1036  for (auto* initializer : *pointers) {
1037    auto* var_proxy = initializer->AsVariableProxy();
1038    if (var_proxy == nullptr) {
1039      FAIL(initializer,
1040           "Function pointer table initializer must be a function name.");
1041    }
1042
1043    auto* var_info = Lookup(var_proxy->var());
1044    if (var_info == nullptr) {
1045      FAIL(var_proxy,
1046           "Undefined identifier in function pointer table initializer.");
1047    }
1048
1049    if (var_info->standard_member() != kNone) {
1050      FAIL(initializer,
1051           "Function pointer table must not be a member of the standard "
1052           "library.");
1053    }
1054
1055    auto* initializer_type = var_info->type();
1056    if (initializer_type->AsFunctionType() == nullptr) {
1057      FAIL(initializer,
1058           "Function pointer table initializer must be an asm.js function.");
1059    }
1060
1061    DCHECK(var_info->type()->AsFFIType() == nullptr);
1062    DCHECK(var_info->type()->AsFunctionTableType() == nullptr);
1063
1064    if (table_element_type == nullptr) {
1065      table_element_type = initializer_type;
1066    } else if (!initializer_type->IsA(table_element_type)) {
1067      FAIL(initializer, "Type mismatch in function pointer table initializer.");
1068    }
1069  }
1070
1071  auto* target_info = Lookup(target_variable);
1072  if (target_info == nullptr) {
1073    // Function pointer tables are the last entities to be validates, so this is
1074    // unlikely to happen: only unreferenced function tables will not already
1075    // have an entry in the global scope.
1076    target_info = new (zone_) VariableInfo(AsmType::FunctionTableType(
1077        zone_, pointers->length(), table_element_type));
1078    target_info->set_mutability(VariableInfo::kImmutableGlobal);
1079    if (!ValidAsmIdentifier(target_variable->name())) {
1080      FAIL(target, "Invalid asm.js identifier in function table name.");
1081    }
1082    if (!AddGlobal(target_variable, target_info)) {
1083      DCHECK(false);
1084      FAIL(assign, "Redeclared global identifier in function table name.");
1085    }
1086    SetTypeOf(value, target_info->type());
1087    return target_info->type();
1088  }
1089
1090  auto* target_info_table = target_info->type()->AsFunctionTableType();
1091  if (target_info_table == nullptr) {
1092    FAIL(assign, "Identifier redefined as function pointer table.");
1093  }
1094
1095  if (!target_info->missing_definition()) {
1096    FAIL(assign, "Identifier redefined (function table name).");
1097  }
1098
1099  if (static_cast<int>(target_info_table->length()) != pointers->length()) {
1100    FAIL(assign, "Function table size mismatch.");
1101  }
1102
1103  DCHECK(target_info_table->signature()->AsFunctionType());
1104  if (!table_element_type->IsA(target_info_table->signature())) {
1105    FAIL(assign, "Function table initializer does not match previous type.");
1106  }
1107
1108  target_info->MarkDefined();
1109  DCHECK(target_info->type() != AsmType::None());
1110  SetTypeOf(value, target_info->type());
1111
1112  return target_info->type();
1113}
1114
1115// 6.4 ValidateFunction
1116AsmType* AsmTyper::ValidateFunction(FunctionDeclaration* fun_decl) {
1117  FunctionScope _(this);
1118
1119  // Extract parameter types.
1120  auto* fun = fun_decl->fun();
1121
1122  auto* fun_decl_proxy = fun_decl->proxy();
1123  if (fun_decl_proxy == nullptr) {
1124    FAIL(fun_decl, "Anonymous functions are not support in asm.js.");
1125  }
1126
1127  Statement* current;
1128  FlattenedStatements iter(zone_, fun->body());
1129
1130  size_t annotated_parameters = 0;
1131
1132  // 5.3 Function type annotations
1133  //     * parameters
1134  ZoneVector<AsmType*> parameter_types(zone_);
1135  for (; (current = iter.Next()) != nullptr; ++annotated_parameters) {
1136    auto* stmt = current->AsExpressionStatement();
1137    if (stmt == nullptr) {
1138      // Done with parameters.
1139      break;
1140    }
1141    auto* expr = stmt->expression()->AsAssignment();
1142    if (expr == nullptr || expr->is_compound()) {
1143      // Done with parameters.
1144      break;
1145    }
1146    auto* proxy = expr->target()->AsVariableProxy();
1147    if (proxy == nullptr) {
1148      // Done with parameters.
1149      break;
1150    }
1151    auto* param = proxy->var();
1152    if (param->location() != VariableLocation::PARAMETER ||
1153        param->index() != static_cast<int>(annotated_parameters)) {
1154      // Done with parameters.
1155      break;
1156    }
1157
1158    AsmType* type;
1159    RECURSE(type = ParameterTypeAnnotations(param, expr->value()));
1160    DCHECK(type->IsParameterType());
1161    auto* param_info = new (zone_) VariableInfo(type);
1162    param_info->set_mutability(VariableInfo::kLocal);
1163    if (!ValidAsmIdentifier(proxy->name())) {
1164      FAIL(proxy, "Invalid asm.js identifier in parameter name.");
1165    }
1166
1167    if (!AddLocal(param, param_info)) {
1168      FAIL(proxy, "Redeclared parameter.");
1169    }
1170    parameter_types.push_back(type);
1171    SetTypeOf(proxy, type);
1172    SetTypeOf(expr, type);
1173    SetTypeOf(expr->value(), type);
1174  }
1175
1176  if (static_cast<int>(annotated_parameters) != fun->parameter_count()) {
1177    FAIL(fun_decl, "Incorrect parameter type annotations.");
1178  }
1179
1180  // 5.3 Function type annotations
1181  //     * locals
1182  for (; current; current = iter.Next()) {
1183    auto* initializer = ExtractInitializerExpression(current);
1184    if (initializer == nullptr) {
1185      // Done with locals.
1186      break;
1187    }
1188
1189    auto* local = initializer->target()->AsVariableProxy();
1190    if (local == nullptr) {
1191      // Done with locals. It should never happen. Even if it does, the asm.js
1192      // code should not declare any other locals after this point, so we assume
1193      // this is OK. If any other variable declaration is found we report a
1194      // validation error.
1195      DCHECK(false);
1196      break;
1197    }
1198
1199    AsmType* type;
1200    RECURSE(type = VariableTypeAnnotations(initializer->value()));
1201    auto* local_info = new (zone_) VariableInfo(type);
1202    local_info->set_mutability(VariableInfo::kLocal);
1203    if (!ValidAsmIdentifier(local->name())) {
1204      FAIL(local, "Invalid asm.js identifier in local variable.");
1205    }
1206
1207    if (!AddLocal(local->var(), local_info)) {
1208      FAIL(initializer, "Redeclared local.");
1209    }
1210
1211    SetTypeOf(local, type);
1212    SetTypeOf(initializer, type);
1213  }
1214
1215  // 5.2 Return Type Annotations
1216  // *VIOLATION* we peel blocks to find the last statement in the asm module
1217  // because the parser may introduce synthetic blocks.
1218  ZoneList<Statement*>* statements = fun->body();
1219
1220  do {
1221    if (statements->length() == 0) {
1222      return_type_ = AsmType::Void();
1223    } else {
1224      auto* last_statement = statements->last();
1225      auto* as_block = last_statement->AsBlock();
1226      if (as_block != nullptr) {
1227        statements = as_block->statements();
1228      } else {
1229        if (auto* ret_statement = last_statement->AsReturnStatement()) {
1230          RECURSE(return_type_ =
1231                      ReturnTypeAnnotations(ret_statement->expression()));
1232        } else {
1233          return_type_ = AsmType::Void();
1234        }
1235      }
1236    }
1237  } while (return_type_ == AsmType::None());
1238
1239  DCHECK(return_type_->IsReturnType());
1240
1241  for (Declaration* decl : *fun->scope()->declarations()) {
1242    auto* var_decl = decl->AsVariableDeclaration();
1243    if (var_decl == nullptr) {
1244      FAIL(decl, "Functions may only define inner variables.");
1245    }
1246
1247    auto* var_proxy = var_decl->proxy();
1248    if (var_proxy == nullptr) {
1249      FAIL(decl, "Invalid local declaration declaration.");
1250    }
1251
1252    auto* var_info = Lookup(var_proxy->var());
1253    if (var_info == nullptr || var_info->IsGlobal()) {
1254      FAIL(decl, "Local variable missing initializer in asm.js module.");
1255    }
1256  }
1257
1258  for (; current; current = iter.Next()) {
1259    AsmType* current_type;
1260    RECURSE(current_type = ValidateStatement(current));
1261  }
1262
1263  auto* fun_type = AsmType::Function(zone_, return_type_);
1264  auto* fun_type_as_function = fun_type->AsFunctionType();
1265  for (auto* param_type : parameter_types) {
1266    fun_type_as_function->AddArgument(param_type);
1267  }
1268
1269  auto* fun_var = fun_decl_proxy->var();
1270  auto* fun_info = new (zone_) VariableInfo(fun_type);
1271  fun_info->set_mutability(VariableInfo::kImmutableGlobal);
1272  auto* old_fun_info = Lookup(fun_var);
1273  if (old_fun_info == nullptr) {
1274    if (!ValidAsmIdentifier(fun_var->name())) {
1275      FAIL(fun_decl_proxy, "Invalid asm.js identifier in function name.");
1276    }
1277    if (!AddGlobal(fun_var, fun_info)) {
1278      DCHECK(false);
1279      FAIL(fun_decl, "Redeclared global identifier.");
1280    }
1281
1282    SetTypeOf(fun, fun_type);
1283    return fun_type;
1284  }
1285
1286  // Not necessarily an error -- fun_decl might have been used before being
1287  // defined. If that's the case, then the type in the global environment must
1288  // be the same as the type inferred by the parameter/return type annotations.
1289  auto* old_fun_type = old_fun_info->type();
1290  if (old_fun_type->AsFunctionType() == nullptr) {
1291    FAIL(fun_decl, "Identifier redefined as function.");
1292  }
1293
1294  if (!old_fun_info->missing_definition()) {
1295    FAIL(fun_decl, "Identifier redefined (function name).");
1296  }
1297
1298  if (!fun_type->IsA(old_fun_type)) {
1299    FAIL(fun_decl, "Signature mismatch when defining function.");
1300  }
1301
1302  old_fun_info->MarkDefined();
1303  SetTypeOf(fun, fun_type);
1304
1305  return fun_type;
1306}
1307
1308// 6.5 ValidateStatement
1309AsmType* AsmTyper::ValidateStatement(Statement* statement) {
1310  switch (statement->node_type()) {
1311    default:
1312      FAIL(statement, "Statement type invalid for asm.js.");
1313    case AstNode::kBlock:
1314      return ValidateBlockStatement(statement->AsBlock());
1315    case AstNode::kExpressionStatement:
1316      return ValidateExpressionStatement(statement->AsExpressionStatement());
1317    case AstNode::kEmptyStatement:
1318      return ValidateEmptyStatement(statement->AsEmptyStatement());
1319    case AstNode::kIfStatement:
1320      return ValidateIfStatement(statement->AsIfStatement());
1321    case AstNode::kReturnStatement:
1322      return ValidateReturnStatement(statement->AsReturnStatement());
1323    case AstNode::kWhileStatement:
1324      return ValidateWhileStatement(statement->AsWhileStatement());
1325    case AstNode::kDoWhileStatement:
1326      return ValidateDoWhileStatement(statement->AsDoWhileStatement());
1327    case AstNode::kForStatement:
1328      return ValidateForStatement(statement->AsForStatement());
1329    case AstNode::kBreakStatement:
1330      return ValidateBreakStatement(statement->AsBreakStatement());
1331    case AstNode::kContinueStatement:
1332      return ValidateContinueStatement(statement->AsContinueStatement());
1333    case AstNode::kSwitchStatement:
1334      return ValidateSwitchStatement(statement->AsSwitchStatement());
1335  }
1336
1337  return AsmType::Void();
1338}
1339
1340// 6.5.1 BlockStatement
1341AsmType* AsmTyper::ValidateBlockStatement(Block* block) {
1342  FlattenedStatements iter(zone_, block->statements());
1343
1344  while (auto* current = iter.Next()) {
1345    RECURSE(ValidateStatement(current));
1346  }
1347
1348  return AsmType::Void();
1349}
1350
1351// 6.5.2 ExpressionStatement
1352AsmType* AsmTyper::ValidateExpressionStatement(ExpressionStatement* expr) {
1353  auto* expression = expr->expression();
1354  if (auto* call = expression->AsCall()) {
1355    RECURSE(ValidateCall(AsmType::Void(), call));
1356  } else {
1357    RECURSE(ValidateExpression(expression));
1358  }
1359
1360  return AsmType::Void();
1361}
1362
1363// 6.5.3 EmptyStatement
1364AsmType* AsmTyper::ValidateEmptyStatement(EmptyStatement* empty) {
1365  return AsmType::Void();
1366}
1367
1368// 6.5.4 IfStatement
1369AsmType* AsmTyper::ValidateIfStatement(IfStatement* if_stmt) {
1370  AsmType* cond_type;
1371  RECURSE(cond_type = ValidateExpression(if_stmt->condition()));
1372  if (!cond_type->IsA(AsmType::Int())) {
1373    FAIL(if_stmt->condition(), "If condition must be type int.");
1374  }
1375  RECURSE(ValidateStatement(if_stmt->then_statement()));
1376  RECURSE(ValidateStatement(if_stmt->else_statement()));
1377  return AsmType::Void();
1378}
1379
1380// 6.5.5 ReturnStatement
1381AsmType* AsmTyper::ValidateReturnStatement(ReturnStatement* ret_stmt) {
1382  AsmType* ret_expr_type = AsmType::Void();
1383  if (auto* ret_expr = ret_stmt->expression()) {
1384    RECURSE(ret_expr_type = ValidateExpression(ret_expr));
1385    if (ret_expr_type == AsmType::Void()) {
1386      // *VIOLATION* The parser modifies the source code so that expressionless
1387      // returns will return undefined, so we need to allow that.
1388      if (!ret_expr->IsUndefinedLiteral()) {
1389        FAIL(ret_stmt, "Return statement expression can't be void.");
1390      }
1391    }
1392  }
1393
1394  if (!ret_expr_type->IsA(return_type_)) {
1395    FAIL(ret_stmt, "Type mismatch in return statement.");
1396  }
1397
1398  return ret_expr_type;
1399}
1400
1401// 6.5.6 IterationStatement
1402// 6.5.6.a WhileStatement
1403AsmType* AsmTyper::ValidateWhileStatement(WhileStatement* while_stmt) {
1404  AsmType* cond_type;
1405  RECURSE(cond_type = ValidateExpression(while_stmt->cond()));
1406  if (!cond_type->IsA(AsmType::Int())) {
1407    FAIL(while_stmt->cond(), "While condition must be type int.");
1408  }
1409
1410  if (auto* body = while_stmt->body()) {
1411    RECURSE(ValidateStatement(body));
1412  }
1413  return AsmType::Void();
1414}
1415
1416// 6.5.6.b DoWhileStatement
1417AsmType* AsmTyper::ValidateDoWhileStatement(DoWhileStatement* do_while) {
1418  AsmType* cond_type;
1419  RECURSE(cond_type = ValidateExpression(do_while->cond()));
1420  if (!cond_type->IsA(AsmType::Int())) {
1421    FAIL(do_while->cond(), "Do {} While condition must be type int.");
1422  }
1423
1424  if (auto* body = do_while->body()) {
1425    RECURSE(ValidateStatement(body));
1426  }
1427  return AsmType::Void();
1428}
1429
1430// 6.5.6.c ForStatement
1431AsmType* AsmTyper::ValidateForStatement(ForStatement* for_stmt) {
1432  if (auto* init = for_stmt->init()) {
1433    RECURSE(ValidateStatement(init));
1434  }
1435
1436  if (auto* cond = for_stmt->cond()) {
1437    AsmType* cond_type;
1438    RECURSE(cond_type = ValidateExpression(cond));
1439    if (!cond_type->IsA(AsmType::Int())) {
1440      FAIL(cond, "For condition must be type int.");
1441    }
1442  }
1443
1444  if (auto* next = for_stmt->next()) {
1445    RECURSE(ValidateStatement(next));
1446  }
1447
1448  if (auto* body = for_stmt->body()) {
1449    RECURSE(ValidateStatement(body));
1450  }
1451
1452  return AsmType::Void();
1453}
1454
1455// 6.5.7 BreakStatement
1456AsmType* AsmTyper::ValidateBreakStatement(BreakStatement* brk_stmt) {
1457  return AsmType::Void();
1458}
1459
1460// 6.5.8 ContinueStatement
1461AsmType* AsmTyper::ValidateContinueStatement(ContinueStatement* cont_stmt) {
1462  return AsmType::Void();
1463}
1464
1465// 6.5.9 LabelledStatement
1466// No need to handle these here -- see the AsmTyper's definition.
1467
1468// 6.5.10 SwitchStatement
1469AsmType* AsmTyper::ValidateSwitchStatement(SwitchStatement* stmt) {
1470  AsmType* cond_type;
1471  RECURSE(cond_type = ValidateExpression(stmt->tag()));
1472  if (!cond_type->IsA(AsmType::Signed())) {
1473    FAIL(stmt, "Switch tag must be signed.");
1474  }
1475
1476  int default_pos = kNoSourcePosition;
1477  int last_case_pos = kNoSourcePosition;
1478  ZoneSet<int32_t> cases_seen(zone_);
1479  for (auto* a_case : *stmt->cases()) {
1480    if (a_case->is_default()) {
1481      CHECK(default_pos == kNoSourcePosition);
1482      RECURSE(ValidateDefault(a_case));
1483      default_pos = a_case->position();
1484      continue;
1485    }
1486
1487    if (last_case_pos == kNoSourcePosition) {
1488      last_case_pos = a_case->position();
1489    } else {
1490      last_case_pos = std::max(last_case_pos, a_case->position());
1491    }
1492
1493    int32_t case_lbl;
1494    RECURSE(ValidateCase(a_case, &case_lbl));
1495    auto case_lbl_pos = cases_seen.find(case_lbl);
1496    if (case_lbl_pos != cases_seen.end() && *case_lbl_pos == case_lbl) {
1497      FAIL(a_case, "Duplicated case label.");
1498    }
1499    cases_seen.insert(case_lbl);
1500  }
1501
1502  if (!cases_seen.empty()) {
1503    const int64_t max_lbl = *cases_seen.rbegin();
1504    const int64_t min_lbl = *cases_seen.begin();
1505    if (max_lbl - min_lbl > std::numeric_limits<int32_t>::max()) {
1506      FAIL(stmt, "Out-of-bounds case label range.");
1507    }
1508  }
1509
1510  if (last_case_pos != kNoSourcePosition && default_pos != kNoSourcePosition &&
1511      default_pos < last_case_pos) {
1512    FAIL(stmt, "Switch default must appear last.");
1513  }
1514
1515  return AsmType::Void();
1516}
1517
1518// 6.6 ValidateCase
1519namespace {
1520bool ExtractInt32CaseLabel(CaseClause* clause, int32_t* lbl) {
1521  auto* lbl_expr = clause->label()->AsLiteral();
1522
1523  if (lbl_expr == nullptr) {
1524    return false;
1525  }
1526
1527  if (!IsLiteralInt(lbl_expr)) {
1528    return false;
1529  }
1530
1531  return lbl_expr->value()->ToInt32(lbl);
1532}
1533}  // namespace
1534
1535AsmType* AsmTyper::ValidateCase(CaseClause* label, int32_t* case_lbl) {
1536  if (!ExtractInt32CaseLabel(label, case_lbl)) {
1537    FAIL(label, "Case label must be a 32-bit signed integer.");
1538  }
1539
1540  FlattenedStatements iter(zone_, label->statements());
1541  while (auto* current = iter.Next()) {
1542    RECURSE(ValidateStatement(current));
1543  }
1544  return AsmType::Void();
1545}
1546
1547// 6.7 ValidateDefault
1548AsmType* AsmTyper::ValidateDefault(CaseClause* label) {
1549  FlattenedStatements iter(zone_, label->statements());
1550  while (auto* current = iter.Next()) {
1551    RECURSE(ValidateStatement(current));
1552  }
1553  return AsmType::Void();
1554}
1555
1556// 6.8 ValidateExpression
1557AsmType* AsmTyper::ValidateExpression(Expression* expr) {
1558  AsmType* expr_ty = AsmType::None();
1559
1560  switch (expr->node_type()) {
1561    default:
1562      FAIL(expr, "Invalid asm.js expression.");
1563    case AstNode::kLiteral:
1564      RECURSE(expr_ty = ValidateNumericLiteral(expr->AsLiteral()));
1565      break;
1566    case AstNode::kVariableProxy:
1567      RECURSE(expr_ty = ValidateIdentifier(expr->AsVariableProxy()));
1568      break;
1569    case AstNode::kCall:
1570      RECURSE(expr_ty = ValidateCallExpression(expr->AsCall()));
1571      break;
1572    case AstNode::kProperty:
1573      RECURSE(expr_ty = ValidateMemberExpression(expr->AsProperty()));
1574      break;
1575    case AstNode::kAssignment:
1576      RECURSE(expr_ty = ValidateAssignmentExpression(expr->AsAssignment()));
1577      break;
1578    case AstNode::kUnaryOperation:
1579      RECURSE(expr_ty = ValidateUnaryExpression(expr->AsUnaryOperation()));
1580      break;
1581    case AstNode::kConditional:
1582      RECURSE(expr_ty = ValidateConditionalExpression(expr->AsConditional()));
1583      break;
1584    case AstNode::kCompareOperation:
1585      RECURSE(expr_ty = ValidateCompareOperation(expr->AsCompareOperation()));
1586      break;
1587    case AstNode::kBinaryOperation:
1588      RECURSE(expr_ty = ValidateBinaryOperation(expr->AsBinaryOperation()));
1589      break;
1590  }
1591
1592  SetTypeOf(expr, expr_ty);
1593  return expr_ty;
1594}
1595
1596AsmType* AsmTyper::ValidateCompareOperation(CompareOperation* cmp) {
1597  switch (cmp->op()) {
1598    default:
1599      FAIL(cmp, "Invalid asm.js comparison operator.");
1600    case Token::LT:
1601    case Token::LTE:
1602    case Token::GT:
1603    case Token::GTE:
1604      return ValidateRelationalExpression(cmp);
1605    case Token::EQ:
1606    case Token::NE:
1607      return ValidateEqualityExpression(cmp);
1608  }
1609
1610  UNREACHABLE();
1611}
1612
1613namespace {
1614bool IsInvert(BinaryOperation* binop) {
1615  if (binop->op() != Token::BIT_XOR) {
1616    return false;
1617  }
1618
1619  auto* right_as_literal = binop->right()->AsLiteral();
1620  if (right_as_literal == nullptr) {
1621    return false;
1622  }
1623
1624  return IsLiteralMinus1(right_as_literal);
1625}
1626
1627bool IsUnaryMinus(BinaryOperation* binop) {
1628  // *VIOLATION* The parser replaces uses of -x with x*-1.
1629  if (binop->op() != Token::MUL) {
1630    return false;
1631  }
1632
1633  auto* right_as_literal = binop->right()->AsLiteral();
1634  if (right_as_literal == nullptr) {
1635    return false;
1636  }
1637
1638  return IsLiteralMinus1(right_as_literal);
1639}
1640}  // namespace
1641
1642AsmType* AsmTyper::ValidateBinaryOperation(BinaryOperation* expr) {
1643#define UNOP_OVERLOAD(Src, Dest)          \
1644  do {                                    \
1645    if (left_type->IsA(AsmType::Src())) { \
1646      return AsmType::Dest();             \
1647    }                                     \
1648  } while (0)
1649
1650  switch (expr->op()) {
1651    default:
1652      FAIL(expr, "Invalid asm.js binary expression.");
1653    case Token::COMMA:
1654      return ValidateCommaExpression(expr);
1655    case Token::MUL:
1656      if (IsDoubleAnnotation(expr)) {
1657        // *VIOLATION* We can't be 100% sure this really IS a unary + in the asm
1658        // source so we have to be lenient, and treat this as a unary +.
1659        if (auto* Call = expr->left()->AsCall()) {
1660          return ValidateCall(AsmType::Double(), Call);
1661        }
1662        AsmType* left_type;
1663        RECURSE(left_type = ValidateExpression(expr->left()));
1664        SetTypeOf(expr->right(), AsmType::Double());
1665        UNOP_OVERLOAD(Signed, Double);
1666        UNOP_OVERLOAD(Unsigned, Double);
1667        UNOP_OVERLOAD(DoubleQ, Double);
1668        UNOP_OVERLOAD(FloatQ, Double);
1669        FAIL(expr, "Invalid type for conversion to double.");
1670      }
1671
1672      if (IsUnaryMinus(expr)) {
1673        // *VIOLATION* the parser converts -x to x * -1.
1674        AsmType* left_type;
1675        RECURSE(left_type = ValidateExpression(expr->left()));
1676        SetTypeOf(expr->right(), left_type);
1677        UNOP_OVERLOAD(Int, Intish);
1678        UNOP_OVERLOAD(DoubleQ, Double);
1679        UNOP_OVERLOAD(FloatQ, Floatish);
1680        FAIL(expr, "Invalid type for unary -.");
1681      }
1682    // FALTHROUGH
1683    case Token::DIV:
1684    case Token::MOD:
1685      return ValidateMultiplicativeExpression(expr);
1686    case Token::ADD:
1687    case Token::SUB: {
1688      static const uint32_t kInitialIntishCount = 0;
1689      return ValidateAdditiveExpression(expr, kInitialIntishCount);
1690    }
1691    case Token::SAR:
1692    case Token::SHL:
1693    case Token::SHR:
1694      return ValidateShiftExpression(expr);
1695    case Token::BIT_AND:
1696      return ValidateBitwiseANDExpression(expr);
1697    case Token::BIT_XOR:
1698      if (IsInvert(expr)) {
1699        auto* left = expr->left();
1700        auto* left_as_binop = left->AsBinaryOperation();
1701
1702        if (left_as_binop != nullptr && IsInvert(left_as_binop)) {
1703          // This is the special ~~ operator.
1704          AsmType* left_type;
1705          RECURSE(left_type = ValidateExpression(left_as_binop->left()));
1706          SetTypeOf(left_as_binop->right(), AsmType::FixNum());
1707          SetTypeOf(left_as_binop, AsmType::Signed());
1708          SetTypeOf(expr->right(), AsmType::FixNum());
1709          UNOP_OVERLOAD(Double, Signed);
1710          UNOP_OVERLOAD(FloatQ, Signed);
1711          FAIL(left_as_binop, "Invalid type for conversion to signed.");
1712        }
1713
1714        AsmType* left_type;
1715        RECURSE(left_type = ValidateExpression(left));
1716        UNOP_OVERLOAD(Intish, Signed);
1717        FAIL(left, "Invalid type for ~.");
1718      }
1719
1720      return ValidateBitwiseXORExpression(expr);
1721    case Token::BIT_OR:
1722      return ValidateBitwiseORExpression(expr);
1723  }
1724#undef UNOP_OVERLOAD
1725  UNREACHABLE();
1726}
1727
1728// 6.8.1 Expression
1729AsmType* AsmTyper::ValidateCommaExpression(BinaryOperation* comma) {
1730  // The AST looks like:
1731  // (expr COMMA (expr COMMA (expr COMMA (... ))))
1732
1733  auto* left = comma->left();
1734  if (auto* left_as_call = left->AsCall()) {
1735    RECURSE(ValidateCall(AsmType::Void(), left_as_call));
1736  } else {
1737    RECURSE(ValidateExpression(left));
1738  }
1739
1740  auto* right = comma->right();
1741  AsmType* right_type = nullptr;
1742  if (auto* right_as_call = right->AsCall()) {
1743    RECURSE(right_type = ValidateFloatCoercion(right_as_call));
1744    if (right_type != AsmType::Float()) {
1745      // right_type == nullptr <-> right_as_call is not a call to fround.
1746      DCHECK(right_type == nullptr);
1747      RECURSE(right_type = ValidateCall(AsmType::Void(), right_as_call));
1748      // Unnanotated function call to something that's not fround must be a call
1749      // to a void function.
1750      DCHECK_EQ(right_type, AsmType::Void());
1751    }
1752  } else {
1753    RECURSE(right_type = ValidateExpression(right));
1754  }
1755
1756  return right_type;
1757}
1758
1759// 6.8.2 NumericLiteral
1760AsmType* AsmTyper::ValidateNumericLiteral(Literal* literal) {
1761  // *VIOLATION* asm.js does not allow the use of undefined, but our parser
1762  // inserts them, so we have to handle them.
1763  if (literal->IsUndefinedLiteral()) {
1764    return AsmType::Void();
1765  }
1766
1767  if (IsLiteralDouble(literal)) {
1768    return AsmType::Double();
1769  }
1770
1771  // The parser collapses expressions like !0 and !123 to true/false.
1772  // We therefore need to permit these as alternate versions of 0 / 1.
1773  if (literal->raw_value()->IsTrue() || literal->raw_value()->IsFalse()) {
1774    return AsmType::Int();
1775  }
1776
1777  uint32_t value;
1778  if (!literal->value()->ToUint32(&value)) {
1779    int32_t value;
1780    if (!literal->value()->ToInt32(&value)) {
1781      FAIL(literal, "Integer literal is out of range.");
1782    }
1783    // *VIOLATION* Not really a violation, but rather a difference in
1784    // validation. The spec handles -NumericLiteral in ValidateUnaryExpression,
1785    // but V8's AST represents the negative literals as Literals.
1786    return AsmType::Signed();
1787  }
1788
1789  if (value <= LargestFixNum) {
1790    return AsmType::FixNum();
1791  }
1792
1793  return AsmType::Unsigned();
1794}
1795
1796// 6.8.3 Identifier
1797AsmType* AsmTyper::ValidateIdentifier(VariableProxy* proxy) {
1798  auto* proxy_info = Lookup(proxy->var());
1799  if (proxy_info == nullptr) {
1800    FAIL(proxy, "Undeclared identifier.");
1801  }
1802  auto* type = proxy_info->type();
1803  if (type->IsA(AsmType::None()) || type->AsCallableType() != nullptr) {
1804    FAIL(proxy, "Identifier may not be accessed by ordinary expressions.");
1805  }
1806  return type;
1807}
1808
1809// 6.8.4 CallExpression
1810AsmType* AsmTyper::ValidateCallExpression(Call* call) {
1811  AsmType* return_type;
1812  RECURSE(return_type = ValidateFloatCoercion(call));
1813  if (return_type == nullptr) {
1814    FAIL(call, "Unanotated call to a function must be a call to fround.");
1815  }
1816  return return_type;
1817}
1818
1819// 6.8.5 MemberExpression
1820AsmType* AsmTyper::ValidateMemberExpression(Property* prop) {
1821  AsmType* return_type;
1822  RECURSE(return_type = ValidateHeapAccess(prop, LoadFromHeap));
1823  return return_type;
1824}
1825
1826// 6.8.6 AssignmentExpression
1827AsmType* AsmTyper::ValidateAssignmentExpression(Assignment* assignment) {
1828  AsmType* value_type;
1829  RECURSE(value_type = ValidateExpression(assignment->value()));
1830
1831  if (assignment->op() == Token::INIT) {
1832    FAIL(assignment,
1833         "Local variable declaration must be at the top of the function.");
1834  }
1835
1836  if (auto* target_as_proxy = assignment->target()->AsVariableProxy()) {
1837    auto* var = target_as_proxy->var();
1838    auto* target_info = Lookup(var);
1839
1840    if (target_info == nullptr) {
1841      if (var->mode() != TEMPORARY) {
1842        FAIL(target_as_proxy, "Undeclared identifier.");
1843      }
1844      // Temporary variables are special: we add them to the local symbol table
1845      // as we see them, with the exact type of the variable's initializer. This
1846      // means that temporary variables might have nonsensical types (i.e.,
1847      // intish, float?, fixnum, and not just the "canonical" types.)
1848      auto* var_info = new (zone_) VariableInfo(value_type);
1849      var_info->set_mutability(VariableInfo::kLocal);
1850      if (!ValidAsmIdentifier(target_as_proxy->name())) {
1851        FAIL(target_as_proxy,
1852             "Invalid asm.js identifier in temporary variable.");
1853      }
1854
1855      if (!AddLocal(var, var_info)) {
1856        FAIL(assignment, "Failed to add temporary variable to symbol table.");
1857      }
1858      return value_type;
1859    }
1860
1861    if (!target_info->IsMutable()) {
1862      FAIL(assignment, "Can't assign to immutable symbol.");
1863    }
1864
1865    DCHECK_NE(AsmType::None(), target_info->type());
1866    if (!value_type->IsA(target_info->type())) {
1867      FAIL(assignment, "Type mismatch in assignment.");
1868    }
1869
1870    return value_type;
1871  }
1872
1873  if (auto* target_as_property = assignment->target()->AsProperty()) {
1874    AsmType* allowed_store_types;
1875    RECURSE(allowed_store_types =
1876                ValidateHeapAccess(target_as_property, StoreToHeap));
1877
1878    if (!value_type->IsA(allowed_store_types)) {
1879      FAIL(assignment, "Type mismatch in heap assignment.");
1880    }
1881
1882    return value_type;
1883  }
1884
1885  FAIL(assignment, "Invalid asm.js assignment.");
1886}
1887
1888// 6.8.7 UnaryExpression
1889AsmType* AsmTyper::ValidateUnaryExpression(UnaryOperation* unop) {
1890  // *VIOLATION* -NumericLiteral is validated in ValidateLiteral.
1891  // *VIOLATION* +UnaryExpression is validated in ValidateBinaryOperation.
1892  // *VIOLATION* ~UnaryOperation is validated in ValidateBinaryOperation.
1893  // *VIOLATION* ~~UnaryOperation is validated in ValidateBinaryOperation.
1894  DCHECK(unop->op() != Token::BIT_NOT);
1895  DCHECK(unop->op() != Token::ADD);
1896  AsmType* exp_type;
1897  RECURSE(exp_type = ValidateExpression(unop->expression()));
1898#define UNOP_OVERLOAD(Src, Dest)         \
1899  do {                                   \
1900    if (exp_type->IsA(AsmType::Src())) { \
1901      return AsmType::Dest();            \
1902    }                                    \
1903  } while (0)
1904
1905  // 8.1 Unary Operators
1906  switch (unop->op()) {
1907    default:
1908      FAIL(unop, "Invalid unary operator.");
1909    case Token::ADD:
1910      // We can't test this because of the +x -> x * 1.0 transformation.
1911      DCHECK(false);
1912      UNOP_OVERLOAD(Signed, Double);
1913      UNOP_OVERLOAD(Unsigned, Double);
1914      UNOP_OVERLOAD(DoubleQ, Double);
1915      UNOP_OVERLOAD(FloatQ, Double);
1916      FAIL(unop, "Invalid type for unary +.");
1917    case Token::SUB:
1918      // We can't test this because of the -x -> x * -1.0 transformation.
1919      DCHECK(false);
1920      UNOP_OVERLOAD(Int, Intish);
1921      UNOP_OVERLOAD(DoubleQ, Double);
1922      UNOP_OVERLOAD(FloatQ, Floatish);
1923      FAIL(unop, "Invalid type for unary -.");
1924    case Token::BIT_NOT:
1925      // We can't test this because of the ~x -> x ^ -1 transformation.
1926      DCHECK(false);
1927      UNOP_OVERLOAD(Intish, Signed);
1928      FAIL(unop, "Invalid type for ~.");
1929    case Token::NOT:
1930      UNOP_OVERLOAD(Int, Int);
1931      FAIL(unop, "Invalid type for !.");
1932  }
1933
1934#undef UNOP_OVERLOAD
1935
1936  UNREACHABLE();
1937}
1938
1939// 6.8.8 MultiplicativeExpression
1940namespace {
1941bool IsIntishLiteralFactor(Expression* expr, int32_t* factor) {
1942  auto* literal = expr->AsLiteral();
1943  if (literal == nullptr) {
1944    return false;
1945  }
1946
1947  if (!IsLiteralInt(literal)) {
1948    return false;
1949  }
1950
1951  if (!literal->value()->ToInt32(factor)) {
1952    return false;
1953  }
1954  static const int32_t kIntishBound = 1 << 20;
1955  return -kIntishBound < *factor && *factor < kIntishBound;
1956}
1957}  // namespace
1958
1959AsmType* AsmTyper::ValidateMultiplicativeExpression(BinaryOperation* binop) {
1960  DCHECK(!IsDoubleAnnotation(binop));
1961
1962  auto* left = binop->left();
1963  auto* right = binop->right();
1964
1965  bool intish_mul_failed = false;
1966  if (binop->op() == Token::MUL) {
1967    int32_t factor;
1968    if (IsIntishLiteralFactor(left, &factor)) {
1969      AsmType* right_type;
1970      RECURSE(right_type = ValidateExpression(right));
1971      if (right_type->IsA(AsmType::Int())) {
1972        return AsmType::Intish();
1973      }
1974      // Can't fail here, because the rhs might contain a valid intish factor.
1975      //
1976      // The solution is to flag that there was an error, and later on -- when
1977      // both lhs and rhs are evaluated -- complain.
1978      intish_mul_failed = true;
1979    }
1980
1981    if (IsIntishLiteralFactor(right, &factor)) {
1982      AsmType* left_type;
1983      RECURSE(left_type = ValidateExpression(left));
1984      if (left_type->IsA(AsmType::Int())) {
1985        // *VIOLATION* This will also (and correctly) handle -X, when X is an
1986        // integer. Therefore, we don't need to handle this case within the if
1987        // block below.
1988        return AsmType::Intish();
1989      }
1990      intish_mul_failed = true;
1991
1992      if (factor == -1) {
1993        // *VIOLATION* The frontend transforms -x into x * -1 (not -1.0, because
1994        // consistency is overrated.)
1995        if (left_type->IsA(AsmType::DoubleQ())) {
1996          return AsmType::Double();
1997        } else if (left_type->IsA(AsmType::FloatQ())) {
1998          return AsmType::Floatish();
1999        }
2000      }
2001    }
2002  }
2003
2004  if (intish_mul_failed) {
2005    FAIL(binop, "Invalid types for intish * (or unary -).");
2006  }
2007
2008  AsmType* left_type;
2009  AsmType* right_type;
2010  RECURSE(left_type = ValidateExpression(left));
2011  RECURSE(right_type = ValidateExpression(right));
2012
2013#define BINOP_OVERLOAD(Src0, Src1, Dest)                                       \
2014  do {                                                                         \
2015    if (left_type->IsA(AsmType::Src0()) && right_type->IsA(AsmType::Src1())) { \
2016      return AsmType::Dest();                                                  \
2017    }                                                                          \
2018  } while (0)
2019  switch (binop->op()) {
2020    default:
2021      FAIL(binop, "Invalid multiplicative expression.");
2022    case Token::MUL:
2023      BINOP_OVERLOAD(DoubleQ, DoubleQ, Double);
2024      BINOP_OVERLOAD(FloatQ, FloatQ, Floatish);
2025      FAIL(binop, "Invalid operands for *.");
2026    case Token::DIV:
2027      BINOP_OVERLOAD(Signed, Signed, Intish);
2028      BINOP_OVERLOAD(Unsigned, Unsigned, Intish);
2029      BINOP_OVERLOAD(DoubleQ, DoubleQ, Double);
2030      BINOP_OVERLOAD(FloatQ, FloatQ, Floatish);
2031      FAIL(binop, "Invalid operands for /.");
2032    case Token::MOD:
2033      BINOP_OVERLOAD(Signed, Signed, Intish);
2034      BINOP_OVERLOAD(Unsigned, Unsigned, Intish);
2035      BINOP_OVERLOAD(DoubleQ, DoubleQ, Double);
2036      FAIL(binop, "Invalid operands for %.");
2037  }
2038#undef BINOP_OVERLOAD
2039
2040  UNREACHABLE();
2041}
2042
2043// 6.8.9 AdditiveExpression
2044AsmType* AsmTyper::ValidateAdditiveExpression(BinaryOperation* binop,
2045                                              uint32_t intish_count) {
2046  static const uint32_t kMaxIntish = 1 << 20;
2047
2048  auto* left = binop->left();
2049  auto* left_as_binop = left->AsBinaryOperation();
2050  AsmType* left_type;
2051
2052  // TODO(jpp): maybe use an iterative approach instead of the recursion to
2053  // ValidateAdditiveExpression.
2054  if (left_as_binop != nullptr && (left_as_binop->op() == Token::ADD ||
2055                                   left_as_binop->op() == Token::SUB)) {
2056    RECURSE(left_type =
2057                ValidateAdditiveExpression(left_as_binop, intish_count + 1));
2058    SetTypeOf(left_as_binop, left_type);
2059  } else {
2060    RECURSE(left_type = ValidateExpression(left));
2061  }
2062
2063  auto* right = binop->right();
2064  auto* right_as_binop = right->AsBinaryOperation();
2065  AsmType* right_type;
2066
2067  if (right_as_binop != nullptr && (right_as_binop->op() == Token::ADD ||
2068                                    right_as_binop->op() == Token::SUB)) {
2069    RECURSE(right_type =
2070                ValidateAdditiveExpression(right_as_binop, intish_count + 1));
2071    SetTypeOf(right_as_binop, right_type);
2072  } else {
2073    RECURSE(right_type = ValidateExpression(right));
2074  }
2075
2076  if (left_type->IsA(AsmType::FloatQ()) && right_type->IsA(AsmType::FloatQ())) {
2077    return AsmType::Floatish();
2078  }
2079
2080  if (left_type->IsA(AsmType::Int()) && right_type->IsA(AsmType::Int())) {
2081    if (intish_count == 0) {
2082      return AsmType::Intish();
2083    }
2084    if (intish_count < kMaxIntish) {
2085      return AsmType::Int();
2086    }
2087    FAIL(binop, "Too many uncoerced integer additive expressions.");
2088  }
2089
2090  if (left_type->IsA(AsmType::Double()) && right_type->IsA(AsmType::Double())) {
2091    return AsmType::Double();
2092  }
2093
2094  if (binop->op() == Token::SUB) {
2095    if (left_type->IsA(AsmType::DoubleQ()) &&
2096        right_type->IsA(AsmType::DoubleQ())) {
2097      return AsmType::Double();
2098    }
2099  }
2100
2101  FAIL(binop, "Invalid operands for additive expression.");
2102}
2103
2104// 6.8.10 ShiftExpression
2105AsmType* AsmTyper::ValidateShiftExpression(BinaryOperation* binop) {
2106  auto* left = binop->left();
2107  auto* right = binop->right();
2108
2109  AsmType* left_type;
2110  AsmType* right_type;
2111  RECURSE(left_type = ValidateExpression(left));
2112  RECURSE(right_type = ValidateExpression(right));
2113
2114#define BINOP_OVERLOAD(Src0, Src1, Dest)                                       \
2115  do {                                                                         \
2116    if (left_type->IsA(AsmType::Src0()) && right_type->IsA(AsmType::Src1())) { \
2117      return AsmType::Dest();                                                  \
2118    }                                                                          \
2119  } while (0)
2120  switch (binop->op()) {
2121    default:
2122      FAIL(binop, "Invalid shift expression.");
2123    case Token::SHL:
2124      BINOP_OVERLOAD(Intish, Intish, Signed);
2125      FAIL(binop, "Invalid operands for <<.");
2126    case Token::SAR:
2127      BINOP_OVERLOAD(Intish, Intish, Signed);
2128      FAIL(binop, "Invalid operands for >>.");
2129    case Token::SHR:
2130      BINOP_OVERLOAD(Intish, Intish, Unsigned);
2131      FAIL(binop, "Invalid operands for >>>.");
2132  }
2133#undef BINOP_OVERLOAD
2134
2135  UNREACHABLE();
2136}
2137
2138// 6.8.11 RelationalExpression
2139AsmType* AsmTyper::ValidateRelationalExpression(CompareOperation* cmpop) {
2140  auto* left = cmpop->left();
2141  auto* right = cmpop->right();
2142
2143  AsmType* left_type;
2144  AsmType* right_type;
2145  RECURSE(left_type = ValidateExpression(left));
2146  RECURSE(right_type = ValidateExpression(right));
2147
2148#define CMPOP_OVERLOAD(Src0, Src1, Dest)                                       \
2149  do {                                                                         \
2150    if (left_type->IsA(AsmType::Src0()) && right_type->IsA(AsmType::Src1())) { \
2151      return AsmType::Dest();                                                  \
2152    }                                                                          \
2153  } while (0)
2154  switch (cmpop->op()) {
2155    default:
2156      FAIL(cmpop, "Invalid relational expression.");
2157    case Token::LT:
2158      CMPOP_OVERLOAD(Signed, Signed, Int);
2159      CMPOP_OVERLOAD(Unsigned, Unsigned, Int);
2160      CMPOP_OVERLOAD(Float, Float, Int);
2161      CMPOP_OVERLOAD(Double, Double, Int);
2162      FAIL(cmpop, "Invalid operands for <.");
2163    case Token::GT:
2164      CMPOP_OVERLOAD(Signed, Signed, Int);
2165      CMPOP_OVERLOAD(Unsigned, Unsigned, Int);
2166      CMPOP_OVERLOAD(Float, Float, Int);
2167      CMPOP_OVERLOAD(Double, Double, Int);
2168      FAIL(cmpop, "Invalid operands for >.");
2169    case Token::LTE:
2170      CMPOP_OVERLOAD(Signed, Signed, Int);
2171      CMPOP_OVERLOAD(Unsigned, Unsigned, Int);
2172      CMPOP_OVERLOAD(Float, Float, Int);
2173      CMPOP_OVERLOAD(Double, Double, Int);
2174      FAIL(cmpop, "Invalid operands for <=.");
2175    case Token::GTE:
2176      CMPOP_OVERLOAD(Signed, Signed, Int);
2177      CMPOP_OVERLOAD(Unsigned, Unsigned, Int);
2178      CMPOP_OVERLOAD(Float, Float, Int);
2179      CMPOP_OVERLOAD(Double, Double, Int);
2180      FAIL(cmpop, "Invalid operands for >=.");
2181  }
2182#undef CMPOP_OVERLOAD
2183
2184  UNREACHABLE();
2185}
2186
2187// 6.8.12 EqualityExpression
2188AsmType* AsmTyper::ValidateEqualityExpression(CompareOperation* cmpop) {
2189  auto* left = cmpop->left();
2190  auto* right = cmpop->right();
2191
2192  AsmType* left_type;
2193  AsmType* right_type;
2194  RECURSE(left_type = ValidateExpression(left));
2195  RECURSE(right_type = ValidateExpression(right));
2196
2197#define CMPOP_OVERLOAD(Src0, Src1, Dest)                                       \
2198  do {                                                                         \
2199    if (left_type->IsA(AsmType::Src0()) && right_type->IsA(AsmType::Src1())) { \
2200      return AsmType::Dest();                                                  \
2201    }                                                                          \
2202  } while (0)
2203  switch (cmpop->op()) {
2204    default:
2205      FAIL(cmpop, "Invalid equality expression.");
2206    case Token::EQ:
2207      CMPOP_OVERLOAD(Signed, Signed, Int);
2208      CMPOP_OVERLOAD(Unsigned, Unsigned, Int);
2209      CMPOP_OVERLOAD(Float, Float, Int);
2210      CMPOP_OVERLOAD(Double, Double, Int);
2211      FAIL(cmpop, "Invalid operands for ==.");
2212    case Token::NE:
2213      CMPOP_OVERLOAD(Signed, Signed, Int);
2214      CMPOP_OVERLOAD(Unsigned, Unsigned, Int);
2215      CMPOP_OVERLOAD(Float, Float, Int);
2216      CMPOP_OVERLOAD(Double, Double, Int);
2217      FAIL(cmpop, "Invalid operands for !=.");
2218  }
2219#undef CMPOP_OVERLOAD
2220
2221  UNREACHABLE();
2222}
2223
2224// 6.8.13 BitwiseANDExpression
2225AsmType* AsmTyper::ValidateBitwiseANDExpression(BinaryOperation* binop) {
2226  auto* left = binop->left();
2227  auto* right = binop->right();
2228
2229  AsmType* left_type;
2230  AsmType* right_type;
2231  RECURSE(left_type = ValidateExpression(left));
2232  RECURSE(right_type = ValidateExpression(right));
2233
2234  if (binop->op() != Token::BIT_AND) {
2235    FAIL(binop, "Invalid & expression.");
2236  }
2237
2238#define BINOP_OVERLOAD(Src0, Src1, Dest)                                       \
2239  do {                                                                         \
2240    if (left_type->IsA(AsmType::Src0()) && right_type->IsA(AsmType::Src1())) { \
2241      return AsmType::Dest();                                                  \
2242    }                                                                          \
2243  } while (0)
2244  BINOP_OVERLOAD(Intish, Intish, Signed);
2245  FAIL(binop, "Invalid operands for &.");
2246#undef BINOP_OVERLOAD
2247
2248  UNREACHABLE();
2249}
2250
2251// 6.8.14 BitwiseXORExpression
2252AsmType* AsmTyper::ValidateBitwiseXORExpression(BinaryOperation* binop) {
2253  auto* left = binop->left();
2254  auto* right = binop->right();
2255
2256  AsmType* left_type;
2257  AsmType* right_type;
2258  RECURSE(left_type = ValidateExpression(left));
2259  RECURSE(right_type = ValidateExpression(right));
2260
2261  if (binop->op() != Token::BIT_XOR) {
2262    FAIL(binop, "Invalid ^ expression.");
2263  }
2264
2265#define BINOP_OVERLOAD(Src0, Src1, Dest)                                       \
2266  do {                                                                         \
2267    if (left_type->IsA(AsmType::Src0()) && right_type->IsA(AsmType::Src1())) { \
2268      return AsmType::Dest();                                                  \
2269    }                                                                          \
2270  } while (0)
2271  BINOP_OVERLOAD(Intish, Intish, Signed);
2272  FAIL(binop, "Invalid operands for ^.");
2273#undef BINOP_OVERLOAD
2274
2275  UNREACHABLE();
2276}
2277
2278// 6.8.15 BitwiseORExpression
2279AsmType* AsmTyper::ValidateBitwiseORExpression(BinaryOperation* binop) {
2280  auto* left = binop->left();
2281  if (IsIntAnnotation(binop)) {
2282    if (auto* left_as_call = left->AsCall()) {
2283      AsmType* type;
2284      RECURSE(type = ValidateCall(AsmType::Signed(), left_as_call));
2285      return type;
2286    }
2287    AsmType* left_type;
2288    RECURSE(left_type = ValidateExpression(left));
2289    if (!left_type->IsA(AsmType::Intish())) {
2290      FAIL(left, "Left side of |0 annotation must be intish.");
2291    }
2292    return AsmType::Signed();
2293  }
2294
2295  auto* right = binop->right();
2296  AsmType* left_type;
2297  AsmType* right_type;
2298  RECURSE(left_type = ValidateExpression(left));
2299  RECURSE(right_type = ValidateExpression(right));
2300
2301  if (binop->op() != Token::BIT_OR) {
2302    FAIL(binop, "Invalid | expression.");
2303  }
2304
2305#define BINOP_OVERLOAD(Src0, Src1, Dest)                                       \
2306  do {                                                                         \
2307    if (left_type->IsA(AsmType::Src0()) && right_type->IsA(AsmType::Src1())) { \
2308      return AsmType::Dest();                                                  \
2309    }                                                                          \
2310  } while (0)
2311  BINOP_OVERLOAD(Intish, Intish, Signed);
2312  FAIL(binop, "Invalid operands for |.");
2313#undef BINOP_OVERLOAD
2314
2315  UNREACHABLE();
2316}
2317
2318// 6.8.16 ConditionalExpression
2319AsmType* AsmTyper::ValidateConditionalExpression(Conditional* cond) {
2320  AsmType* cond_type;
2321  RECURSE(cond_type = ValidateExpression(cond->condition()));
2322  if (!cond_type->IsA(AsmType::Int())) {
2323    FAIL(cond, "Ternary operation condition should be int.");
2324  }
2325
2326  AsmType* then_type;
2327  RECURSE(then_type = ValidateExpression(cond->then_expression()));
2328  AsmType* else_type;
2329  RECURSE(else_type = ValidateExpression(cond->else_expression()));
2330
2331#define SUCCEED_IF_BOTH_ARE(type)                                       \
2332  do {                                                                  \
2333    if (then_type->IsA(AsmType::type())) {                              \
2334      if (!else_type->IsA(AsmType::type())) {                           \
2335        FAIL(cond, "Type mismatch for ternary operation result type."); \
2336      }                                                                 \
2337      return AsmType::type();                                           \
2338    }                                                                   \
2339  } while (0)
2340  SUCCEED_IF_BOTH_ARE(Int);
2341  SUCCEED_IF_BOTH_ARE(Float);
2342  SUCCEED_IF_BOTH_ARE(Double);
2343#undef SUCCEED_IF_BOTH_ARE
2344
2345  FAIL(cond, "Ternary operator must return int, float, or double.");
2346}
2347
2348// 6.9 ValidateCall
2349namespace {
2350bool ExtractIndirectCallMask(Expression* expr, uint32_t* value) {
2351  auto* as_literal = expr->AsLiteral();
2352  if (as_literal == nullptr) {
2353    return false;
2354  }
2355
2356  if (!IsLiteralInt(as_literal)) {
2357    return false;
2358  }
2359
2360  if (!as_literal->value()->ToUint32(value)) {
2361    return false;
2362  }
2363
2364  return base::bits::IsPowerOfTwo32(1 + *value);
2365}
2366}  // namespace
2367
2368AsmType* AsmTyper::ValidateCall(AsmType* return_type, Call* call) {
2369  AsmType* float_coercion_type;
2370  RECURSE(float_coercion_type = ValidateFloatCoercion(call));
2371  if (float_coercion_type == AsmType::Float()) {
2372    SetTypeOf(call, AsmType::Float());
2373    return return_type;
2374  }
2375
2376  // TODO(jpp): we should be able to reuse the args vector's storage space.
2377  ZoneVector<AsmType*> args(zone_);
2378  args.reserve(call->arguments()->length());
2379
2380  for (auto* arg : *call->arguments()) {
2381    AsmType* arg_type;
2382    RECURSE(arg_type = ValidateExpression(arg));
2383    args.emplace_back(arg_type);
2384  }
2385
2386  auto* call_expr = call->expression();
2387
2388  // identifier(Expression...)
2389  if (auto* call_var_proxy = call_expr->AsVariableProxy()) {
2390    auto* call_var_info = Lookup(call_var_proxy->var());
2391
2392    if (call_var_info == nullptr) {
2393      // We can't fail here: the validator performs a single pass over the AST,
2394      // so it is possible for some calls to be currently unresolved. We eagerly
2395      // add the function to the table of globals.
2396      auto* call_type = AsmType::Function(zone_, return_type)->AsFunctionType();
2397      for (auto* arg : args) {
2398        call_type->AddArgument(arg->ToParameterType());
2399      }
2400      auto* fun_info =
2401          new (zone_) VariableInfo(reinterpret_cast<AsmType*>(call_type));
2402      fun_info->set_mutability(VariableInfo::kImmutableGlobal);
2403      AddForwardReference(call_var_proxy, fun_info);
2404      if (!ValidAsmIdentifier(call_var_proxy->name())) {
2405        FAIL(call_var_proxy,
2406             "Invalid asm.js identifier in (forward) function name.");
2407      }
2408      if (!AddGlobal(call_var_proxy->var(), fun_info)) {
2409        DCHECK(false);
2410        FAIL(call, "Redeclared global identifier.");
2411      }
2412      if (call->GetCallType() != Call::OTHER_CALL) {
2413        FAIL(call, "Invalid call of existing global function.");
2414      }
2415      SetTypeOf(call_var_proxy, reinterpret_cast<AsmType*>(call_type));
2416      SetTypeOf(call, return_type);
2417      return return_type;
2418    }
2419
2420    auto* callee_type = call_var_info->type()->AsCallableType();
2421    if (callee_type == nullptr) {
2422      FAIL(call, "Calling something that's not a function.");
2423    }
2424
2425    if (callee_type->AsFFIType() != nullptr) {
2426      if (return_type == AsmType::Float()) {
2427        FAIL(call, "Foreign functions can't return float.");
2428      }
2429      // Record FFI use signature, since the asm->wasm translator must know
2430      // all uses up-front.
2431      ffi_use_signatures_.emplace_back(
2432          FFIUseSignature(call_var_proxy->var(), zone_));
2433      FFIUseSignature* sig = &ffi_use_signatures_.back();
2434      sig->return_type_ = return_type;
2435      sig->arg_types_.reserve(args.size());
2436      for (size_t i = 0; i < args.size(); ++i) {
2437        sig->arg_types_.emplace_back(args[i]);
2438      }
2439    }
2440
2441    if (!callee_type->CanBeInvokedWith(return_type, args)) {
2442      FAIL(call, "Function invocation does not match function type.");
2443    }
2444
2445    if (call->GetCallType() != Call::OTHER_CALL) {
2446      FAIL(call, "Invalid forward call of global function.");
2447    }
2448
2449    SetTypeOf(call_var_proxy, call_var_info->type());
2450    SetTypeOf(call, return_type);
2451    return return_type;
2452  }
2453
2454  // identifier[expr & n](Expression...)
2455  if (auto* call_property = call_expr->AsProperty()) {
2456    auto* index = call_property->key()->AsBinaryOperation();
2457    if (index == nullptr || index->op() != Token::BIT_AND) {
2458      FAIL(call_property->key(),
2459           "Indirect call index must be in the expr & mask form.");
2460    }
2461
2462    auto* left = index->left();
2463    auto* right = index->right();
2464    uint32_t mask;
2465    if (!ExtractIndirectCallMask(right, &mask)) {
2466      if (!ExtractIndirectCallMask(left, &mask)) {
2467        FAIL(right, "Invalid indirect call mask.");
2468      } else {
2469        left = right;
2470      }
2471    }
2472    const uint32_t table_length = mask + 1;
2473
2474    AsmType* left_type;
2475    RECURSE(left_type = ValidateExpression(left));
2476    if (!left_type->IsA(AsmType::Intish())) {
2477      FAIL(left, "Indirect call index should be an intish.");
2478    }
2479
2480    auto* name_var = call_property->obj()->AsVariableProxy();
2481
2482    if (name_var == nullptr) {
2483      FAIL(call_property, "Invalid call.");
2484    }
2485
2486    auto* name_info = Lookup(name_var->var());
2487    if (name_info == nullptr) {
2488      // We can't fail here -- just like above.
2489      auto* call_type = AsmType::Function(zone_, return_type)->AsFunctionType();
2490      for (auto* arg : args) {
2491        call_type->AddArgument(arg->ToParameterType());
2492      }
2493      auto* table_type = AsmType::FunctionTableType(
2494          zone_, table_length, reinterpret_cast<AsmType*>(call_type));
2495      auto* fun_info =
2496          new (zone_) VariableInfo(reinterpret_cast<AsmType*>(table_type));
2497      fun_info->set_mutability(VariableInfo::kImmutableGlobal);
2498      AddForwardReference(name_var, fun_info);
2499      if (!ValidAsmIdentifier(name_var->name())) {
2500        FAIL(name_var,
2501             "Invalid asm.js identifier in (forward) function table name.");
2502      }
2503      if (!AddGlobal(name_var->var(), fun_info)) {
2504        DCHECK(false);
2505        FAIL(call, "Redeclared global identifier.");
2506      }
2507      if (call->GetCallType() != Call::KEYED_PROPERTY_CALL) {
2508        FAIL(call, "Invalid call of existing function table.");
2509      }
2510      SetTypeOf(call_property, reinterpret_cast<AsmType*>(call_type));
2511      SetTypeOf(call, return_type);
2512      return return_type;
2513    }
2514
2515    auto* previous_type = name_info->type()->AsFunctionTableType();
2516    if (previous_type == nullptr) {
2517      FAIL(call, "Identifier does not name a function table.");
2518    }
2519
2520    if (table_length != previous_type->length()) {
2521      FAIL(call, "Function table size does not match expected size.");
2522    }
2523
2524    auto* previous_type_signature =
2525        previous_type->signature()->AsFunctionType();
2526    DCHECK(previous_type_signature != nullptr);
2527    if (!previous_type_signature->CanBeInvokedWith(return_type, args)) {
2528      // TODO(jpp): better error messages.
2529      FAIL(call,
2530           "Function pointer table signature does not match previous "
2531           "signature.");
2532    }
2533
2534    if (call->GetCallType() != Call::KEYED_PROPERTY_CALL) {
2535      FAIL(call, "Invalid forward call of function table.");
2536    }
2537    SetTypeOf(call_property, previous_type->signature());
2538    SetTypeOf(call, return_type);
2539    return return_type;
2540  }
2541
2542  FAIL(call, "Invalid call.");
2543}
2544
2545// 6.10 ValidateHeapAccess
2546namespace {
2547bool ExtractHeapAccessShift(Expression* expr, uint32_t* value) {
2548  auto* as_literal = expr->AsLiteral();
2549  if (as_literal == nullptr) {
2550    return false;
2551  }
2552
2553  if (!IsLiteralInt(as_literal)) {
2554    return false;
2555  }
2556
2557  return as_literal->value()->ToUint32(value);
2558}
2559
2560// Returns whether index is too large to access a heap with the given type.
2561bool LiteralIndexOutOfBounds(AsmType* obj_type, uint32_t index) {
2562  switch (obj_type->ElementSizeInBytes()) {
2563    case 1:
2564      return false;
2565    case 2:
2566      return (index & 0x80000000u) != 0;
2567    case 4:
2568      return (index & 0xC0000000u) != 0;
2569    case 8:
2570      return (index & 0xE0000000u) != 0;
2571  }
2572  UNREACHABLE();
2573  return true;
2574}
2575
2576}  // namespace
2577
2578AsmType* AsmTyper::ValidateHeapAccess(Property* heap,
2579                                      HeapAccessType access_type) {
2580  auto* obj = heap->obj()->AsVariableProxy();
2581  if (obj == nullptr) {
2582    FAIL(heap, "Invalid heap access.");
2583  }
2584
2585  auto* obj_info = Lookup(obj->var());
2586  if (obj_info == nullptr) {
2587    FAIL(heap, "Undeclared identifier in heap access.");
2588  }
2589
2590  auto* obj_type = obj_info->type();
2591  if (!obj_type->IsA(AsmType::Heap())) {
2592    FAIL(heap, "Identifier does not represent a heap view.");
2593  }
2594  SetTypeOf(obj, obj_type);
2595
2596  if (auto* key_as_literal = heap->key()->AsLiteral()) {
2597    if (!IsLiteralInt(key_as_literal)) {
2598      FAIL(key_as_literal, "Heap access index must be int.");
2599    }
2600
2601    uint32_t index;
2602    if (!key_as_literal->value()->ToUint32(&index)) {
2603      FAIL(key_as_literal,
2604           "Heap access index must be a 32-bit unsigned integer.");
2605    }
2606
2607    if (LiteralIndexOutOfBounds(obj_type, index)) {
2608      FAIL(key_as_literal, "Heap access index is out of bounds");
2609    }
2610
2611    if (access_type == LoadFromHeap) {
2612      return obj_type->LoadType();
2613    }
2614    return obj_type->StoreType();
2615  }
2616
2617  if (auto* key_as_binop = heap->key()->AsBinaryOperation()) {
2618    uint32_t shift;
2619    if (key_as_binop->op() == Token::SAR &&
2620        ExtractHeapAccessShift(key_as_binop->right(), &shift) &&
2621        (1 << shift) == obj_type->ElementSizeInBytes()) {
2622      AsmType* type;
2623      RECURSE(type = ValidateExpression(key_as_binop->left()));
2624      if (type->IsA(AsmType::Intish())) {
2625        if (access_type == LoadFromHeap) {
2626          return obj_type->LoadType();
2627        }
2628        return obj_type->StoreType();
2629      }
2630      FAIL(key_as_binop, "Invalid heap access index.");
2631    }
2632  }
2633
2634  if (obj_type->ElementSizeInBytes() == 1) {
2635    // Leniency: if this is a byte array, we don't require the shift operation
2636    // to be present.
2637    AsmType* index_type;
2638    RECURSE(index_type = ValidateExpression(heap->key()));
2639    if (!index_type->IsA(AsmType::Int())) {
2640      FAIL(heap, "Invalid heap access index for byte array.");
2641    }
2642    if (access_type == LoadFromHeap) {
2643      return obj_type->LoadType();
2644    }
2645    return obj_type->StoreType();
2646  }
2647
2648  FAIL(heap, "Invalid heap access index.");
2649}
2650
2651// 6.11 ValidateFloatCoercion
2652bool AsmTyper::IsCallToFround(Call* call) {
2653  if (call->arguments()->length() != 1) {
2654    return false;
2655  }
2656
2657  auto* call_var_proxy = call->expression()->AsVariableProxy();
2658  if (call_var_proxy == nullptr) {
2659    return false;
2660  }
2661
2662  auto* call_var_info = Lookup(call_var_proxy->var());
2663  if (call_var_info == nullptr) {
2664    return false;
2665  }
2666
2667  return call_var_info->standard_member() == kMathFround;
2668}
2669
2670AsmType* AsmTyper::ValidateFloatCoercion(Call* call) {
2671  if (!IsCallToFround(call)) {
2672    return nullptr;
2673  }
2674
2675  auto* arg = call->arguments()->at(0);
2676  // call is a fround() node. From now, there can be two possible outcomes:
2677  // 1. fround is used as a return type annotation.
2678  if (auto* arg_as_call = arg->AsCall()) {
2679    RECURSE(ValidateCall(AsmType::Float(), arg_as_call));
2680    return AsmType::Float();
2681  }
2682
2683  // 2. fround is used for converting to float.
2684  AsmType* arg_type;
2685  RECURSE(arg_type = ValidateExpression(arg));
2686  if (arg_type->IsA(AsmType::Floatish()) || arg_type->IsA(AsmType::DoubleQ()) ||
2687      arg_type->IsA(AsmType::Signed()) || arg_type->IsA(AsmType::Unsigned())) {
2688    SetTypeOf(call->expression(), fround_type_);
2689    return AsmType::Float();
2690  }
2691
2692  FAIL(call, "Invalid argument type to fround.");
2693}
2694
2695// 5.1 ParameterTypeAnnotations
2696AsmType* AsmTyper::ParameterTypeAnnotations(Variable* parameter,
2697                                            Expression* annotation) {
2698  if (auto* binop = annotation->AsBinaryOperation()) {
2699    // Must be:
2700    //   * x|0
2701    //   * x*1 (*VIOLATION* i.e.,, +x)
2702    auto* left = binop->left()->AsVariableProxy();
2703    if (left == nullptr) {
2704      FAIL(
2705          binop->left(),
2706          "Invalid parameter type annotation - should annotate an identifier.");
2707    }
2708    if (left->var() != parameter) {
2709      FAIL(binop->left(),
2710           "Invalid parameter type annotation - should annotate a parameter.");
2711    }
2712    if (IsDoubleAnnotation(binop)) {
2713      SetTypeOf(left, AsmType::Double());
2714      return AsmType::Double();
2715    }
2716    if (IsIntAnnotation(binop)) {
2717      SetTypeOf(left, AsmType::Int());
2718      return AsmType::Int();
2719    }
2720    FAIL(binop, "Invalid parameter type annotation.");
2721  }
2722
2723  auto* call = annotation->AsCall();
2724  if (call == nullptr) {
2725    FAIL(
2726        annotation,
2727        "Invalid float parameter type annotation - must be fround(parameter).");
2728  }
2729
2730  if (!IsCallToFround(call)) {
2731    FAIL(annotation,
2732         "Invalid float parameter type annotation - must be call to fround.");
2733  }
2734
2735  auto* src_expr = call->arguments()->at(0)->AsVariableProxy();
2736  if (src_expr == nullptr) {
2737    FAIL(annotation,
2738         "Invalid float parameter type annotation - argument to fround is not "
2739         "an identifier.");
2740  }
2741
2742  if (src_expr->var() != parameter) {
2743    FAIL(annotation,
2744         "Invalid float parameter type annotation - argument to fround is not "
2745         "a parameter.");
2746  }
2747
2748  SetTypeOf(src_expr, AsmType::Float());
2749  return AsmType::Float();
2750}
2751
2752// 5.2 ReturnTypeAnnotations
2753AsmType* AsmTyper::ReturnTypeAnnotations(Expression* ret_expr) {
2754  DCHECK_NOT_NULL(ret_expr);
2755
2756  if (auto* binop = ret_expr->AsBinaryOperation()) {
2757    if (IsDoubleAnnotation(binop)) {
2758      return AsmType::Double();
2759    } else if (IsIntAnnotation(binop)) {
2760      return AsmType::Signed();
2761    }
2762    FAIL(ret_expr, "Invalid return type annotation.");
2763  }
2764
2765  if (auto* call = ret_expr->AsCall()) {
2766    if (IsCallToFround(call)) {
2767      return AsmType::Float();
2768    }
2769    FAIL(ret_expr, "Invalid function call in return statement.");
2770  }
2771
2772  if (auto* literal = ret_expr->AsLiteral()) {
2773    int32_t _;
2774    if (IsLiteralDouble(literal)) {
2775      return AsmType::Double();
2776    } else if (IsLiteralInt(literal) && literal->value()->ToInt32(&_)) {
2777      return AsmType::Signed();
2778    } else if (literal->IsUndefinedLiteral()) {
2779      // *VIOLATION* The parser changes
2780      //
2781      // return;
2782      //
2783      // into
2784      //
2785      // return undefined
2786      return AsmType::Void();
2787    }
2788    FAIL(ret_expr, "Invalid literal in return statement.");
2789  }
2790
2791  if (auto* proxy = ret_expr->AsVariableProxy()) {
2792    auto* var_info = Lookup(proxy->var());
2793
2794    if (var_info == nullptr) {
2795      FAIL(ret_expr, "Undeclared identifier in return statement.");
2796    }
2797
2798    if (var_info->mutability() != VariableInfo::kConstGlobal) {
2799      FAIL(ret_expr, "Identifier in return statement is not const.");
2800    }
2801
2802    if (!var_info->type()->IsReturnType()) {
2803      FAIL(ret_expr, "Constant in return must be signed, float, or double.");
2804    }
2805
2806    return var_info->type();
2807  }
2808
2809  // NOTE: This is not strictly valid asm.js, but is emitted by some versions of
2810  // Emscripten.
2811  if (auto* cond = ret_expr->AsConditional()) {
2812    AsmType* a = AsmType::None();
2813    AsmType* b = AsmType::None();
2814    RECURSE(a = ReturnTypeAnnotations(cond->then_expression()));
2815    if (a->IsA(AsmType::None())) {
2816      return a;
2817    }
2818    RECURSE(b = ReturnTypeAnnotations(cond->else_expression()));
2819    if (b->IsA(AsmType::None())) {
2820      return b;
2821    }
2822    if (a->IsExactly(b)) {
2823      return a;
2824    }
2825  }
2826
2827  FAIL(ret_expr, "Invalid return type expression.");
2828}
2829
2830// 5.4 VariableTypeAnnotations
2831// Also used for 5.5 GlobalVariableTypeAnnotations
2832AsmType* AsmTyper::VariableTypeAnnotations(
2833    Expression* initializer, VariableInfo::Mutability mutability_type) {
2834  if (auto* literal = initializer->AsLiteral()) {
2835    if (IsLiteralDouble(literal)) {
2836      SetTypeOf(initializer, AsmType::Double());
2837      return AsmType::Double();
2838    }
2839    if (!IsLiteralInt(literal)) {
2840      FAIL(initializer, "Invalid type annotation - forbidden literal.");
2841    }
2842    int32_t i32;
2843    uint32_t u32;
2844    AsmType* initializer_type = nullptr;
2845    if (literal->value()->ToUint32(&u32)) {
2846      if (u32 > LargestFixNum) {
2847        initializer_type = AsmType::Unsigned();
2848        SetTypeOf(initializer, initializer_type);
2849      } else {
2850        initializer_type = AsmType::FixNum();
2851        SetTypeOf(initializer, initializer_type);
2852        initializer_type = AsmType::Signed();
2853      }
2854    } else if (literal->value()->ToInt32(&i32)) {
2855      initializer_type = AsmType::Signed();
2856      SetTypeOf(initializer, initializer_type);
2857    } else {
2858      FAIL(initializer, "Invalid type annotation - forbidden literal.");
2859    }
2860    if (mutability_type != VariableInfo::kConstGlobal) {
2861      return AsmType::Int();
2862    }
2863    return initializer_type;
2864  }
2865
2866  if (auto* proxy = initializer->AsVariableProxy()) {
2867    auto* var_info = Lookup(proxy->var());
2868
2869    if (var_info == nullptr) {
2870      FAIL(initializer,
2871           "Undeclared identifier in variable declaration initializer.");
2872    }
2873
2874    if (var_info->mutability() != VariableInfo::kConstGlobal) {
2875      FAIL(initializer,
2876           "Identifier in variable declaration initializer must be const.");
2877    }
2878
2879    SetTypeOf(initializer, var_info->type());
2880    return var_info->type();
2881  }
2882
2883  auto* call = initializer->AsCall();
2884  if (call == nullptr) {
2885    FAIL(initializer,
2886         "Invalid variable initialization - it should be a literal, const, or "
2887         "fround(literal).");
2888  }
2889
2890  if (!IsCallToFround(call)) {
2891    FAIL(initializer,
2892         "Invalid float coercion - expected call fround(literal).");
2893  }
2894
2895  auto* src_expr = call->arguments()->at(0)->AsLiteral();
2896  if (src_expr == nullptr) {
2897    FAIL(initializer,
2898         "Invalid float type annotation - expected literal argument for call "
2899         "to fround.");
2900  }
2901
2902  // ERRATA: 5.4
2903  // According to the spec: float constants must contain dots in local,
2904  // but not in globals.
2905  // However, the errata doc (and actual programs), use integer values
2906  // with fround(..).
2907  // Skipping the check that would go here to enforce this.
2908  // Checking instead the literal expression is at least a number.
2909  if (!src_expr->raw_value()->IsNumber()) {
2910    FAIL(initializer,
2911         "Invalid float type annotation - expected numeric literal for call "
2912         "to fround.");
2913  }
2914
2915  return AsmType::Float();
2916}
2917
2918// 5.5 GlobalVariableTypeAnnotations
2919AsmType* AsmTyper::NewHeapView(CallNew* new_heap_view) {
2920  auto* heap_type = new_heap_view->expression()->AsProperty();
2921  if (heap_type == nullptr) {
2922    FAIL(new_heap_view, "Invalid type after new.");
2923  }
2924  auto* heap_view_info = ImportLookup(heap_type);
2925
2926  if (heap_view_info == nullptr) {
2927    FAIL(new_heap_view, "Unknown stdlib member in heap view declaration.");
2928  }
2929
2930  if (!heap_view_info->type()->IsA(AsmType::Heap())) {
2931    FAIL(new_heap_view, "Type is not a heap view type.");
2932  }
2933
2934  if (new_heap_view->arguments()->length() != 1) {
2935    FAIL(new_heap_view, "Invalid number of arguments when creating heap view.");
2936  }
2937
2938  auto* heap = new_heap_view->arguments()->at(0);
2939  auto* heap_var_proxy = heap->AsVariableProxy();
2940
2941  if (heap_var_proxy == nullptr) {
2942    FAIL(heap,
2943         "Heap view creation parameter should be the module's heap parameter.");
2944  }
2945
2946  auto* heap_var_info = Lookup(heap_var_proxy->var());
2947
2948  if (heap_var_info == nullptr) {
2949    FAIL(heap, "Undeclared identifier instead of heap parameter.");
2950  }
2951
2952  if (!heap_var_info->IsHeap()) {
2953    FAIL(heap,
2954         "Heap view creation parameter should be the module's heap parameter.");
2955  }
2956
2957  DCHECK(heap_view_info->type()->IsA(AsmType::Heap()));
2958  return heap_view_info->type();
2959}
2960
2961}  // namespace wasm
2962}  // namespace internal
2963}  // namespace v8
2964