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