• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2015 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/typing-asm.h"
6 
7 #include <limits>
8 
9 #include "src/v8.h"
10 
11 #include "src/ast/ast.h"
12 #include "src/ast/scopes.h"
13 #include "src/codegen.h"
14 #include "src/type-cache.h"
15 
16 namespace v8 {
17 namespace internal {
18 
19 #define FAIL(node, msg)                                        \
20   do {                                                         \
21     valid_ = false;                                            \
22     int line = node->position() == RelocInfo::kNoPosition      \
23                    ? -1                                        \
24                    : script_->GetLineNumber(node->position()); \
25     base::OS::SNPrintF(error_message_, sizeof(error_message_), \
26                        "asm: line %d: %s\n", line + 1, msg);   \
27     return;                                                    \
28   } while (false)
29 
30 
31 #define RECURSE(call)               \
32   do {                              \
33     DCHECK(!HasStackOverflow());    \
34     call;                           \
35     if (HasStackOverflow()) return; \
36     if (!valid_) return;            \
37   } while (false)
38 
AsmTyper(Isolate * isolate,Zone * zone,Script * script,FunctionLiteral * root)39 AsmTyper::AsmTyper(Isolate* isolate, Zone* zone, Script* script,
40                    FunctionLiteral* root)
41     : zone_(zone),
42       isolate_(isolate),
43       script_(script),
44       root_(root),
45       valid_(true),
46       allow_simd_(false),
47       property_info_(nullptr),
48       intish_(0),
49       stdlib_types_(zone),
50       stdlib_heap_types_(zone),
51       stdlib_math_types_(zone),
52 #define V(NAME, Name, name, lane_count, lane_type) \
53   stdlib_simd_##name##_types_(zone),
54       SIMD128_TYPES(V)
55 #undef V
56           global_variable_type_(base::HashMap::PointersMatch,
57                                 ZoneHashMap::kDefaultHashMapCapacity,
58                                 ZoneAllocationPolicy(zone)),
59       local_variable_type_(base::HashMap::PointersMatch,
60                            ZoneHashMap::kDefaultHashMapCapacity,
61                            ZoneAllocationPolicy(zone)),
62       in_function_(false),
63       building_function_tables_(false),
64       visiting_exports_(false),
65       cache_(TypeCache::Get()),
66       bounds_(zone) {
67   InitializeAstVisitor(isolate);
68   InitializeStdlib();
69 }
70 
71 
Validate()72 bool AsmTyper::Validate() {
73   VisitAsmModule(root_);
74   return valid_ && !HasStackOverflow();
75 }
76 
77 
VisitAsmModule(FunctionLiteral * fun)78 void AsmTyper::VisitAsmModule(FunctionLiteral* fun) {
79   Scope* scope = fun->scope();
80   if (!scope->is_function_scope()) FAIL(fun, "not at function scope");
81 
82   ExpressionStatement* use_asm = fun->body()->first()->AsExpressionStatement();
83   if (use_asm == nullptr) FAIL(fun, "missing \"use asm\"");
84   Literal* use_asm_literal = use_asm->expression()->AsLiteral();
85   if (use_asm_literal == nullptr) FAIL(fun, "missing \"use asm\"");
86   if (!use_asm_literal->raw_value()->AsString()->IsOneByteEqualTo("use asm"))
87     FAIL(fun, "missing \"use asm\"");
88 
89   // Module parameters.
90   for (int i = 0; i < scope->num_parameters(); ++i) {
91     Variable* param = scope->parameter(i);
92     DCHECK(GetType(param) == nullptr);
93     SetType(param, Type::None());
94   }
95 
96   ZoneList<Declaration*>* decls = scope->declarations();
97 
98   // Set all globals to type Any.
99   VariableDeclaration* decl = scope->function();
100   if (decl != nullptr) SetType(decl->proxy()->var(), Type::None());
101   RECURSE(VisitDeclarations(scope->declarations()));
102 
103   // Validate global variables.
104   RECURSE(VisitStatements(fun->body()));
105 
106   // Validate function annotations.
107   for (int i = 0; i < decls->length(); ++i) {
108     FunctionDeclaration* decl = decls->at(i)->AsFunctionDeclaration();
109     if (decl != nullptr) {
110       RECURSE(VisitFunctionAnnotation(decl->fun()));
111       Variable* var = decl->proxy()->var();
112       if (property_info_ != nullptr) {
113         SetVariableInfo(var, property_info_);
114         property_info_ = nullptr;
115       }
116       SetType(var, computed_type_);
117       DCHECK(GetType(var) != nullptr);
118     }
119   }
120 
121   // Build function tables.
122   building_function_tables_ = true;
123   RECURSE(VisitStatements(fun->body()));
124   building_function_tables_ = false;
125 
126   // Validate function bodies.
127   for (int i = 0; i < decls->length(); ++i) {
128     FunctionDeclaration* decl = decls->at(i)->AsFunctionDeclaration();
129     if (decl != nullptr) {
130       RECURSE(VisitWithExpectation(decl->fun(), Type::Any(), "UNREACHABLE"));
131       if (!computed_type_->IsFunction()) {
132         FAIL(decl->fun(), "function literal expected to be a function");
133       }
134     }
135   }
136 
137   // Validate exports.
138   visiting_exports_ = true;
139   ReturnStatement* stmt = fun->body()->last()->AsReturnStatement();
140   if (stmt == nullptr) {
141     FAIL(fun->body()->last(), "last statement in module is not a return");
142   }
143   RECURSE(VisitWithExpectation(stmt->expression(), Type::Object(),
144                                "expected object export"));
145 }
146 
147 
VisitVariableDeclaration(VariableDeclaration * decl)148 void AsmTyper::VisitVariableDeclaration(VariableDeclaration* decl) {
149   Variable* var = decl->proxy()->var();
150   if (var->location() != VariableLocation::PARAMETER) {
151     if (GetType(var) == nullptr) {
152       SetType(var, Type::Any());
153     } else {
154       DCHECK(!GetType(var)->IsFunction());
155     }
156   }
157   DCHECK(GetType(var) != nullptr);
158   intish_ = 0;
159 }
160 
161 
VisitFunctionDeclaration(FunctionDeclaration * decl)162 void AsmTyper::VisitFunctionDeclaration(FunctionDeclaration* decl) {
163   if (in_function_) {
164     FAIL(decl, "function declared inside another");
165   }
166   // Set function type so global references to functions have some type
167   // (so they can give a more useful error).
168   Variable* var = decl->proxy()->var();
169   if (GetVariableInfo(var)) {
170     // Detect previously-seen functions.
171     FAIL(decl->fun(), "function repeated in module");
172   }
173   SetType(var, Type::Function());
174 }
175 
176 
VisitFunctionAnnotation(FunctionLiteral * fun)177 void AsmTyper::VisitFunctionAnnotation(FunctionLiteral* fun) {
178   // Extract result type.
179   ZoneList<Statement*>* body = fun->body();
180   Type* result_type = Type::Undefined();
181   if (body->length() > 0) {
182     ReturnStatement* stmt = body->last()->AsReturnStatement();
183     if (stmt != nullptr) {
184       Literal* literal = stmt->expression()->AsLiteral();
185       Type* old_expected = expected_type_;
186       expected_type_ = Type::Any();
187       if (literal) {
188         RECURSE(VisitLiteral(literal, true));
189       } else {
190         RECURSE(VisitExpressionAnnotation(stmt->expression(), nullptr, true));
191       }
192       expected_type_ = old_expected;
193       result_type = computed_type_;
194     }
195   }
196   Type* type =
197       Type::Function(result_type, Type::Any(), fun->parameter_count(), zone());
198 
199   // Extract parameter types.
200   bool good = true;
201   for (int i = 0; i < fun->parameter_count(); ++i) {
202     good = false;
203     if (i >= body->length()) break;
204     ExpressionStatement* stmt = body->at(i)->AsExpressionStatement();
205     if (stmt == nullptr) break;
206     Assignment* expr = stmt->expression()->AsAssignment();
207     if (expr == nullptr || expr->is_compound()) break;
208     VariableProxy* proxy = expr->target()->AsVariableProxy();
209     if (proxy == nullptr) break;
210     Variable* var = proxy->var();
211     if (var->location() != VariableLocation::PARAMETER || var->index() != i)
212       break;
213     RECURSE(VisitExpressionAnnotation(expr->value(), var, false));
214     if (property_info_ != nullptr) {
215       SetVariableInfo(var, property_info_);
216       property_info_ = nullptr;
217     }
218     SetType(var, computed_type_);
219     type->AsFunction()->InitParameter(i, computed_type_);
220     good = true;
221   }
222   if (!good) FAIL(fun, "missing parameter type annotations");
223 
224   SetResult(fun, type);
225 }
226 
227 
VisitExpressionAnnotation(Expression * expr,Variable * var,bool is_return)228 void AsmTyper::VisitExpressionAnnotation(Expression* expr, Variable* var,
229                                          bool is_return) {
230   // Normal +x or x|0 annotations.
231   BinaryOperation* bin = expr->AsBinaryOperation();
232   if (bin != nullptr) {
233     if (var != nullptr) {
234       VariableProxy* proxy = bin->left()->AsVariableProxy();
235       if (proxy == nullptr) {
236         FAIL(bin->left(), "expected variable for type annotation");
237       }
238       if (proxy->var() != var) {
239         FAIL(proxy, "annotation source doesn't match destination");
240       }
241     }
242     Literal* right = bin->right()->AsLiteral();
243     if (right != nullptr) {
244       switch (bin->op()) {
245         case Token::MUL:  // We encode +x as x*1.0
246           if (right->raw_value()->ContainsDot() &&
247               right->raw_value()->AsNumber() == 1.0) {
248             SetResult(expr, cache_.kAsmDouble);
249             return;
250           }
251           break;
252         case Token::BIT_OR:
253           if (!right->raw_value()->ContainsDot() &&
254               right->raw_value()->AsNumber() == 0.0) {
255             if (is_return) {
256               SetResult(expr, cache_.kAsmSigned);
257             } else {
258               SetResult(expr, cache_.kAsmInt);
259             }
260             return;
261           }
262           break;
263         default:
264           break;
265       }
266     }
267     FAIL(expr, "invalid type annotation on binary op");
268   }
269 
270   // Numbers or the undefined literal (for empty returns).
271   if (expr->IsLiteral()) {
272     RECURSE(VisitWithExpectation(expr, Type::Any(), "invalid literal"));
273     return;
274   }
275 
276   Call* call = expr->AsCall();
277   if (call != nullptr) {
278     VariableProxy* proxy = call->expression()->AsVariableProxy();
279     if (proxy != nullptr) {
280       VariableInfo* info = GetVariableInfo(proxy->var());
281       if (!info ||
282           (!info->is_check_function && !info->is_constructor_function)) {
283         if (allow_simd_) {
284           FAIL(call->expression(),
285                "only fround/SIMD.checks allowed on expression annotations");
286         } else {
287           FAIL(call->expression(),
288                "only fround allowed on expression annotations");
289         }
290       }
291       Type* type = info->type;
292       DCHECK(type->IsFunction());
293       if (info->is_check_function) {
294         DCHECK(type->AsFunction()->Arity() == 1);
295       }
296       if (call->arguments()->length() != type->AsFunction()->Arity()) {
297         FAIL(call, "invalid argument count calling function");
298       }
299       SetResult(expr, type->AsFunction()->Result());
300       return;
301     }
302   }
303 
304   FAIL(expr, "invalid type annotation");
305 }
306 
307 
VisitStatements(ZoneList<Statement * > * stmts)308 void AsmTyper::VisitStatements(ZoneList<Statement*>* stmts) {
309   for (int i = 0; i < stmts->length(); ++i) {
310     Statement* stmt = stmts->at(i);
311     RECURSE(Visit(stmt));
312   }
313 }
314 
315 
VisitBlock(Block * stmt)316 void AsmTyper::VisitBlock(Block* stmt) {
317   RECURSE(VisitStatements(stmt->statements()));
318 }
319 
320 
VisitExpressionStatement(ExpressionStatement * stmt)321 void AsmTyper::VisitExpressionStatement(ExpressionStatement* stmt) {
322   RECURSE(VisitWithExpectation(stmt->expression(), Type::Any(),
323                                "expression statement expected to be any"));
324 }
325 
326 
VisitEmptyStatement(EmptyStatement * stmt)327 void AsmTyper::VisitEmptyStatement(EmptyStatement* stmt) {}
328 
329 
VisitSloppyBlockFunctionStatement(SloppyBlockFunctionStatement * stmt)330 void AsmTyper::VisitSloppyBlockFunctionStatement(
331     SloppyBlockFunctionStatement* stmt) {
332   Visit(stmt->statement());
333 }
334 
335 
VisitEmptyParentheses(EmptyParentheses * expr)336 void AsmTyper::VisitEmptyParentheses(EmptyParentheses* expr) { UNREACHABLE(); }
337 
338 
VisitIfStatement(IfStatement * stmt)339 void AsmTyper::VisitIfStatement(IfStatement* stmt) {
340   if (!in_function_) {
341     FAIL(stmt, "if statement inside module body");
342   }
343   RECURSE(VisitWithExpectation(stmt->condition(), cache_.kAsmSigned,
344                                "if condition expected to be integer"));
345   RECURSE(Visit(stmt->then_statement()));
346   RECURSE(Visit(stmt->else_statement()));
347 }
348 
349 
VisitContinueStatement(ContinueStatement * stmt)350 void AsmTyper::VisitContinueStatement(ContinueStatement* stmt) {
351   if (!in_function_) {
352     FAIL(stmt, "continue statement inside module body");
353   }
354 }
355 
356 
VisitBreakStatement(BreakStatement * stmt)357 void AsmTyper::VisitBreakStatement(BreakStatement* stmt) {
358   if (!in_function_) {
359     FAIL(stmt, "continue statement inside module body");
360   }
361 }
362 
363 
VisitReturnStatement(ReturnStatement * stmt)364 void AsmTyper::VisitReturnStatement(ReturnStatement* stmt) {
365   // Handle module return statement in VisitAsmModule.
366   if (!in_function_) {
367     return;
368   }
369   Literal* literal = stmt->expression()->AsLiteral();
370   if (literal) {
371     VisitLiteral(literal, true);
372   } else {
373     RECURSE(
374         VisitWithExpectation(stmt->expression(), Type::Any(),
375                              "return expression expected to have return type"));
376   }
377   if (!computed_type_->Is(return_type_) || !return_type_->Is(computed_type_)) {
378     FAIL(stmt->expression(), "return type does not match function signature");
379   }
380 }
381 
382 
VisitWithStatement(WithStatement * stmt)383 void AsmTyper::VisitWithStatement(WithStatement* stmt) {
384   FAIL(stmt, "bad with statement");
385 }
386 
387 
VisitSwitchStatement(SwitchStatement * stmt)388 void AsmTyper::VisitSwitchStatement(SwitchStatement* stmt) {
389   if (!in_function_) {
390     FAIL(stmt, "switch statement inside module body");
391   }
392   RECURSE(VisitWithExpectation(stmt->tag(), cache_.kAsmSigned,
393                                "switch expression non-integer"));
394   ZoneList<CaseClause*>* clauses = stmt->cases();
395   ZoneSet<int32_t> cases(zone());
396   for (int i = 0; i < clauses->length(); ++i) {
397     CaseClause* clause = clauses->at(i);
398     if (clause->is_default()) {
399       if (i != clauses->length() - 1) {
400         FAIL(clause, "default case out of order");
401       }
402     } else {
403       Expression* label = clause->label();
404       RECURSE(VisitWithExpectation(label, cache_.kAsmSigned,
405                                    "case label non-integer"));
406       if (!label->IsLiteral()) FAIL(label, "non-literal case label");
407       Handle<Object> value = label->AsLiteral()->value();
408       int32_t value32;
409       if (!value->ToInt32(&value32)) FAIL(label, "illegal case label value");
410       if (cases.find(value32) != cases.end()) {
411         FAIL(label, "duplicate case value");
412       }
413       cases.insert(value32);
414     }
415     // TODO(bradnelson): Detect duplicates.
416     ZoneList<Statement*>* stmts = clause->statements();
417     RECURSE(VisitStatements(stmts));
418   }
419   if (cases.size() > 0) {
420     int64_t min_case = *cases.begin();
421     int64_t max_case = *cases.rbegin();
422     if (max_case - min_case > std::numeric_limits<int32_t>::max()) {
423       FAIL(stmt, "case range too large");
424     }
425   }
426 }
427 
428 
VisitCaseClause(CaseClause * clause)429 void AsmTyper::VisitCaseClause(CaseClause* clause) { UNREACHABLE(); }
430 
431 
VisitDoWhileStatement(DoWhileStatement * stmt)432 void AsmTyper::VisitDoWhileStatement(DoWhileStatement* stmt) {
433   if (!in_function_) {
434     FAIL(stmt, "do statement inside module body");
435   }
436   RECURSE(Visit(stmt->body()));
437   RECURSE(VisitWithExpectation(stmt->cond(), cache_.kAsmSigned,
438                                "do condition expected to be integer"));
439 }
440 
441 
VisitWhileStatement(WhileStatement * stmt)442 void AsmTyper::VisitWhileStatement(WhileStatement* stmt) {
443   if (!in_function_) {
444     FAIL(stmt, "while statement inside module body");
445   }
446   RECURSE(VisitWithExpectation(stmt->cond(), cache_.kAsmSigned,
447                                "while condition expected to be integer"));
448   RECURSE(Visit(stmt->body()));
449 }
450 
451 
VisitForStatement(ForStatement * stmt)452 void AsmTyper::VisitForStatement(ForStatement* stmt) {
453   if (!in_function_) {
454     FAIL(stmt, "for statement inside module body");
455   }
456   if (stmt->init() != nullptr) {
457     RECURSE(Visit(stmt->init()));
458   }
459   if (stmt->cond() != nullptr) {
460     RECURSE(VisitWithExpectation(stmt->cond(), cache_.kAsmSigned,
461                                  "for condition expected to be integer"));
462   }
463   if (stmt->next() != nullptr) {
464     RECURSE(Visit(stmt->next()));
465   }
466   RECURSE(Visit(stmt->body()));
467 }
468 
469 
VisitForInStatement(ForInStatement * stmt)470 void AsmTyper::VisitForInStatement(ForInStatement* stmt) {
471   FAIL(stmt, "for-in statement encountered");
472 }
473 
474 
VisitForOfStatement(ForOfStatement * stmt)475 void AsmTyper::VisitForOfStatement(ForOfStatement* stmt) {
476   FAIL(stmt, "for-of statement encountered");
477 }
478 
479 
VisitTryCatchStatement(TryCatchStatement * stmt)480 void AsmTyper::VisitTryCatchStatement(TryCatchStatement* stmt) {
481   FAIL(stmt, "try statement encountered");
482 }
483 
484 
VisitTryFinallyStatement(TryFinallyStatement * stmt)485 void AsmTyper::VisitTryFinallyStatement(TryFinallyStatement* stmt) {
486   FAIL(stmt, "try statement encountered");
487 }
488 
489 
VisitDebuggerStatement(DebuggerStatement * stmt)490 void AsmTyper::VisitDebuggerStatement(DebuggerStatement* stmt) {
491   FAIL(stmt, "debugger statement encountered");
492 }
493 
494 
VisitFunctionLiteral(FunctionLiteral * expr)495 void AsmTyper::VisitFunctionLiteral(FunctionLiteral* expr) {
496   if (in_function_) {
497     FAIL(expr, "invalid nested function");
498   }
499   Scope* scope = expr->scope();
500   DCHECK(scope->is_function_scope());
501 
502   if (!bounds_.get(expr).upper->IsFunction()) {
503     FAIL(expr, "invalid function literal");
504   }
505 
506   Type* type = bounds_.get(expr).upper;
507   Type* save_return_type = return_type_;
508   return_type_ = type->AsFunction()->Result();
509   in_function_ = true;
510   local_variable_type_.Clear();
511   RECURSE(VisitDeclarations(scope->declarations()));
512   RECURSE(VisitStatements(expr->body()));
513   in_function_ = false;
514   return_type_ = save_return_type;
515   RECURSE(IntersectResult(expr, type));
516 }
517 
518 
VisitNativeFunctionLiteral(NativeFunctionLiteral * expr)519 void AsmTyper::VisitNativeFunctionLiteral(NativeFunctionLiteral* expr) {
520   FAIL(expr, "function info literal encountered");
521 }
522 
523 
VisitDoExpression(DoExpression * expr)524 void AsmTyper::VisitDoExpression(DoExpression* expr) {
525   FAIL(expr, "do-expression encountered");
526 }
527 
528 
VisitConditional(Conditional * expr)529 void AsmTyper::VisitConditional(Conditional* expr) {
530   if (!in_function_) {
531     FAIL(expr, "ternary operator inside module body");
532   }
533   RECURSE(VisitWithExpectation(expr->condition(), Type::Number(),
534                                "condition expected to be integer"));
535   if (!computed_type_->Is(cache_.kAsmInt)) {
536     FAIL(expr->condition(), "condition must be of type int");
537   }
538 
539   RECURSE(VisitWithExpectation(
540       expr->then_expression(), expected_type_,
541       "conditional then branch type mismatch with enclosing expression"));
542   Type* then_type = StorageType(computed_type_);
543   if (intish_ != 0 || !then_type->Is(cache_.kAsmComparable)) {
544     FAIL(expr->then_expression(), "invalid type in ? then expression");
545   }
546 
547   RECURSE(VisitWithExpectation(
548       expr->else_expression(), expected_type_,
549       "conditional else branch type mismatch with enclosing expression"));
550   Type* else_type = StorageType(computed_type_);
551   if (intish_ != 0 || !else_type->Is(cache_.kAsmComparable)) {
552     FAIL(expr->else_expression(), "invalid type in ? else expression");
553   }
554 
555   if (!then_type->Is(else_type) || !else_type->Is(then_type)) {
556     FAIL(expr, "then and else expressions in ? must have the same type");
557   }
558 
559   RECURSE(IntersectResult(expr, then_type));
560 }
561 
562 
VisitVariableProxy(VariableProxy * expr)563 void AsmTyper::VisitVariableProxy(VariableProxy* expr) {
564   Variable* var = expr->var();
565   VariableInfo* info = GetVariableInfo(var);
566   if (!in_function_ && !building_function_tables_ && !visiting_exports_) {
567     if (var->location() != VariableLocation::PARAMETER || var->index() >= 3) {
568       FAIL(expr, "illegal variable reference in module body");
569     }
570   }
571   if (info == nullptr || info->type == nullptr) {
572     if (var->mode() == TEMPORARY) {
573       SetType(var, Type::Any());
574       info = GetVariableInfo(var);
575     } else {
576       FAIL(expr, "unbound variable");
577     }
578   }
579   if (property_info_ != nullptr) {
580     SetVariableInfo(var, property_info_);
581     property_info_ = nullptr;
582   }
583   Type* type = Type::Intersect(info->type, expected_type_, zone());
584   if (type->Is(cache_.kAsmInt)) type = cache_.kAsmInt;
585   intish_ = 0;
586   RECURSE(IntersectResult(expr, type));
587 }
588 
VisitLiteral(Literal * expr,bool is_return)589 void AsmTyper::VisitLiteral(Literal* expr, bool is_return) {
590   intish_ = 0;
591   Handle<Object> value = expr->value();
592   if (value->IsNumber()) {
593     int32_t i;
594     uint32_t u;
595     if (expr->raw_value()->ContainsDot()) {
596       RECURSE(IntersectResult(expr, cache_.kAsmDouble));
597     } else if (!is_return && value->ToUint32(&u)) {
598       if (u <= 0x7fffffff) {
599         RECURSE(IntersectResult(expr, cache_.kAsmFixnum));
600       } else {
601         RECURSE(IntersectResult(expr, cache_.kAsmUnsigned));
602       }
603     } else if (value->ToInt32(&i)) {
604       RECURSE(IntersectResult(expr, cache_.kAsmSigned));
605     } else {
606       FAIL(expr, "illegal number");
607     }
608   } else if (!is_return && value->IsString()) {
609     RECURSE(IntersectResult(expr, Type::String()));
610   } else if (value->IsUndefined(isolate_)) {
611     RECURSE(IntersectResult(expr, Type::Undefined()));
612   } else {
613     FAIL(expr, "illegal literal");
614   }
615 }
616 
617 
VisitLiteral(Literal * expr)618 void AsmTyper::VisitLiteral(Literal* expr) { VisitLiteral(expr, false); }
619 
620 
VisitRegExpLiteral(RegExpLiteral * expr)621 void AsmTyper::VisitRegExpLiteral(RegExpLiteral* expr) {
622   FAIL(expr, "regular expression encountered");
623 }
624 
625 
VisitObjectLiteral(ObjectLiteral * expr)626 void AsmTyper::VisitObjectLiteral(ObjectLiteral* expr) {
627   if (in_function_) {
628     FAIL(expr, "object literal in function");
629   }
630   // Allowed for asm module's export declaration.
631   ZoneList<ObjectLiteralProperty*>* props = expr->properties();
632   for (int i = 0; i < props->length(); ++i) {
633     ObjectLiteralProperty* prop = props->at(i);
634     RECURSE(VisitWithExpectation(prop->value(), Type::Any(),
635                                  "object property expected to be a function"));
636     if (!computed_type_->IsFunction()) {
637       FAIL(prop->value(), "non-function in function table");
638     }
639   }
640   RECURSE(IntersectResult(expr, Type::Object()));
641 }
642 
643 
VisitArrayLiteral(ArrayLiteral * expr)644 void AsmTyper::VisitArrayLiteral(ArrayLiteral* expr) {
645   if (in_function_) {
646     FAIL(expr, "array literal inside a function");
647   }
648   // Allowed for function tables.
649   ZoneList<Expression*>* values = expr->values();
650   Type* elem_type = Type::None();
651   for (int i = 0; i < values->length(); ++i) {
652     Expression* value = values->at(i);
653     RECURSE(VisitWithExpectation(value, Type::Any(), "UNREACHABLE"));
654     if (!computed_type_->IsFunction()) {
655       FAIL(value, "array component expected to be a function");
656     }
657     elem_type = Type::Union(elem_type, computed_type_, zone());
658   }
659   array_size_ = values->length();
660   RECURSE(IntersectResult(expr, Type::Array(elem_type, zone())));
661 }
662 
663 
VisitAssignment(Assignment * expr)664 void AsmTyper::VisitAssignment(Assignment* expr) {
665   // Handle function tables and everything else in different passes.
666   if (!in_function_) {
667     if (expr->value()->IsArrayLiteral()) {
668       if (!building_function_tables_) {
669         return;
670       }
671     } else {
672       if (building_function_tables_) {
673         return;
674       }
675     }
676   }
677   if (expr->is_compound()) FAIL(expr, "compound assignment encountered");
678   Type* type = expected_type_;
679   RECURSE(VisitWithExpectation(
680       expr->value(), type, "assignment value expected to match surrounding"));
681   Type* target_type = StorageType(computed_type_);
682 
683   if (expr->target()->IsVariableProxy()) {
684     // Assignment to a local or context variable.
685     VariableProxy* proxy = expr->target()->AsVariableProxy();
686     if (intish_ != 0) {
687       FAIL(expr, "intish or floatish assignment");
688     }
689     if (in_function_ && target_type->IsArray()) {
690       FAIL(expr, "assignment to array variable");
691     }
692     expected_type_ = target_type;
693     Variable* var = proxy->var();
694     VariableInfo* info = GetVariableInfo(var);
695     if (info == nullptr || info->type == nullptr) {
696       if (var->mode() == TEMPORARY) {
697         SetType(var, Type::Any());
698         info = GetVariableInfo(var);
699       } else {
700         FAIL(proxy, "unbound variable");
701       }
702     }
703     if (property_info_ != nullptr) {
704       SetVariableInfo(var, property_info_);
705       property_info_ = nullptr;
706     }
707     Type* type = Type::Intersect(info->type, expected_type_, zone());
708     if (type->Is(cache_.kAsmInt)) type = cache_.kAsmInt;
709     info->type = type;
710     intish_ = 0;
711     RECURSE(IntersectResult(proxy, type));
712   } else if (expr->target()->IsProperty()) {
713     // Assignment to a property: should be a heap assignment {H[x] = y}.
714     int32_t value_intish = intish_;
715     Property* property = expr->target()->AsProperty();
716     RECURSE(VisitWithExpectation(property->obj(), Type::Any(),
717                                  "bad propety object"));
718     if (!computed_type_->IsArray()) {
719       FAIL(property->obj(), "array expected");
720     }
721     if (value_intish != 0 && computed_type_->Is(cache_.kFloat64Array)) {
722       FAIL(expr, "floatish assignment to double array");
723     }
724     VisitHeapAccess(property, true, target_type);
725   }
726   RECURSE(IntersectResult(expr, target_type));
727 }
728 
729 
VisitYield(Yield * expr)730 void AsmTyper::VisitYield(Yield* expr) {
731   FAIL(expr, "yield expression encountered");
732 }
733 
734 
VisitThrow(Throw * expr)735 void AsmTyper::VisitThrow(Throw* expr) {
736   FAIL(expr, "throw statement encountered");
737 }
738 
739 
ElementShiftSize(Type * type)740 int AsmTyper::ElementShiftSize(Type* type) {
741   if (type->Is(cache_.kAsmSize8)) return 0;
742   if (type->Is(cache_.kAsmSize16)) return 1;
743   if (type->Is(cache_.kAsmSize32)) return 2;
744   if (type->Is(cache_.kAsmSize64)) return 3;
745   return -1;
746 }
747 
748 
StorageType(Type * type)749 Type* AsmTyper::StorageType(Type* type) {
750   if (type->Is(cache_.kAsmInt)) {
751     return cache_.kAsmInt;
752   } else {
753     return type;
754   }
755 }
756 
757 
VisitHeapAccess(Property * expr,bool assigning,Type * assignment_type)758 void AsmTyper::VisitHeapAccess(Property* expr, bool assigning,
759                                Type* assignment_type) {
760   ArrayType* array_type = computed_type_->AsArray();
761   //  size_t size = array_size_;
762   Type* type = array_type->Element();
763   if (type->IsFunction()) {
764     if (assigning) {
765       FAIL(expr, "assigning to function table is illegal");
766     }
767     // TODO(bradnelson): Fix the parser and then un-comment this part
768     // BinaryOperation* bin = expr->key()->AsBinaryOperation();
769     // if (bin == nullptr || bin->op() != Token::BIT_AND) {
770     //   FAIL(expr->key(), "expected & in call");
771     // }
772     // RECURSE(VisitWithExpectation(bin->left(), cache_.kAsmSigned,
773     //                              "array index expected to be integer"));
774     // Literal* right = bin->right()->AsLiteral();
775     // if (right == nullptr || right->raw_value()->ContainsDot()) {
776     //   FAIL(right, "call mask must be integer");
777     // }
778     // RECURSE(VisitWithExpectation(bin->right(), cache_.kAsmSigned,
779     //                              "call mask expected to be integer"));
780     // if (static_cast<size_t>(right->raw_value()->AsNumber()) != size - 1) {
781     //   FAIL(right, "call mask must match function table");
782     // }
783     // bin->set_bounds(Bounds(cache_.kAsmSigned));
784     RECURSE(VisitWithExpectation(expr->key(), cache_.kAsmSigned,
785                                  "must be integer"));
786     RECURSE(IntersectResult(expr, type));
787   } else {
788     Literal* literal = expr->key()->AsLiteral();
789     if (literal) {
790       RECURSE(VisitWithExpectation(literal, cache_.kAsmSigned,
791                                    "array index expected to be integer"));
792     } else {
793       int expected_shift = ElementShiftSize(type);
794       if (expected_shift == 0) {
795         RECURSE(Visit(expr->key()));
796       } else {
797         BinaryOperation* bin = expr->key()->AsBinaryOperation();
798         if (bin == nullptr || bin->op() != Token::SAR) {
799           FAIL(expr->key(), "expected >> in heap access");
800         }
801         RECURSE(VisitWithExpectation(bin->left(), cache_.kAsmSigned,
802                                      "array index expected to be integer"));
803         Literal* right = bin->right()->AsLiteral();
804         if (right == nullptr || right->raw_value()->ContainsDot()) {
805           FAIL(bin->right(), "heap access shift must be integer");
806         }
807         RECURSE(VisitWithExpectation(bin->right(), cache_.kAsmSigned,
808                                      "array shift expected to be integer"));
809         int n = static_cast<int>(right->raw_value()->AsNumber());
810         if (expected_shift < 0 || n != expected_shift) {
811           FAIL(right, "heap access shift must match element size");
812         }
813       }
814       bounds_.set(expr->key(), Bounds(cache_.kAsmSigned));
815     }
816     Type* result_type;
817     if (type->Is(cache_.kAsmIntArrayElement)) {
818       result_type = cache_.kAsmIntQ;
819       intish_ = kMaxUncombinedAdditiveSteps;
820     } else if (type->Is(cache_.kAsmFloat)) {
821       if (assigning) {
822         result_type = cache_.kAsmFloatDoubleQ;
823       } else {
824         result_type = cache_.kAsmFloatQ;
825       }
826       intish_ = 0;
827     } else if (type->Is(cache_.kAsmDouble)) {
828       if (assigning) {
829         result_type = cache_.kAsmFloatDoubleQ;
830         if (intish_ != 0) {
831           FAIL(expr, "Assignment of floatish to Float64Array");
832         }
833       } else {
834         result_type = cache_.kAsmDoubleQ;
835       }
836       intish_ = 0;
837     } else {
838       UNREACHABLE();
839     }
840     if (assigning) {
841       if (!assignment_type->Is(result_type)) {
842         FAIL(expr, "illegal type in assignment");
843       }
844     } else {
845       RECURSE(IntersectResult(expr, expected_type_));
846       RECURSE(IntersectResult(expr, result_type));
847     }
848   }
849 }
850 
851 
IsStdlibObject(Expression * expr)852 bool AsmTyper::IsStdlibObject(Expression* expr) {
853   VariableProxy* proxy = expr->AsVariableProxy();
854   if (proxy == nullptr) {
855     return false;
856   }
857   Variable* var = proxy->var();
858   VariableInfo* info = GetVariableInfo(var);
859   if (info) {
860     if (info->standard_member == kStdlib) return true;
861   }
862   if (var->location() != VariableLocation::PARAMETER || var->index() != 0) {
863     return false;
864   }
865   info = MakeVariableInfo(var);
866   info->type = Type::Object();
867   info->standard_member = kStdlib;
868   return true;
869 }
870 
871 
GetReceiverOfPropertyAccess(Expression * expr,const char * name)872 Expression* AsmTyper::GetReceiverOfPropertyAccess(Expression* expr,
873                                                   const char* name) {
874   Property* property = expr->AsProperty();
875   if (property == nullptr) {
876     return nullptr;
877   }
878   Literal* key = property->key()->AsLiteral();
879   if (key == nullptr || !key->IsPropertyName() ||
880       !key->AsPropertyName()->IsUtf8EqualTo(CStrVector(name))) {
881     return nullptr;
882   }
883   return property->obj();
884 }
885 
886 
IsMathObject(Expression * expr)887 bool AsmTyper::IsMathObject(Expression* expr) {
888   Expression* obj = GetReceiverOfPropertyAccess(expr, "Math");
889   return obj && IsStdlibObject(obj);
890 }
891 
892 
IsSIMDObject(Expression * expr)893 bool AsmTyper::IsSIMDObject(Expression* expr) {
894   Expression* obj = GetReceiverOfPropertyAccess(expr, "SIMD");
895   return obj && IsStdlibObject(obj);
896 }
897 
898 
IsSIMDTypeObject(Expression * expr,const char * name)899 bool AsmTyper::IsSIMDTypeObject(Expression* expr, const char* name) {
900   Expression* obj = GetReceiverOfPropertyAccess(expr, name);
901   return obj && IsSIMDObject(obj);
902 }
903 
904 
VisitProperty(Property * expr)905 void AsmTyper::VisitProperty(Property* expr) {
906   if (IsMathObject(expr->obj())) {
907     VisitLibraryAccess(&stdlib_math_types_, expr);
908     return;
909   }
910 #define V(NAME, Name, name, lane_count, lane_type)               \
911   if (IsSIMDTypeObject(expr->obj(), #Name)) {                    \
912     VisitLibraryAccess(&stdlib_simd_##name##_types_, expr);      \
913     return;                                                      \
914   }                                                              \
915   if (IsSIMDTypeObject(expr, #Name)) {                           \
916     VariableInfo* info = stdlib_simd_##name##_constructor_type_; \
917     SetResult(expr, info->type);                                 \
918     property_info_ = info;                                       \
919     return;                                                      \
920   }
921   SIMD128_TYPES(V)
922 #undef V
923   if (IsStdlibObject(expr->obj())) {
924     VisitLibraryAccess(&stdlib_types_, expr);
925     return;
926   }
927 
928   property_info_ = nullptr;
929 
930   // Only recurse at this point so that we avoid needing
931   // stdlib.Math to have a real type.
932   RECURSE(
933       VisitWithExpectation(expr->obj(), Type::Any(), "bad property object"));
934 
935   // For heap view or function table access.
936   if (computed_type_->IsArray()) {
937     VisitHeapAccess(expr, false, nullptr);
938     return;
939   }
940 
941   VariableProxy* proxy = expr->obj()->AsVariableProxy();
942   if (proxy != nullptr) {
943     Variable* var = proxy->var();
944     if (var->location() == VariableLocation::PARAMETER && var->index() == 1) {
945       // foreign.x - Function represent as () -> Any
946       if (Type::Any()->Is(expected_type_)) {
947         SetResult(expr, Type::Function(Type::Any(), zone()));
948       } else {
949         SetResult(expr, expected_type_);
950       }
951       return;
952     }
953   }
954 
955   FAIL(expr, "invalid property access");
956 }
957 
CheckPolymorphicStdlibArguments(enum StandardMember standard_member,ZoneList<Expression * > * args)958 void AsmTyper::CheckPolymorphicStdlibArguments(
959     enum StandardMember standard_member, ZoneList<Expression*>* args) {
960   if (args->length() == 0) {
961     return;
962   }
963   // Handle polymorphic stdlib functions specially.
964   Expression* arg0 = args->at(0);
965   Type* arg0_type = bounds_.get(arg0).upper;
966   switch (standard_member) {
967     case kMathFround: {
968       if (!arg0_type->Is(cache_.kAsmFloat) &&
969           !arg0_type->Is(cache_.kAsmDouble) &&
970           !arg0_type->Is(cache_.kAsmSigned) &&
971           !arg0_type->Is(cache_.kAsmUnsigned)) {
972         FAIL(arg0, "illegal function argument type");
973       }
974       break;
975     }
976     case kMathCeil:
977     case kMathFloor:
978     case kMathSqrt: {
979       if (!arg0_type->Is(cache_.kAsmFloat) &&
980           !arg0_type->Is(cache_.kAsmDouble)) {
981         FAIL(arg0, "illegal function argument type");
982       }
983       break;
984     }
985     case kMathAbs:
986     case kMathMin:
987     case kMathMax: {
988       if (!arg0_type->Is(cache_.kAsmFloat) &&
989           !arg0_type->Is(cache_.kAsmDouble) &&
990           !arg0_type->Is(cache_.kAsmSigned)) {
991         FAIL(arg0, "illegal function argument type");
992       }
993       if (args->length() > 1) {
994         Type* other = Type::Intersect(bounds_.get(args->at(0)).upper,
995                                       bounds_.get(args->at(1)).upper, zone());
996         if (!other->Is(cache_.kAsmFloat) && !other->Is(cache_.kAsmDouble) &&
997             !other->Is(cache_.kAsmSigned)) {
998           FAIL(arg0, "function arguments types don't match");
999         }
1000       }
1001       break;
1002     }
1003     default: { break; }
1004   }
1005 }
1006 
VisitCall(Call * expr)1007 void AsmTyper::VisitCall(Call* expr) {
1008   Type* expected_type = expected_type_;
1009   RECURSE(VisitWithExpectation(expr->expression(), Type::Any(),
1010                                "callee expected to be any"));
1011   StandardMember standard_member = kNone;
1012   VariableProxy* proxy = expr->expression()->AsVariableProxy();
1013   if (proxy) {
1014     standard_member = VariableAsStandardMember(proxy->var());
1015   }
1016   if (!in_function_ && (proxy == nullptr || standard_member != kMathFround)) {
1017     FAIL(expr, "calls forbidden outside function bodies");
1018   }
1019   if (proxy == nullptr && !expr->expression()->IsProperty()) {
1020     FAIL(expr, "calls must be to bound variables or function tables");
1021   }
1022   if (computed_type_->IsFunction()) {
1023     FunctionType* fun_type = computed_type_->AsFunction();
1024     Type* result_type = fun_type->Result();
1025     ZoneList<Expression*>* args = expr->arguments();
1026     if (Type::Any()->Is(result_type)) {
1027       // For foreign calls.
1028       for (int i = 0; i < args->length(); ++i) {
1029         Expression* arg = args->at(i);
1030         RECURSE(VisitWithExpectation(
1031             arg, Type::Any(), "foreign call argument expected to be any"));
1032         // Checking for asm extern types explicitly, as the type system
1033         // doesn't correctly check their inheritance relationship.
1034         if (!computed_type_->Is(cache_.kAsmSigned) &&
1035             !computed_type_->Is(cache_.kAsmFixnum) &&
1036             !computed_type_->Is(cache_.kAsmDouble)) {
1037           FAIL(arg,
1038                "foreign call argument expected to be int, double, or fixnum");
1039         }
1040       }
1041       intish_ = 0;
1042       bounds_.set(expr->expression(),
1043                   Bounds(Type::Function(Type::Any(), zone())));
1044       RECURSE(IntersectResult(expr, expected_type));
1045     } else {
1046       if (fun_type->Arity() != args->length()) {
1047         FAIL(expr, "call with wrong arity");
1048       }
1049       for (int i = 0; i < args->length(); ++i) {
1050         Expression* arg = args->at(i);
1051         RECURSE(VisitWithExpectation(
1052             arg, fun_type->Parameter(i),
1053             "call argument expected to match callee parameter"));
1054         if (standard_member != kNone && standard_member != kMathFround &&
1055             i == 0) {
1056           result_type = computed_type_;
1057         }
1058       }
1059       RECURSE(CheckPolymorphicStdlibArguments(standard_member, args));
1060       intish_ = 0;
1061       RECURSE(IntersectResult(expr, result_type));
1062     }
1063   } else {
1064     FAIL(expr, "invalid callee");
1065   }
1066 }
1067 
1068 
VisitCallNew(CallNew * expr)1069 void AsmTyper::VisitCallNew(CallNew* expr) {
1070   if (in_function_) {
1071     FAIL(expr, "new not allowed in module function");
1072   }
1073   RECURSE(VisitWithExpectation(expr->expression(), Type::Any(),
1074                                "expected stdlib function"));
1075   if (computed_type_->IsFunction()) {
1076     FunctionType* fun_type = computed_type_->AsFunction();
1077     ZoneList<Expression*>* args = expr->arguments();
1078     if (fun_type->Arity() != args->length())
1079       FAIL(expr, "call with wrong arity");
1080     for (int i = 0; i < args->length(); ++i) {
1081       Expression* arg = args->at(i);
1082       RECURSE(VisitWithExpectation(
1083           arg, fun_type->Parameter(i),
1084           "constructor argument expected to match callee parameter"));
1085     }
1086     RECURSE(IntersectResult(expr, fun_type->Result()));
1087     return;
1088   }
1089 
1090   FAIL(expr, "ill-typed new operator");
1091 }
1092 
1093 
VisitCallRuntime(CallRuntime * expr)1094 void AsmTyper::VisitCallRuntime(CallRuntime* expr) {
1095   FAIL(expr, "runtime call not allowed");
1096 }
1097 
1098 
VisitUnaryOperation(UnaryOperation * expr)1099 void AsmTyper::VisitUnaryOperation(UnaryOperation* expr) {
1100   if (!in_function_) {
1101     FAIL(expr, "unary operator inside module body");
1102   }
1103   switch (expr->op()) {
1104     case Token::NOT:  // Used to encode != and !==
1105       RECURSE(VisitWithExpectation(expr->expression(), cache_.kAsmInt,
1106                                    "operand expected to be integer"));
1107       RECURSE(IntersectResult(expr, cache_.kAsmSigned));
1108       return;
1109     case Token::DELETE:
1110       FAIL(expr, "delete operator encountered");
1111     case Token::VOID:
1112       FAIL(expr, "void operator encountered");
1113     case Token::TYPEOF:
1114       FAIL(expr, "typeof operator encountered");
1115     default:
1116       UNREACHABLE();
1117   }
1118 }
1119 
1120 
VisitCountOperation(CountOperation * expr)1121 void AsmTyper::VisitCountOperation(CountOperation* expr) {
1122   FAIL(expr, "increment or decrement operator encountered");
1123 }
1124 
1125 
VisitIntegerBitwiseOperator(BinaryOperation * expr,Type * left_expected,Type * right_expected,Type * result_type,bool conversion)1126 void AsmTyper::VisitIntegerBitwiseOperator(BinaryOperation* expr,
1127                                            Type* left_expected,
1128                                            Type* right_expected,
1129                                            Type* result_type, bool conversion) {
1130   RECURSE(VisitWithExpectation(expr->left(), Type::Number(),
1131                                "left bitwise operand expected to be a number"));
1132   int32_t left_intish = intish_;
1133   Type* left_type = computed_type_;
1134   if (!left_type->Is(left_expected)) {
1135     FAIL(expr->left(), "left bitwise operand expected to be an integer");
1136   }
1137   if (left_intish > kMaxUncombinedAdditiveSteps) {
1138     FAIL(expr->left(), "too many consecutive additive ops");
1139   }
1140 
1141   RECURSE(
1142       VisitWithExpectation(expr->right(), Type::Number(),
1143                            "right bitwise operand expected to be a number"));
1144   int32_t right_intish = intish_;
1145   Type* right_type = computed_type_;
1146   if (!right_type->Is(right_expected)) {
1147     FAIL(expr->right(), "right bitwise operand expected to be an integer");
1148   }
1149   if (right_intish > kMaxUncombinedAdditiveSteps) {
1150     FAIL(expr->right(), "too many consecutive additive ops");
1151   }
1152 
1153   intish_ = 0;
1154 
1155   if (left_type->Is(cache_.kAsmFixnum) && right_type->Is(cache_.kAsmInt)) {
1156     left_type = right_type;
1157   }
1158   if (right_type->Is(cache_.kAsmFixnum) && left_type->Is(cache_.kAsmInt)) {
1159     right_type = left_type;
1160   }
1161   if (!conversion) {
1162     if (!left_type->Is(cache_.kAsmIntQ) || !right_type->Is(cache_.kAsmIntQ)) {
1163       FAIL(expr, "ill-typed bitwise operation");
1164     }
1165   }
1166   RECURSE(IntersectResult(expr, result_type));
1167 }
1168 
1169 
VisitBinaryOperation(BinaryOperation * expr)1170 void AsmTyper::VisitBinaryOperation(BinaryOperation* expr) {
1171   if (!in_function_) {
1172     if (expr->op() != Token::BIT_OR && expr->op() != Token::MUL) {
1173       FAIL(expr, "illegal binary operator inside module body");
1174     }
1175     if (!(expr->left()->IsProperty() || expr->left()->IsVariableProxy()) ||
1176         !expr->right()->IsLiteral()) {
1177       FAIL(expr, "illegal computation inside module body");
1178     }
1179     DCHECK(expr->right()->AsLiteral() != nullptr);
1180     const AstValue* right_value = expr->right()->AsLiteral()->raw_value();
1181     if (expr->op() == Token::BIT_OR) {
1182       if (right_value->AsNumber() != 0.0 || right_value->ContainsDot()) {
1183         FAIL(expr, "illegal integer annotation value");
1184       }
1185     }
1186     if (expr->op() == Token::MUL) {
1187       if (right_value->AsNumber() != 1.0 && right_value->ContainsDot()) {
1188         FAIL(expr, "illegal double annotation value");
1189       }
1190     }
1191   }
1192   switch (expr->op()) {
1193     case Token::COMMA: {
1194       RECURSE(VisitWithExpectation(expr->left(), Type::Any(),
1195                                    "left comma operand expected to be any"));
1196       RECURSE(VisitWithExpectation(expr->right(), Type::Any(),
1197                                    "right comma operand expected to be any"));
1198       RECURSE(IntersectResult(expr, computed_type_));
1199       return;
1200     }
1201     case Token::OR:
1202     case Token::AND:
1203       FAIL(expr, "illegal logical operator");
1204     case Token::BIT_OR: {
1205       // BIT_OR allows Any since it is used as a type coercion.
1206       RECURSE(VisitIntegerBitwiseOperator(expr, Type::Any(), cache_.kAsmIntQ,
1207                                           cache_.kAsmSigned, true));
1208       if (expr->left()->IsCall() && expr->op() == Token::BIT_OR &&
1209           Type::Number()->Is(bounds_.get(expr->left()).upper)) {
1210         // Force the return types of foreign functions.
1211         bounds_.set(expr->left(), Bounds(cache_.kAsmSigned));
1212       }
1213       if (in_function_ &&
1214           !bounds_.get(expr->left()).upper->Is(cache_.kAsmIntQ)) {
1215         FAIL(expr->left(), "intish required");
1216       }
1217       return;
1218     }
1219     case Token::BIT_XOR: {
1220       // Handle booleans specially to handle de-sugared !
1221       Literal* left = expr->left()->AsLiteral();
1222       if (left && left->value()->IsBoolean()) {
1223         if (left->ToBooleanIsTrue()) {
1224           bounds_.set(left, Bounds(cache_.kSingletonOne));
1225           RECURSE(VisitWithExpectation(expr->right(), cache_.kAsmIntQ,
1226                                        "not operator expects an integer"));
1227           RECURSE(IntersectResult(expr, cache_.kAsmSigned));
1228           return;
1229         } else {
1230           FAIL(left, "unexpected false");
1231         }
1232       }
1233       // BIT_XOR allows Any since it is used as a type coercion (via ~~).
1234       RECURSE(VisitIntegerBitwiseOperator(expr, Type::Any(), cache_.kAsmIntQ,
1235                                           cache_.kAsmSigned, true));
1236       return;
1237     }
1238     case Token::SHR: {
1239       RECURSE(VisitIntegerBitwiseOperator(
1240           expr, cache_.kAsmIntQ, cache_.kAsmIntQ, cache_.kAsmUnsigned, false));
1241       return;
1242     }
1243     case Token::SHL:
1244     case Token::SAR:
1245     case Token::BIT_AND: {
1246       RECURSE(VisitIntegerBitwiseOperator(
1247           expr, cache_.kAsmIntQ, cache_.kAsmIntQ, cache_.kAsmSigned, false));
1248       return;
1249     }
1250     case Token::ADD:
1251     case Token::SUB:
1252     case Token::MUL:
1253     case Token::DIV:
1254     case Token::MOD: {
1255       RECURSE(VisitWithExpectation(
1256           expr->left(), Type::Number(),
1257           "left arithmetic operand expected to be number"));
1258       Type* left_type = computed_type_;
1259       int32_t left_intish = intish_;
1260       RECURSE(VisitWithExpectation(
1261           expr->right(), Type::Number(),
1262           "right arithmetic operand expected to be number"));
1263       Type* right_type = computed_type_;
1264       int32_t right_intish = intish_;
1265       Type* type = Type::Union(left_type, right_type, zone());
1266       if (type->Is(cache_.kAsmInt)) {
1267         if (expr->op() == Token::MUL) {
1268           int32_t i;
1269           Literal* left = expr->left()->AsLiteral();
1270           Literal* right = expr->right()->AsLiteral();
1271           if (left != nullptr && left->value()->IsNumber() &&
1272               left->value()->ToInt32(&i)) {
1273             if (right_intish != 0) {
1274               FAIL(expr, "intish not allowed in multiply");
1275             }
1276           } else if (right != nullptr && right->value()->IsNumber() &&
1277                      right->value()->ToInt32(&i)) {
1278             if (left_intish != 0) {
1279               FAIL(expr, "intish not allowed in multiply");
1280             }
1281           } else {
1282             FAIL(expr, "multiply must be by an integer literal");
1283           }
1284           i = abs(i);
1285           if (i >= (1 << 20)) {
1286             FAIL(expr, "multiply must be by value in -2^20 < n < 2^20");
1287           }
1288           intish_ = i;
1289           RECURSE(IntersectResult(expr, cache_.kAsmInt));
1290           return;
1291         } else {
1292           intish_ = left_intish + right_intish + 1;
1293           if (expr->op() == Token::ADD || expr->op() == Token::SUB) {
1294             if (intish_ > kMaxUncombinedAdditiveSteps) {
1295               FAIL(expr, "too many consecutive additive ops");
1296             }
1297           } else {
1298             if (intish_ > kMaxUncombinedMultiplicativeSteps) {
1299               FAIL(expr, "too many consecutive multiplicative ops");
1300             }
1301           }
1302           RECURSE(IntersectResult(expr, cache_.kAsmInt));
1303           return;
1304         }
1305       } else if (expr->op() == Token::MUL && expr->right()->IsLiteral() &&
1306                  right_type->Is(cache_.kAsmDouble) &&
1307                  expr->right()->AsLiteral()->raw_value()->ContainsDot() &&
1308                  expr->right()->AsLiteral()->raw_value()->AsNumber() == 1.0) {
1309         // For unary +, expressed as x * 1.0
1310         if (expr->left()->IsCall() &&
1311             Type::Number()->Is(bounds_.get(expr->left()).upper)) {
1312           // Force the return types of foreign functions.
1313           bounds_.set(expr->left(), Bounds(cache_.kAsmDouble));
1314           left_type = bounds_.get(expr->left()).upper;
1315         }
1316         if (!(expr->left()->IsProperty() &&
1317               Type::Number()->Is(bounds_.get(expr->left()).upper))) {
1318           if (!left_type->Is(cache_.kAsmSigned) &&
1319               !left_type->Is(cache_.kAsmUnsigned) &&
1320               !left_type->Is(cache_.kAsmFixnum) &&
1321               !left_type->Is(cache_.kAsmFloatQ) &&
1322               !left_type->Is(cache_.kAsmDoubleQ)) {
1323             FAIL(
1324                 expr->left(),
1325                 "unary + only allowed on signed, unsigned, float?, or double?");
1326           }
1327         }
1328         RECURSE(IntersectResult(expr, cache_.kAsmDouble));
1329         return;
1330       } else if (expr->op() == Token::MUL && left_type->Is(cache_.kAsmDouble) &&
1331                  expr->right()->IsLiteral() &&
1332                  !expr->right()->AsLiteral()->raw_value()->ContainsDot() &&
1333                  expr->right()->AsLiteral()->raw_value()->AsNumber() == -1.0) {
1334         // For unary -, expressed as x * -1
1335         bounds_.set(expr->right(), Bounds(cache_.kAsmDouble));
1336         RECURSE(IntersectResult(expr, cache_.kAsmDouble));
1337         return;
1338       } else if (type->Is(cache_.kAsmFloat) && expr->op() != Token::MOD) {
1339         if (left_intish != 0 || right_intish != 0) {
1340           FAIL(expr, "float operation before required fround");
1341         }
1342         RECURSE(IntersectResult(expr, cache_.kAsmFloat));
1343         intish_ = 1;
1344         return;
1345       } else if (type->Is(cache_.kAsmDouble)) {
1346         RECURSE(IntersectResult(expr, cache_.kAsmDouble));
1347         return;
1348       } else {
1349         FAIL(expr, "ill-typed arithmetic operation");
1350       }
1351     }
1352     default:
1353       UNREACHABLE();
1354   }
1355 }
1356 
1357 
VisitCompareOperation(CompareOperation * expr)1358 void AsmTyper::VisitCompareOperation(CompareOperation* expr) {
1359   if (!in_function_) {
1360     FAIL(expr, "comparison inside module body");
1361   }
1362   Token::Value op = expr->op();
1363   if (op != Token::EQ && op != Token::NE && op != Token::LT &&
1364       op != Token::LTE && op != Token::GT && op != Token::GTE) {
1365     FAIL(expr, "illegal comparison operator");
1366   }
1367 
1368   RECURSE(
1369       VisitWithExpectation(expr->left(), Type::Number(),
1370                            "left comparison operand expected to be number"));
1371   Type* left_type = computed_type_;
1372   if (!left_type->Is(cache_.kAsmComparable)) {
1373     FAIL(expr->left(), "bad type on left side of comparison");
1374   }
1375 
1376   RECURSE(
1377       VisitWithExpectation(expr->right(), Type::Number(),
1378                            "right comparison operand expected to be number"));
1379   Type* right_type = computed_type_;
1380   if (!right_type->Is(cache_.kAsmComparable)) {
1381     FAIL(expr->right(), "bad type on right side of comparison");
1382   }
1383 
1384   if (!left_type->Is(right_type) && !right_type->Is(left_type)) {
1385     FAIL(expr, "left and right side of comparison must match");
1386   }
1387 
1388   RECURSE(IntersectResult(expr, cache_.kAsmSigned));
1389 }
1390 
1391 
VisitThisFunction(ThisFunction * expr)1392 void AsmTyper::VisitThisFunction(ThisFunction* expr) {
1393   FAIL(expr, "this function not allowed");
1394 }
1395 
1396 
VisitDeclarations(ZoneList<Declaration * > * decls)1397 void AsmTyper::VisitDeclarations(ZoneList<Declaration*>* decls) {
1398   for (int i = 0; i < decls->length(); ++i) {
1399     Declaration* decl = decls->at(i);
1400     RECURSE(Visit(decl));
1401   }
1402 }
1403 
1404 
VisitImportDeclaration(ImportDeclaration * decl)1405 void AsmTyper::VisitImportDeclaration(ImportDeclaration* decl) {
1406   FAIL(decl, "import declaration encountered");
1407 }
1408 
1409 
VisitExportDeclaration(ExportDeclaration * decl)1410 void AsmTyper::VisitExportDeclaration(ExportDeclaration* decl) {
1411   FAIL(decl, "export declaration encountered");
1412 }
1413 
1414 
VisitClassLiteral(ClassLiteral * expr)1415 void AsmTyper::VisitClassLiteral(ClassLiteral* expr) {
1416   FAIL(expr, "class literal not allowed");
1417 }
1418 
1419 
VisitSpread(Spread * expr)1420 void AsmTyper::VisitSpread(Spread* expr) { FAIL(expr, "spread not allowed"); }
1421 
1422 
VisitSuperPropertyReference(SuperPropertyReference * expr)1423 void AsmTyper::VisitSuperPropertyReference(SuperPropertyReference* expr) {
1424   FAIL(expr, "super property reference not allowed");
1425 }
1426 
1427 
VisitSuperCallReference(SuperCallReference * expr)1428 void AsmTyper::VisitSuperCallReference(SuperCallReference* expr) {
1429   FAIL(expr, "call reference not allowed");
1430 }
1431 
1432 
InitializeStdlibSIMD()1433 void AsmTyper::InitializeStdlibSIMD() {
1434 #define V(NAME, Name, name, lane_count, lane_type)                            \
1435   {                                                                           \
1436     Type* type = Type::Function(Type::Name(isolate_, zone()), Type::Any(),    \
1437                                 lane_count, zone());                          \
1438     for (int i = 0; i < lane_count; ++i) {                                    \
1439       type->AsFunction()->InitParameter(i, Type::Number());                   \
1440     }                                                                         \
1441     stdlib_simd_##name##_constructor_type_ = new (zone()) VariableInfo(type); \
1442     stdlib_simd_##name##_constructor_type_->is_constructor_function = true;   \
1443   }
1444   SIMD128_TYPES(V)
1445 #undef V
1446 }
1447 
1448 
InitializeStdlib()1449 void AsmTyper::InitializeStdlib() {
1450   if (allow_simd_) {
1451     InitializeStdlibSIMD();
1452   }
1453   Type* number_type = Type::Number();
1454   Type* double_type = cache_.kAsmDouble;
1455   Type* double_fn1_type = Type::Function(double_type, double_type, zone());
1456   Type* double_fn2_type =
1457       Type::Function(double_type, double_type, double_type, zone());
1458 
1459   Type* fround_type = Type::Function(cache_.kAsmFloat, number_type, zone());
1460   Type* imul_type =
1461       Type::Function(cache_.kAsmSigned, cache_.kAsmInt, cache_.kAsmInt, zone());
1462   // TODO(bradnelson): currently only approximating the proper intersection type
1463   // (which we cannot currently represent).
1464   Type* number_fn1_type = Type::Function(number_type, number_type, zone());
1465   Type* number_fn2_type =
1466       Type::Function(number_type, number_type, number_type, zone());
1467 
1468   struct Assignment {
1469     const char* name;
1470     StandardMember standard_member;
1471     Type* type;
1472   };
1473 
1474   const Assignment math[] = {{"PI", kMathPI, double_type},
1475                              {"E", kMathE, double_type},
1476                              {"LN2", kMathLN2, double_type},
1477                              {"LN10", kMathLN10, double_type},
1478                              {"LOG2E", kMathLOG2E, double_type},
1479                              {"LOG10E", kMathLOG10E, double_type},
1480                              {"SQRT2", kMathSQRT2, double_type},
1481                              {"SQRT1_2", kMathSQRT1_2, double_type},
1482                              {"imul", kMathImul, imul_type},
1483                              {"abs", kMathAbs, number_fn1_type},
1484                              {"ceil", kMathCeil, number_fn1_type},
1485                              {"floor", kMathFloor, number_fn1_type},
1486                              {"fround", kMathFround, fround_type},
1487                              {"pow", kMathPow, double_fn2_type},
1488                              {"exp", kMathExp, double_fn1_type},
1489                              {"log", kMathLog, double_fn1_type},
1490                              {"min", kMathMin, number_fn2_type},
1491                              {"max", kMathMax, number_fn2_type},
1492                              {"sqrt", kMathSqrt, number_fn1_type},
1493                              {"cos", kMathCos, double_fn1_type},
1494                              {"sin", kMathSin, double_fn1_type},
1495                              {"tan", kMathTan, double_fn1_type},
1496                              {"acos", kMathAcos, double_fn1_type},
1497                              {"asin", kMathAsin, double_fn1_type},
1498                              {"atan", kMathAtan, double_fn1_type},
1499                              {"atan2", kMathAtan2, double_fn2_type}};
1500   for (unsigned i = 0; i < arraysize(math); ++i) {
1501     stdlib_math_types_[math[i].name] = new (zone()) VariableInfo(math[i].type);
1502     stdlib_math_types_[math[i].name]->standard_member = math[i].standard_member;
1503   }
1504   stdlib_math_types_["fround"]->is_check_function = true;
1505 
1506   stdlib_types_["Infinity"] = new (zone()) VariableInfo(double_type);
1507   stdlib_types_["Infinity"]->standard_member = kInfinity;
1508   stdlib_types_["NaN"] = new (zone()) VariableInfo(double_type);
1509   stdlib_types_["NaN"]->standard_member = kNaN;
1510   Type* buffer_type = Type::Any();
1511 #define TYPED_ARRAY(TypeName, type_name, TYPE_NAME, ctype, size) \
1512   stdlib_types_[#TypeName "Array"] = new (zone()) VariableInfo(  \
1513       Type::Function(cache_.k##TypeName##Array, buffer_type, zone()));
1514   TYPED_ARRAYS(TYPED_ARRAY)
1515 #undef TYPED_ARRAY
1516 
1517 #define TYPED_ARRAY(TypeName, type_name, TYPE_NAME, ctype, size)     \
1518   stdlib_heap_types_[#TypeName "Array"] = new (zone()) VariableInfo( \
1519       Type::Function(cache_.k##TypeName##Array, buffer_type, zone()));
1520   TYPED_ARRAYS(TYPED_ARRAY)
1521 #undef TYPED_ARRAY
1522 }
1523 
1524 
VisitLibraryAccess(ObjectTypeMap * map,Property * expr)1525 void AsmTyper::VisitLibraryAccess(ObjectTypeMap* map, Property* expr) {
1526   Literal* key = expr->key()->AsLiteral();
1527   if (key == nullptr || !key->IsPropertyName())
1528     FAIL(expr, "invalid key used on stdlib member");
1529   Handle<String> name = key->AsPropertyName();
1530   VariableInfo* info = LibType(map, name);
1531   if (info == nullptr || info->type == nullptr)
1532     FAIL(expr, "unknown stdlib function");
1533   SetResult(expr, info->type);
1534   property_info_ = info;
1535 }
1536 
1537 
LibType(ObjectTypeMap * map,Handle<String> name)1538 AsmTyper::VariableInfo* AsmTyper::LibType(ObjectTypeMap* map,
1539                                           Handle<String> name) {
1540   base::SmartArrayPointer<char> aname = name->ToCString();
1541   ObjectTypeMap::iterator i = map->find(std::string(aname.get()));
1542   if (i == map->end()) {
1543     return nullptr;
1544   }
1545   return i->second;
1546 }
1547 
1548 
SetType(Variable * variable,Type * type)1549 void AsmTyper::SetType(Variable* variable, Type* type) {
1550   VariableInfo* info = MakeVariableInfo(variable);
1551   info->type = type;
1552 }
1553 
1554 
GetType(Variable * variable)1555 Type* AsmTyper::GetType(Variable* variable) {
1556   VariableInfo* info = GetVariableInfo(variable);
1557   if (!info) return nullptr;
1558   return info->type;
1559 }
1560 
GetVariableInfo(Variable * variable)1561 AsmTyper::VariableInfo* AsmTyper::GetVariableInfo(Variable* variable) {
1562   ZoneHashMap* map =
1563       in_function_ ? &local_variable_type_ : &global_variable_type_;
1564   ZoneHashMap::Entry* entry =
1565       map->Lookup(variable, ComputePointerHash(variable));
1566   if (!entry && in_function_) {
1567     entry =
1568         global_variable_type_.Lookup(variable, ComputePointerHash(variable));
1569   }
1570   return entry ? reinterpret_cast<VariableInfo*>(entry->value) : nullptr;
1571 }
1572 
MakeVariableInfo(Variable * variable)1573 AsmTyper::VariableInfo* AsmTyper::MakeVariableInfo(Variable* variable) {
1574   ZoneHashMap* map =
1575       in_function_ ? &local_variable_type_ : &global_variable_type_;
1576   ZoneHashMap::Entry* entry = map->LookupOrInsert(
1577       variable, ComputePointerHash(variable), ZoneAllocationPolicy(zone()));
1578   if (!entry->value) entry->value = new (zone()) VariableInfo;
1579   return reinterpret_cast<VariableInfo*>(entry->value);
1580 }
1581 
SetVariableInfo(Variable * variable,const VariableInfo * info)1582 void AsmTyper::SetVariableInfo(Variable* variable, const VariableInfo* info) {
1583   VariableInfo* dest = MakeVariableInfo(variable);
1584   dest->type = info->type;
1585   dest->is_check_function = info->is_check_function;
1586   dest->is_constructor_function = info->is_constructor_function;
1587   dest->standard_member = info->standard_member;
1588 }
1589 
1590 
VariableAsStandardMember(Variable * variable)1591 AsmTyper::StandardMember AsmTyper::VariableAsStandardMember(
1592     Variable* variable) {
1593   VariableInfo* info = GetVariableInfo(variable);
1594   if (!info) return kNone;
1595   return info->standard_member;
1596 }
1597 
1598 
SetResult(Expression * expr,Type * type)1599 void AsmTyper::SetResult(Expression* expr, Type* type) {
1600   computed_type_ = type;
1601   bounds_.set(expr, Bounds(computed_type_));
1602 }
1603 
1604 
IntersectResult(Expression * expr,Type * type)1605 void AsmTyper::IntersectResult(Expression* expr, Type* type) {
1606   computed_type_ = type;
1607   Type* bounded_type = Type::Intersect(computed_type_, expected_type_, zone());
1608   if (Type::Representation(bounded_type, zone())->Is(Type::None())) {
1609 #ifdef DEBUG
1610     PrintF("Computed type: ");
1611     computed_type_->Print();
1612     PrintF("Expected type: ");
1613     expected_type_->Print();
1614 #endif
1615     FAIL(expr, "type mismatch");
1616   }
1617   bounds_.set(expr, Bounds(bounded_type));
1618 }
1619 
1620 
VisitWithExpectation(Expression * expr,Type * expected_type,const char * msg)1621 void AsmTyper::VisitWithExpectation(Expression* expr, Type* expected_type,
1622                                     const char* msg) {
1623   Type* save = expected_type_;
1624   expected_type_ = expected_type;
1625   RECURSE(Visit(expr));
1626   Type* bounded_type = Type::Intersect(computed_type_, expected_type_, zone());
1627   if (Type::Representation(bounded_type, zone())->Is(Type::None())) {
1628 #ifdef DEBUG
1629     PrintF("Computed type: ");
1630     computed_type_->Print();
1631     PrintF("Expected type: ");
1632     expected_type_->Print();
1633 #endif
1634     FAIL(expr, msg);
1635   }
1636   expected_type_ = save;
1637 }
1638 
1639 
VisitRewritableExpression(RewritableExpression * expr)1640 void AsmTyper::VisitRewritableExpression(RewritableExpression* expr) {
1641   RECURSE(Visit(expr->expression()));
1642 }
1643 
1644 
1645 }  // namespace internal
1646 }  // namespace v8
1647