• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
66 namespace v8 {
67 namespace internal {
68 namespace wasm {
69 namespace {
70 static const uint32_t LargestFixNum = std::numeric_limits<int32_t>::max();
71 }  // namespace
72 
73 using v8::internal::AstNode;
74 using v8::internal::GetCurrentStackPosition;
75 
76 // ----------------------------------------------------------------------------
77 // Implementation of AsmTyper::FlattenedStatements
78 
FlattenedStatements(Zone * zone,ZoneList<Statement * > * s)79 AsmTyper::FlattenedStatements::FlattenedStatements(Zone* zone,
80                                                    ZoneList<Statement*>* s)
81     : context_stack_(zone) {
82   context_stack_.emplace_back(Context(s));
83 }
84 
Next()85 Statement* 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 
IsValid() const113 bool 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 
AddNewElement(const AstNode & node)127 void 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 
IsPrecededBy(const Section & other) const142 bool 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 
ForSpecialSymbol(Zone * zone,StandardMember standard_member)160 AsmTyper::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 
Clone(Zone * zone) const170 AsmTyper::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 
SetFirstForwardUse(const MessageLocation & source_location)179 void 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 
AsmTyper(Isolate * isolate,Zone * zone,Handle<Script> script,FunctionLiteral * root)188 AsmTyper::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 
210 namespace {
ValidAsmIdentifier(Handle<String> name)211 bool 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 
InitializeStdlib()223 void 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
ImportLookup(Property * import)347 AsmTyper::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 
Lookup(Variable * variable) const402 AsmTyper::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 
AddForwardReference(VariableProxy * proxy,VariableInfo * info)418 void 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 
AddGlobal(Variable * variable,VariableInfo * info)424 bool 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 
AddLocal(Variable * variable,VariableInfo * info)446 bool 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 
SetTypeOf(AstNode * node,AsmType * type)463 void 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 
474 namespace {
IsLiteralDouble(Literal * literal)475 bool IsLiteralDouble(Literal* literal) {
476   return literal->raw_value()->IsNumber() &&
477          literal->raw_value()->ContainsDot();
478 }
479 
IsLiteralInt(Literal * literal)480 bool IsLiteralInt(Literal* literal) {
481   return literal->raw_value()->IsNumber() &&
482          !literal->raw_value()->ContainsDot();
483 }
484 
IsLiteralMinus1(Literal * literal)485 bool IsLiteralMinus1(Literal* literal) {
486   return IsLiteralInt(literal) && literal->raw_value()->AsNumber() == -1.0;
487 }
488 
IsLiteral1Dot0(Literal * literal)489 bool IsLiteral1Dot0(Literal* literal) {
490   return IsLiteralDouble(literal) && literal->raw_value()->AsNumber() == 1.0;
491 }
492 
IsLiteral0(Literal * literal)493 bool IsLiteral0(Literal* literal) {
494   return IsLiteralInt(literal) && literal->raw_value()->AsNumber() == 0.0;
495 }
496 }  // namespace
497 
TypeOf(AstNode * node) const498 AsmType* 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 
TypeOf(Variable * v) const533 AsmType* AsmTyper::TypeOf(Variable* v) const { return Lookup(v)->type(); }
534 
VariableAsStandardMember(Variable * var)535 AsmTyper::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 
FailWithMessage(const char * text)544 AsmType* AsmTyper::FailWithMessage(const char* text) {
545   FAIL_RAW(root_, OneByteVector(text));
546 }
547 
Validate()548 bool AsmTyper::Validate() {
549   return ValidateBeforeFunctionsPhase() &&
550          !AsmType::None()->IsExactly(ValidateModuleFunctions(root_)) &&
551          ValidateAfterFunctionsPhase();
552 }
553 
ValidateBeforeFunctionsPhase()554 bool AsmTyper::ValidateBeforeFunctionsPhase() {
555   if (!AsmType::None()->IsExactly(ValidateModuleBeforeFunctionsPhase(root_))) {
556     return true;
557   }
558   return false;
559 }
560 
ValidateInnerFunction(FunctionDeclaration * fun_decl)561 bool AsmTyper::ValidateInnerFunction(FunctionDeclaration* fun_decl) {
562   if (!AsmType::None()->IsExactly(ValidateModuleFunction(fun_decl))) {
563     return true;
564   }
565   return false;
566 }
567 
ValidateAfterFunctionsPhase()568 bool AsmTyper::ValidateAfterFunctionsPhase() {
569   if (!AsmType::None()->IsExactly(ValidateModuleAfterFunctionsPhase(root_))) {
570     return true;
571   }
572   return false;
573 }
574 
ClearFunctionNodeTypes()575 void AsmTyper::ClearFunctionNodeTypes() { function_node_types_.clear(); }
576 
TriggerParsingError()577 AsmType* AsmTyper::TriggerParsingError() { FAIL(root_, "Parsing error"); }
578 
579 namespace {
IsUseAsmDirective(Statement * first_statement)580 bool 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 
ExtractInitializerExpression(Statement * statement)595 Assignment* 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
ValidateModuleBeforeFunctionsPhase(FunctionLiteral * fun)616 AsmType* 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 
ValidateModuleFunction(FunctionDeclaration * fun_decl)709 AsmType* 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 
ValidateModuleFunctions(FunctionLiteral * fun)716 AsmType* 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 
ValidateModuleAfterFunctionsPhase(FunctionLiteral * fun)729 AsmType* 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 
778 namespace {
IsDoubleAnnotation(BinaryOperation * binop)779 bool 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 
IsIntAnnotation(BinaryOperation * binop)793 bool 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 
ValidateGlobalDeclaration(Assignment * assign)807 AsmType* 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
ExportType(VariableProxy * fun_export)945 AsmType* 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 
ValidateExport(ReturnStatement * exports)975 AsmType* 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
ValidateFunctionTable(Assignment * assign)1013 AsmType* 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
ValidateFunction(FunctionDeclaration * fun_decl)1116 AsmType* 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
ValidateStatement(Statement * statement)1309 AsmType* 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
ValidateBlockStatement(Block * block)1341 AsmType* 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
ValidateExpressionStatement(ExpressionStatement * expr)1352 AsmType* 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
ValidateEmptyStatement(EmptyStatement * empty)1364 AsmType* AsmTyper::ValidateEmptyStatement(EmptyStatement* empty) {
1365   return AsmType::Void();
1366 }
1367 
1368 // 6.5.4 IfStatement
ValidateIfStatement(IfStatement * if_stmt)1369 AsmType* 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
ValidateReturnStatement(ReturnStatement * ret_stmt)1381 AsmType* 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
ValidateWhileStatement(WhileStatement * while_stmt)1403 AsmType* 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
ValidateDoWhileStatement(DoWhileStatement * do_while)1417 AsmType* 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
ValidateForStatement(ForStatement * for_stmt)1431 AsmType* 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
ValidateBreakStatement(BreakStatement * brk_stmt)1456 AsmType* AsmTyper::ValidateBreakStatement(BreakStatement* brk_stmt) {
1457   return AsmType::Void();
1458 }
1459 
1460 // 6.5.8 ContinueStatement
ValidateContinueStatement(ContinueStatement * cont_stmt)1461 AsmType* 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
ValidateSwitchStatement(SwitchStatement * stmt)1469 AsmType* 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
1519 namespace {
ExtractInt32CaseLabel(CaseClause * clause,int32_t * lbl)1520 bool 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 
ValidateCase(CaseClause * label,int32_t * case_lbl)1535 AsmType* 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
ValidateDefault(CaseClause * label)1548 AsmType* 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
ValidateExpression(Expression * expr)1557 AsmType* 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 
ValidateCompareOperation(CompareOperation * cmp)1596 AsmType* 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 
1613 namespace {
IsInvert(BinaryOperation * binop)1614 bool 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 
IsUnaryMinus(BinaryOperation * binop)1627 bool 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 
ValidateBinaryOperation(BinaryOperation * expr)1642 AsmType* 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
ValidateCommaExpression(BinaryOperation * comma)1729 AsmType* 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
ValidateNumericLiteral(Literal * literal)1760 AsmType* 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
ValidateIdentifier(VariableProxy * proxy)1797 AsmType* 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
ValidateCallExpression(Call * call)1810 AsmType* 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
ValidateMemberExpression(Property * prop)1820 AsmType* 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
ValidateAssignmentExpression(Assignment * assignment)1827 AsmType* 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
ValidateUnaryExpression(UnaryOperation * unop)1889 AsmType* 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
1940 namespace {
IsIntishLiteralFactor(Expression * expr,int32_t * factor)1941 bool 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 
ValidateMultiplicativeExpression(BinaryOperation * binop)1959 AsmType* 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
ValidateAdditiveExpression(BinaryOperation * binop,uint32_t intish_count)2044 AsmType* 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
ValidateShiftExpression(BinaryOperation * binop)2105 AsmType* 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
ValidateRelationalExpression(CompareOperation * cmpop)2139 AsmType* 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
ValidateEqualityExpression(CompareOperation * cmpop)2188 AsmType* 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
ValidateBitwiseANDExpression(BinaryOperation * binop)2225 AsmType* 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
ValidateBitwiseXORExpression(BinaryOperation * binop)2252 AsmType* 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
ValidateBitwiseORExpression(BinaryOperation * binop)2279 AsmType* 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
ValidateConditionalExpression(Conditional * cond)2319 AsmType* 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
2349 namespace {
ExtractIndirectCallMask(Expression * expr,uint32_t * value)2350 bool 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 
ValidateCall(AsmType * return_type,Call * call)2368 AsmType* 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
2546 namespace {
ExtractHeapAccessShift(Expression * expr,uint32_t * value)2547 bool 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.
LiteralIndexOutOfBounds(AsmType * obj_type,uint32_t index)2561 bool 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 
ValidateHeapAccess(Property * heap,HeapAccessType access_type)2578 AsmType* 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
IsCallToFround(Call * call)2652 bool 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 
ValidateFloatCoercion(Call * call)2670 AsmType* 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
ParameterTypeAnnotations(Variable * parameter,Expression * annotation)2696 AsmType* 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
ReturnTypeAnnotations(Expression * ret_expr)2753 AsmType* 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
VariableTypeAnnotations(Expression * initializer,VariableInfo::Mutability mutability_type)2832 AsmType* 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
NewHeapView(CallNew * new_heap_view)2919 AsmType* 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