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

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

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

Powered by Google App Engine
This is Rietveld 408576698