Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(375)

Side by Side Diff: src/typing-asm.cc

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

Powered by Google App Engine
This is Rietveld 408576698