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

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

Issue 2071343003: V8. ASM-2-WASM. Validator V2. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: moves test-asm-validator to the asmjs cctest folder. 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/asm-typer.h ('k') | src/asmjs/asm-types.h » ('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 2016 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "src/asmjs/asm-typer.h"
6
7 #include <limits>
8 #include <string>
9
10 #include "src/v8.h"
11
12 #include "src/asmjs/asm-types.h"
13 #include "src/ast/ast.h"
14 #include "src/ast/scopes.h"
15 #include "src/base/bits.h"
16 #include "src/codegen.h"
17 #include "src/globals.h"
18 #include "src/type-cache.h"
19 #include "src/utils.h"
20
21 #define FAIL(node, msg) \
22 do { \
23 int line = node->position() == kNoSourcePosition \
24 ? -1 \
25 : script_->GetLineNumber(node->position()); \
26 base::OS::SNPrintF(error_message_, sizeof(error_message_), \
27 "asm: line %d: %s\n", line + 1, msg); \
28 return AsmType::None(); \
29 } while (false)
30
31 #define RECURSE(call) \
32 do { \
33 if (GetCurrentStackPosition() < stack_limit_) { \
34 stack_overflow_ = true; \
35 FAIL(root_, "Stack overflow while parsing asm.js module."); \
36 } \
37 \
38 AsmType* result = (call); \
39 if (stack_overflow_) { \
40 return AsmType::None(); \
41 } \
42 \
43 if (result == AsmType::None()) { \
44 return AsmType::None(); \
45 } \
46 } while (false)
47
48 namespace v8 {
49 namespace internal {
50 namespace wasm {
51
52 using v8::internal::AstNode;
53 using v8::internal::GetCurrentStackPosition;
54
55 // ----------------------------------------------------------------------------
56 // Implementation of AsmTyper::FlattenedStatements
57
58 AsmTyper::FlattenedStatements::FlattenedStatements(Zone* zone,
59 ZoneList<Statement*>* s)
60 : context_stack_(zone) {
61 context_stack_.emplace_back(Context(s));
62 }
63
64 Statement* AsmTyper::FlattenedStatements::Next() {
65 for (;;) {
66 if (context_stack_.empty()) {
67 return nullptr;
68 }
69
70 Context* current = &context_stack_.back();
71
72 if (current->statements_->length() <= current->next_index_) {
73 context_stack_.pop_back();
74 continue;
75 }
76
77 Statement* current_statement =
78 current->statements_->at(current->next_index_++);
79 if (current_statement->IsBlock()) {
80 context_stack_.emplace_back(
81 Context(current_statement->AsBlock()->statements()));
82 continue;
83 }
84
85 return current_statement;
86 }
87 }
88
89 // ----------------------------------------------------------------------------
90 // Implementation of AsmTyper::VariableInfo
91
92 AsmTyper::VariableInfo* AsmTyper::VariableInfo::Clone(Zone* zone) const {
93 CHECK(standard_member_ != kNone);
94 auto* new_var_info = new (zone) VariableInfo(type_);
95 new_var_info->standard_member_ = standard_member_;
96 new_var_info->mutability_ = mutability_;
97 return new_var_info;
98 }
99
100 void AsmTyper::VariableInfo::FirstForwardUseIs(VariableProxy* var) {
101 DCHECK(first_forward_use_ == nullptr);
102 missing_definition_ = true;
103 first_forward_use_ = var;
104 }
105
106 // ----------------------------------------------------------------------------
107 // Implementation of AsmTyper
108
109 AsmTyper::AsmTyper(Isolate* isolate, Zone* zone, Script* script,
110 FunctionLiteral* root)
111 : isolate_(isolate),
112 zone_(zone),
113 script_(script),
114 root_(root),
115 forward_definitions_(zone),
116 stdlib_types_(zone),
117 stdlib_math_types_(zone),
118 global_scope_(ZoneHashMap::PointersMatch,
119 ZoneHashMap::kDefaultHashMapCapacity,
120 ZoneAllocationPolicy(zone)),
121 local_scope_(ZoneHashMap::PointersMatch,
122 ZoneHashMap::kDefaultHashMapCapacity,
123 ZoneAllocationPolicy(zone)),
124 stack_limit_(isolate->stack_guard()->real_climit()),
125 node_types_(zone_) {
126 InitializeStdlib();
127 module_info_.set_standard_member(kModule);
128 }
129
130 namespace {
131 bool ValidAsmIdentifier(Handle<String> name) {
132 static const char* kInvalidAsmNames[] = {"eval", "arguments"};
133
134 for (size_t ii = 0; ii < arraysize(kInvalidAsmNames); ++ii) {
135 if (strcmp(name->ToCString().get(), kInvalidAsmNames[ii]) == 0) {
136 return false;
137 }
138 }
139 return true;
140 }
141 } // namespace
142
143 void AsmTyper::InitializeStdlib() {
144 auto* d = AsmType::Double();
145 auto* dq = AsmType::DoubleQ();
146 auto* dq2d = AsmType::Function(zone_, d);
147 dq2d->AsFunctionType()->AddArgument(dq);
148
149 auto* dqdq2d = AsmType::Function(zone_, d);
150 dqdq2d->AsFunctionType()->AddArgument(dq);
151 dqdq2d->AsFunctionType()->AddArgument(dq);
152
153 auto* f = AsmType::Float();
154 auto* fq = AsmType::FloatQ();
155 auto* fq2f = AsmType::Function(zone_, f);
156 fq2f->AsFunctionType()->AddArgument(fq);
157
158 auto* s = AsmType::Signed();
159 auto* s2s = AsmType::Function(zone_, s);
160 s2s->AsFunctionType()->AddArgument(s);
161
162 auto* i = AsmType::Int();
163 auto* ii2s = AsmType::Function(zone_, s);
164 ii2s->AsFunctionType()->AddArgument(i);
165 ii2s->AsFunctionType()->AddArgument(i);
166
167 auto* minmax_d = AsmType::MinMaxType(zone_, d, d);
168 auto* minmax_i = AsmType::MinMaxType(zone_, s, i);
169 auto* minmax = AsmType::OverloadedFunction(zone_);
170 minmax->AsOverloadedFunctionType()->AddOverload(minmax_i);
171 minmax->AsOverloadedFunctionType()->AddOverload(minmax_d);
172
173 auto* fround = AsmType::FroundType(zone_);
174
175 auto* abs = AsmType::OverloadedFunction(zone_);
176 abs->AsOverloadedFunctionType()->AddOverload(s2s);
177 abs->AsOverloadedFunctionType()->AddOverload(dq2d);
178 abs->AsOverloadedFunctionType()->AddOverload(fq2f);
179
180 auto* ceil = AsmType::OverloadedFunction(zone_);
181 ceil->AsOverloadedFunctionType()->AddOverload(dq2d);
182 ceil->AsOverloadedFunctionType()->AddOverload(fq2f);
183
184 auto* floor = ceil;
185 auto* sqrt = ceil;
186
187 struct StandardMemberInitializer {
188 const char* name;
189 StandardMember standard_member;
190 AsmType* type;
191 };
192
193 const StandardMemberInitializer stdlib[] = {{"Infinity", kInfinity, d},
194 {"NaN", kNaN, d},
195 #define asm_TYPED_ARRAYS(V) \
196 V(Uint8) \
197 V(Int8) \
198 V(Uint16) \
199 V(Int16) \
200 V(Uint32) \
201 V(Int32) \
202 V(Float32) \
203 V(Float64)
204
205 #define asm_TYPED_ARRAY(TypeName) \
206 {#TypeName "Array", kNone, AsmType::TypeName##Array()},
207 asm_TYPED_ARRAYS(asm_TYPED_ARRAY)
208 #undef asm_TYPED_ARRAY
209 };
210 for (size_t ii = 0; ii < arraysize(stdlib); ++ii) {
211 stdlib_types_[stdlib[ii].name] = new (zone_) VariableInfo(stdlib[ii].type);
212 stdlib_types_[stdlib[ii].name]->set_standard_member(
213 stdlib[ii].standard_member);
214 stdlib_types_[stdlib[ii].name]->set_mutability(
215 VariableInfo::kImmutableGlobal);
216 }
217
218 const StandardMemberInitializer math[] = {
219 {"PI", kMathPI, d},
220 {"E", kMathE, d},
221 {"LN2", kMathLN2, d},
222 {"LN10", kMathLN10, d},
223 {"LOG2E", kMathLOG2E, d},
224 {"LOG10E", kMathLOG10E, d},
225 {"SQRT2", kMathSQRT2, d},
226 {"SQRT1_2", kMathSQRT1_2, d},
227 {"imul", kMathImul, ii2s},
228 {"abs", kMathAbs, abs},
229 {"ceil", kMathCeil, ceil},
230 {"floor", kMathFloor, floor},
231 {"fround", kMathFround, fround},
232 {"pow", kMathPow, dqdq2d},
233 {"exp", kMathExp, dq2d},
234 {"log", kMathLog, dq2d},
235 {"min", kMathMin, minmax},
236 {"max", kMathMax, minmax},
237 {"sqrt", kMathSqrt, sqrt},
238 {"cos", kMathCos, dq2d},
239 {"sin", kMathSin, dq2d},
240 {"tan", kMathTan, dq2d},
241 {"acos", kMathAcos, dq2d},
242 {"asin", kMathAsin, dq2d},
243 {"atan", kMathAtan, dq2d},
244 {"atan2", kMathAtan2, dqdq2d},
245 };
246 for (size_t ii = 0; ii < arraysize(math); ++ii) {
247 stdlib_math_types_[math[ii].name] = new (zone_) VariableInfo(math[ii].type);
248 stdlib_math_types_[math[ii].name]->set_standard_member(
249 math[ii].standard_member);
250 stdlib_math_types_[math[ii].name]->set_mutability(
251 VariableInfo::kImmutableGlobal);
252 }
253 }
254
255 // Used for 5.5 GlobalVariableTypeAnnotations
256 AsmTyper::VariableInfo* AsmTyper::ImportLookup(Property* import) {
257 auto* obj = import->obj();
258 auto* key = import->key()->AsLiteral();
259
260 ObjectTypeMap* stdlib = &stdlib_types_;
261 if (auto* obj_as_property = obj->AsProperty()) {
262 // This can only be stdlib.Math
263 auto* math_name = obj_as_property->key()->AsLiteral();
264 if (math_name == nullptr || !math_name->IsPropertyName()) {
265 return nullptr;
266 }
267
268 if (!math_name->AsPropertyName()->IsUtf8EqualTo(CStrVector("Math"))) {
269 return nullptr;
270 }
271
272 auto* stdlib_var_proxy = obj_as_property->obj()->AsVariableProxy();
273 if (stdlib_var_proxy == nullptr) {
274 return nullptr;
275 }
276 obj = stdlib_var_proxy;
277 stdlib = &stdlib_math_types_;
278 }
279
280 auto* obj_as_var_proxy = obj->AsVariableProxy();
281 if (obj_as_var_proxy == nullptr) {
282 return nullptr;
283 }
284
285 auto* obj_info = Lookup(obj_as_var_proxy->var());
286 if (obj_info == nullptr) {
287 return nullptr;
288 }
289
290 if (obj_info->IsFFI()) {
291 // For FFI we can't validate import->key, so assume this is OK.
292 return obj_info;
293 }
294
295 base::SmartArrayPointer<char> aname = key->AsPropertyName()->ToCString();
296 ObjectTypeMap::iterator i = stdlib->find(std::string(aname.get()));
297 if (i == stdlib->end()) {
298 return nullptr;
299 }
300 return i->second;
301 }
302
303 AsmTyper::VariableInfo* AsmTyper::Lookup(Variable* variable) {
304 ZoneHashMap* scope = in_function_ ? &local_scope_ : &global_scope_;
305 ZoneHashMap::Entry* entry =
306 scope->Lookup(variable, ComputePointerHash(variable));
307 if (entry == nullptr && in_function_) {
308 entry = global_scope_.Lookup(variable, ComputePointerHash(variable));
309 }
310
311 if (entry == nullptr && !module_name_.is_null() &&
312 module_name_->Equals(*variable->name())) {
313 return &module_info_;
314 }
315
316 return entry ? reinterpret_cast<VariableInfo*>(entry->value) : nullptr;
317 }
318
319 void AsmTyper::AddForwardReference(VariableProxy* proxy, VariableInfo* info) {
320 info->FirstForwardUseIs(proxy);
321 forward_definitions_.push_back(info);
322 }
323
324 bool AsmTyper::AddGlobal(Variable* variable, VariableInfo* info) {
325 // We can't DCHECK(!in_function_) because function may actually install global
326 // names (forward defined functions and function tables.)
327 DCHECK(info->mutability() != VariableInfo::kInvalidMutability);
328 DCHECK(info->IsGlobal());
329 DCHECK(ValidAsmIdentifier(variable->name()));
330
331 if (!module_name_.is_null() && module_name_->Equals(*variable->name())) {
332 return false;
333 }
334
335 ZoneHashMap::Entry* entry = global_scope_.LookupOrInsert(
336 variable, ComputePointerHash(variable), ZoneAllocationPolicy(zone_));
337
338 if (entry->value != nullptr) {
339 return false;
340 }
341
342 entry->value = info;
343 return true;
344 }
345
346 bool AsmTyper::AddLocal(Variable* variable, VariableInfo* info) {
347 DCHECK(in_function_);
348 DCHECK(info->mutability() != VariableInfo::kInvalidMutability);
349 DCHECK(!info->IsGlobal());
350 DCHECK(ValidAsmIdentifier(variable->name()));
351
352 ZoneHashMap::Entry* entry = local_scope_.LookupOrInsert(
353 variable, ComputePointerHash(variable), ZoneAllocationPolicy(zone_));
354
355 if (entry->value != nullptr) {
356 return false;
357 }
358
359 entry->value = info;
360 return true;
361 }
362
363 void AsmTyper::SetTypeOf(AstNode* node, AsmType* type) {
364 DCHECK_NE(type, AsmType::None());
365 auto** node_type = &node_types_[node];
366 DCHECK(*node_type == nullptr);
367 *node_type = type;
368 }
369
370 AsmType* AsmTyper::TypeOf(AstNode* node) const {
371 auto node_type_iter = node_types_.find(node);
372 if (node_type_iter == node_types_.end()) {
373 return AsmType::None();
374 }
375 return node_type_iter->second;
376 }
377
378 AsmTyper::StandardMember AsmTyper::VariableAsStandardMember(Variable* var) {
379 auto* var_info = Lookup(var);
380 if (var_info == nullptr) {
381 return kNone;
382 }
383 return var_info->standard_member();
384 }
385
386 bool AsmTyper::Validate() {
387 if (!AsmType::None()->IsExactly(ValidateModule(root_))) {
388 return true;
389 }
390 return false;
391 }
392
393 namespace {
394 bool IsUseAsmDirective(Statement* first_statement) {
395 ExpressionStatement* use_asm = first_statement->AsExpressionStatement();
396 if (use_asm == nullptr) {
397 return false;
398 }
399
400 Literal* use_asm_literal = use_asm->expression()->AsLiteral();
401
402 if (use_asm_literal == nullptr) {
403 return false;
404 }
405
406 return use_asm_literal->raw_value()->AsString()->IsOneByteEqualTo("use asm");
407 }
408
409 Assignment* ExtractInitializerExpression(Statement* statement) {
410 auto* expr_stmt = statement->AsExpressionStatement();
411 if (expr_stmt == nullptr) {
412 // Done with initializers.
413 return nullptr;
414 }
415 auto* assign = expr_stmt->expression()->AsAssignment();
416 if (assign == nullptr) {
417 // Done with initializers.
418 return nullptr;
419 }
420 if (assign->op() != Token::INIT) {
421 // Done with initializers.
422 return nullptr;
423 }
424 return assign;
425 }
426
427 } // namespace
428
429 // 6.1 ValidateModule
430 AsmType* AsmTyper::ValidateModule(FunctionLiteral* fun) {
431 Scope* scope = fun->scope();
432 if (!scope->is_function_scope()) FAIL(fun, "Not at function scope.");
433 if (!ValidAsmIdentifier(fun->name()))
434 FAIL(fun, "Invalid asm.js identifier in module name.");
435 module_name_ = fun->name();
436
437 // Allowed parameters: Stdlib, FFI, Mem
438 static const uint32_t MaxModuleParameters = 3;
439 if (scope->num_parameters() > MaxModuleParameters) {
440 FAIL(fun, "asm.js modules may not have more than three parameters.");
441 }
442
443 struct {
444 StandardMember standard_member;
445 AsmType* type;
446 } kModuleParamInfo[3] = {
447 {kStdlib, AsmType::None()},
448 {kFFI, AsmType::FFIType(zone_)},
449 {kHeap, AsmType::None()},
450 };
451
452 for (int ii = 0; ii < scope->num_parameters(); ++ii) {
453 Variable* param = scope->parameter(ii);
454 DCHECK(param);
455
456 if (!ValidAsmIdentifier(param->name())) {
457 FAIL(fun, "Invalid asm.js identifier in module parameter.");
458 }
459
460 auto* param_info = new (zone_) VariableInfo();
461 param_info->set_mutability(VariableInfo::kImmutableGlobal);
462 param_info->set_standard_member(kModuleParamInfo[ii].standard_member);
463 param_info->set_type(kModuleParamInfo[ii].type);
464
465 if (!AddGlobal(param, param_info)) {
466 FAIL(fun, "Redeclared identifier in module parameter.");
467 }
468 }
469
470 ZoneVector<Assignment*> function_pointer_tables(zone_);
471 FlattenedStatements iter(zone_, fun->body());
472 auto* use_asm_directive = iter.Next();
473 if (use_asm_directive == nullptr || !IsUseAsmDirective(use_asm_directive)) {
474 FAIL(fun, "Missing \"use asm\".");
475 }
476 ReturnStatement* module_return = nullptr;
477
478 // *VIOLATION* The spec states that globals should be followed by function
479 // declarations, which should be followed by function pointer tables, followed
480 // by the module export (return) statement. Our AST might be rearraged by the
481 // parser, so we can't rely on it being in source code order.
482 while (Statement* current = iter.Next()) {
483 if (auto* assign = ExtractInitializerExpression(current)) {
484 if (assign->value()->IsArrayLiteral()) {
485 // Save function tables for later validation.
486 function_pointer_tables.push_back(assign);
487 } else {
488 RECURSE(ValidateGlobalDeclaration(assign));
489 }
490 continue;
491 }
492
493 if (auto* current_as_return = current->AsReturnStatement()) {
494 if (module_return != nullptr) {
495 FAIL(fun, "Multiple export statements.");
496 }
497 module_return = current_as_return;
498 continue;
499 }
500
501 FAIL(current, "Invalid top-level statement in asm.js module.");
502 }
503
504 ZoneList<Declaration*>* decls = scope->declarations();
505
506 for (int ii = 0; ii < decls->length(); ++ii) {
507 Declaration* decl = decls->at(ii);
508
509 if (FunctionDeclaration* fun_decl = decl->AsFunctionDeclaration()) {
510 RECURSE(ValidateFunction(fun_decl));
511 continue;
512 }
513 }
514
515 for (auto* function_table : function_pointer_tables) {
516 RECURSE(ValidateFunctionTable(function_table));
517 }
518
519 for (int ii = 0; ii < decls->length(); ++ii) {
520 Declaration* decl = decls->at(ii);
521
522 if (decl->IsFunctionDeclaration()) {
523 continue;
524 }
525
526 VariableDeclaration* var_decl = decl->AsVariableDeclaration();
527 if (var_decl == nullptr) {
528 FAIL(decl, "Invalid asm.js declaration.");
529 }
530
531 auto* var_proxy = var_decl->proxy();
532 if (var_proxy == nullptr) {
533 FAIL(decl, "Invalid asm.js declaration.");
534 }
535
536 if (Lookup(var_proxy->var()) == nullptr) {
537 FAIL(decl, "Global variable missing initializer in asm.js module.");
538 }
539 }
540
541 // 6.2 ValidateExport
542 if (module_return == nullptr) {
543 FAIL(fun, "Missing asm.js module export.");
544 }
545
546 for (auto* forward_def : forward_definitions_) {
547 if (forward_def->missing_definition()) {
548 FAIL(forward_def->first_forward_use(),
549 "Missing definition for forward declared identifier.");
550 }
551 }
552
553 RECURSE(ValidateExport(module_return));
554
555 return AsmType::Int(); // Any type that is not AsmType::None();
556 }
557
558 namespace {
559 bool IsDoubleAnnotation(BinaryOperation* binop) {
560 // *VIOLATION* The parser replaces uses of +x with x*1.0.
561 if (binop->op() != Token::MUL) {
562 return false;
563 }
564
565 auto* right_as_literal = binop->right()->AsLiteral();
566 if (right_as_literal == nullptr) {
567 return false;
568 }
569
570 return right_as_literal->raw_value()->ContainsDot() &&
571 right_as_literal->raw_value()->AsNumber() == 1.0;
572 }
573
574 bool IsIntAnnotation(BinaryOperation* binop) {
575 if (binop->op() != Token::BIT_OR) {
576 return false;
577 }
578
579 auto* right_as_literal = binop->right()->AsLiteral();
580 if (right_as_literal == nullptr) {
581 return false;
582 }
583
584 return !right_as_literal->raw_value()->ContainsDot() &&
585 right_as_literal->raw_value()->AsNumber() == 0.0;
586 }
587 } // namespace
588
589 AsmType* AsmTyper::ValidateGlobalDeclaration(Assignment* assign) {
590 DCHECK(!assign->is_compound());
591 if (assign->is_compound()) {
592 FAIL(assign,
593 "Compound assignment not supported when declaring global variables.");
594 }
595
596 auto* target = assign->target();
597 if (!target->IsVariableProxy()) {
598 FAIL(target, "Module assignments may only assign to globals.");
599 }
600 auto* target_variable = target->AsVariableProxy()->var();
601 auto* target_info = Lookup(target_variable);
602
603 if (target_info != nullptr) {
604 FAIL(target, "Redefined global variable.");
605 }
606
607 auto* value = assign->value();
608 // Not all types of assignment are allowed by asm.js. See
609 // 5.5 Global Variable Type Annotations.
610 if (value->IsLiteral() || value->IsCall()) {
611 AsmType* type = nullptr;
612 RECURSE(type = VariableTypeAnnotations(value));
613 target_info = new (zone_) VariableInfo(type);
614 target_info->set_mutability(VariableInfo::kMutableGlobal);
615 } else if (value->IsProperty()) {
616 target_info = ImportLookup(value->AsProperty());
617 if (target_info == nullptr) {
618 FAIL(assign, "Invalid import.");
619 }
620 CHECK(target_info->mutability() == VariableInfo::kImmutableGlobal);
621 if (!target_info->IsFFI()) {
622 target_info = target_info->Clone(zone_);
623 } else {
624 // create a new target info that represents a foreign variable.
625 DCHECK(target_info->type()->AsFFIType() != nullptr);
626 target_info = new (zone_) VariableInfo(target_info->type());
627 target_info->set_mutability(VariableInfo::kImmutableGlobal);
628 }
629 } else if (value->IsBinaryOperation()) {
630 // This should either be:
631 //
632 // var <> = ffi.<>|0
633 //
634 // or
635 //
636 // var <> = +ffi.<>
637 auto* value_binop = value->AsBinaryOperation();
638 auto* left = value_binop->left();
639 AsmType* import_type = nullptr;
640
641 if (IsDoubleAnnotation(value_binop)) {
642 import_type = AsmType::Double();
643 } else if (IsIntAnnotation(value_binop)) {
644 import_type = AsmType::Int();
645 } else {
646 FAIL(value,
647 "Invalid initializer for foreign import - unrecognized annotation.");
648 }
649
650 if (!left->IsProperty()) {
651 FAIL(value,
652 "Invalid initializer for foreign import - must import member.");
653 }
654 target_info = ImportLookup(left->AsProperty());
655 if (target_info == nullptr) {
656 // TODO(jpp): this error message is innacurate: this may fail if the
657 // object lookup fails, or if the property lookup fails, or even if the
658 // import is bogus like a().c.
659 FAIL(value,
660 "Invalid initializer for foreign import - object lookup failed.");
661 }
662 CHECK(target_info->mutability() == VariableInfo::kImmutableGlobal);
663 if (!target_info->IsFFI()) {
664 FAIL(value,
665 "Invalid initializer for foreign import - object is not the ffi.");
666 }
667
668 // Create a new target info that represents the foreign import.
669 DCHECK(target_info->type()->AsFFIType() != nullptr);
670 target_info = new (zone_) VariableInfo(import_type);
671 target_info->set_mutability(VariableInfo::kMutableGlobal);
672 } else if (value->IsCallNew()) {
673 AsmType* type = nullptr;
674 RECURSE(type = NewHeapView(value->AsCallNew()));
675 target_info = new (zone_) VariableInfo(type);
676 target_info->set_mutability(VariableInfo::kImmutableGlobal);
677 }
678
679 if (target_info == nullptr) {
680 FAIL(assign, "Invalid global variable initializer.");
681 }
682
683 if (!ValidAsmIdentifier(target_variable->name())) {
684 FAIL(target, "Invalid asm.js identifier in global variable.");
685 }
686
687 if (!AddGlobal(target_variable, target_info)) {
688 FAIL(assign, "Redeclared global identifier.");
689 }
690
691 DCHECK(target_info->type() != AsmType::None());
692 return target_info->type();
693 }
694
695 // 6.2 ValidateExport
696 AsmType* AsmTyper::ExportType(VariableProxy* fun_export) {
697 auto* fun_info = Lookup(fun_export->var());
698 if (fun_info == nullptr) {
699 FAIL(fun_export, "Undefined identifier in asm.js module export.");
700 }
701
702 if (fun_info->standard_member() != kNone) {
703 FAIL(fun_export, "Module cannot export standard library functions.");
704 }
705
706 auto* type = fun_info->type();
707 if (type->AsFFIType() != nullptr) {
708 FAIL(fun_export, "Module cannot export foreign functions.");
709 }
710
711 if (type->AsFunctionTableType() != nullptr) {
712 FAIL(fun_export, "Module cannot export function tables.");
713 }
714
715 if (fun_info->type()->AsFunctionType() == nullptr) {
716 FAIL(fun_export, "Module export is not an asm.js function.");
717 }
718
719 return type;
720 }
721
722 AsmType* AsmTyper::ValidateExport(ReturnStatement* exports) {
723 // asm.js modules can export single functions, or multiple functions in an
724 // object literal.
725 if (auto* fun_export = exports->expression()->AsVariableProxy()) {
726 // Exporting single function.
727 AsmType* export_type;
728 RECURSE(export_type = ExportType(fun_export));
729 return export_type;
730 }
731
732 if (auto* obj_export = exports->expression()->AsObjectLiteral()) {
733 // Exporting object literal.
734 for (auto* prop : *obj_export->properties()) {
735 if (!prop->key()->IsLiteral()) {
736 FAIL(prop->key(),
737 "Only normal object properties may be used in the export object "
738 "literal.");
739 }
740
741 auto* export_obj = prop->value()->AsVariableProxy();
742 if (export_obj == nullptr) {
743 FAIL(prop->value(), "Exported value must be an asm.js function name.");
744 }
745
746 RECURSE(ExportType(export_obj));
747 }
748
749 return AsmType::Int();
750 }
751
752 FAIL(exports, "Unrecognized expression in asm.js module export expression.");
753 }
754
755 // 6.3 ValidateFunctionTable
756 AsmType* AsmTyper::ValidateFunctionTable(Assignment* assign) {
757 if (assign->is_compound()) {
758 FAIL(assign,
759 "Compound assignment not supported when declaring global variables.");
760 }
761
762 auto* target = assign->target();
763 if (!target->IsVariableProxy()) {
764 FAIL(target, "Module assignments may only assign to globals.");
765 }
766 auto* target_variable = target->AsVariableProxy()->var();
767
768 auto* value = assign->value()->AsArrayLiteral();
769 CHECK(value != nullptr);
770 ZoneList<Expression*>* pointers = value->values();
771
772 // The function table size must be n = 2 ** m, for m >= 0;
773 // TODO(jpp): should this be capped?
774 if (!base::bits::IsPowerOfTwo32(pointers->length())) {
775 FAIL(assign, "Invalid length for function pointer table.");
776 }
777
778 AsmType* table_element_type = nullptr;
779 AsmCallableType* callable_type = nullptr;
780 for (auto* initializer : *pointers) {
781 auto* var_proxy = initializer->AsVariableProxy();
782 if (var_proxy == nullptr) {
783 FAIL(initializer,
784 "Function pointer table initializer must be a function name.");
785 }
786
787 auto* var_info = Lookup(var_proxy->var());
788 if (var_info == nullptr) {
789 FAIL(var_proxy,
790 "Undefined identifier in function pointer table initializer.");
791 }
792
793 if (var_info->standard_member() != kNone) {
794 FAIL(initializer,
795 "Function pointer table must not be a member of the standard "
796 "library.");
797 }
798
799 auto* initializer_callable = var_info->type()->AsFunctionType();
800 if (initializer_callable == nullptr) {
801 FAIL(initializer,
802 "Function pointer table initializer must be an asm.js function.");
803 }
804
805 DCHECK(var_info->type()->AsFFIType() == nullptr);
806 DCHECK(var_info->type()->AsFunctionTableType() == nullptr);
807
808 if (callable_type == nullptr) {
809 table_element_type = var_info->type();
810 callable_type = initializer_callable;
811 } else if (callable_type->ValidateCall(initializer_callable->ReturnType(),
812 initializer_callable->Arguments()) ==
813 AsmType::None()) {
814 FAIL(initializer, "Type mismatch in function pointer table initializer.");
815 }
816 }
817
818 auto* target_info = Lookup(target_variable);
819 if (target_info == nullptr) {
820 // Function pointer tables are the last entities to be validates, so this is
821 // unlikely to happen: only unreferenced function tables will not already
822 // have an entry in the global scope.
823 target_info = new (zone_) VariableInfo(AsmType::FunctionTableType(
824 zone_, pointers->length(), table_element_type));
825 target_info->set_mutability(VariableInfo::kImmutableGlobal);
826 if (!ValidAsmIdentifier(target_variable->name())) {
827 FAIL(target, "Invalid asm.js identifier in function table name.");
828 }
829 if (!AddGlobal(target_variable, target_info)) {
830 DCHECK(false);
831 FAIL(assign, "Redeclared global identifier in function table name.");
832 }
833 return target_info->type();
834 }
835
836 auto* target_info_table = target_info->type()->AsFunctionTableType();
837 if (target_info_table == nullptr) {
838 FAIL(assign, "Identifier redefined as function pointer table.");
839 }
840
841 if (!target_info->missing_definition()) {
842 FAIL(assign, "Identifier redefined (function table name).");
843 }
844
845 if (target_info_table->length() != pointers->length()) {
846 FAIL(assign, "Function table size mismatch.");
847 }
848
849 auto* function_type = callable_type->AsFunctionType();
850 if (target_info_table->ValidateCall(function_type->ReturnType(),
851 function_type->Arguments()) ==
852 AsmType::None()) {
853 FAIL(assign, "Function table initializer does not match previous type.");
854 }
855
856 target_info->MarkDefined();
857 DCHECK(target_info->type() == AsmType::None());
858 SetTypeOf(value, target_info->type());
859
860 return target_info->type();
861 }
862
863 // 6.4 ValidateFunction
864 AsmType* AsmTyper::ValidateFunction(FunctionDeclaration* fun_decl) {
865 FunctionScope _(this);
866
867 // Extract parameter types.
868 auto* fun = fun_decl->fun();
869
870 auto* fun_decl_proxy = fun_decl->proxy();
871 if (fun_decl_proxy == nullptr) {
872 FAIL(fun_decl, "Anonymous functions are not support in asm.js.");
873 }
874
875 Statement* current;
876 FlattenedStatements iter(zone_, fun->body());
877
878 size_t annotated_parameters = 0;
879
880 // 5.3 Function type annotations
881 // * parameters
882 ZoneVector<AsmType*> parameter_types(zone_);
883 for (; (current = iter.Next()) != nullptr; ++annotated_parameters) {
884 auto* stmt = current->AsExpressionStatement();
885 if (stmt == nullptr) {
886 // Done with parameters.
887 break;
888 }
889 auto* expr = stmt->expression()->AsAssignment();
890 if (expr == nullptr || expr->is_compound()) {
891 // Done with parameters.
892 break;
893 }
894 auto* proxy = expr->target()->AsVariableProxy();
895 if (proxy == nullptr) {
896 // Done with parameters.
897 break;
898 }
899 auto* param = proxy->var();
900 if (param->location() != VariableLocation::PARAMETER ||
901 param->index() != annotated_parameters) {
902 // Done with parameters.
903 break;
904 }
905
906 AsmType* type;
907 RECURSE(type = ParameterTypeAnnotations(param, expr->value()));
908 DCHECK(type->IsParameterType());
909 auto* param_info = new (zone_) VariableInfo(type);
910 param_info->set_mutability(VariableInfo::kLocal);
911 if (!ValidAsmIdentifier(proxy->name())) {
912 FAIL(proxy, "Invalid asm.js identifier in parameter name.");
913 }
914
915 if (!AddLocal(param, param_info)) {
916 FAIL(proxy, "Redeclared parameter.");
917 }
918 parameter_types.push_back(type);
919 }
920
921 if (annotated_parameters != fun->parameter_count()) {
922 FAIL(fun_decl, "Incorrect parameter type annotations.");
923 }
924
925 // 5.3 Function type annotations
926 // * locals
927 for (; current; current = iter.Next()) {
928 auto* initializer = ExtractInitializerExpression(current);
929 if (initializer == nullptr) {
930 // Done with locals.
931 break;
932 }
933
934 auto* local = initializer->target()->AsVariableProxy();
935 if (local == nullptr) {
936 // Done with locals. It should never happen. Even if it does, the asm.js
937 // code should not declare any other locals after this point, so we assume
938 // this is OK. If any other variable declaration is found we report a
939 // validation error.
940 DCHECK(false);
941 break;
942 }
943
944 AsmType* type;
945 RECURSE(type = VariableTypeAnnotations(initializer->value()));
946 auto* local_info = new (zone_) VariableInfo(type);
947 local_info->set_mutability(VariableInfo::kLocal);
948 if (!ValidAsmIdentifier(local->name())) {
949 FAIL(local, "Invalid asm.js identifier in local variable.");
950 }
951
952 if (!AddLocal(local->var(), local_info)) {
953 FAIL(initializer, "Redeclared local.");
954 }
955 }
956
957 // 5.2 Return Type Annotations
958 // *VIOLATION* we peel blocks to find the last statement in the asm module
959 // because the parser may introduce synthetic blocks.
960 ZoneList<Statement*>* statements = fun->body();
961
962 do {
963 if (statements->length() == 0) {
964 return_type_ = AsmType::Void();
965 } else {
966 auto* last_statement = statements->last();
967 auto* as_block = last_statement->AsBlock();
968 if (as_block != nullptr) {
969 statements = as_block->statements();
970 } else {
971 // We don't check whether AsReturnStatement() below returns non-null --
972 // we leave that to the ReturnTypeAnnotations method.
973 RECURSE(return_type_ =
974 ReturnTypeAnnotations(last_statement->AsReturnStatement()));
975 }
976 }
977 } while (return_type_ == AsmType::None());
978
979 DCHECK(return_type_->IsReturnType());
980
981 for (auto* decl : *fun->scope()->declarations()) {
982 auto* var_decl = decl->AsVariableDeclaration();
983 if (var_decl == nullptr) {
984 FAIL(decl, "Functions may only define inner variables.");
985 }
986
987 auto* var_proxy = var_decl->proxy();
988 if (var_proxy == nullptr) {
989 FAIL(decl, "Invalid local declaration declaration.");
990 }
991
992 auto* var_info = Lookup(var_proxy->var());
993 if (var_info == nullptr || var_info->IsGlobal()) {
994 FAIL(decl, "Local variable missing initializer in asm.js module.");
995 }
996 }
997
998 for (; current; current = iter.Next()) {
999 AsmType* current_type;
1000 RECURSE(current_type = ValidateStatement(current));
1001 }
1002
1003 auto* fun_type = AsmType::Function(zone_, return_type_);
1004 auto* fun_type_as_function = fun_type->AsFunctionType();
1005 for (auto* param_type : parameter_types) {
1006 fun_type_as_function->AddArgument(param_type);
1007 }
1008
1009 auto* fun_var = fun_decl_proxy->var();
1010 auto* fun_info = new (zone_) VariableInfo(fun_type);
1011 fun_info->set_mutability(VariableInfo::kImmutableGlobal);
1012 auto* old_fun_type = Lookup(fun_var);
1013 if (old_fun_type == nullptr) {
1014 if (!ValidAsmIdentifier(fun_var->name())) {
1015 FAIL(fun_decl_proxy, "Invalid asm.js identifier in function name.");
1016 }
1017 if (!AddGlobal(fun_var, fun_info)) {
1018 DCHECK(false);
1019 FAIL(fun_decl, "Redeclared global identifier.");
1020 }
1021 return fun_type;
1022 }
1023
1024 // Not necessarily an error -- fun_decl might have been used before being
1025 // defined. If that's the case, then the type in the global environment must
1026 // be the same as the type inferred by the parameter/return type annotations.
1027 auto* old_fun_callable = old_fun_type->type()->AsCallableType();
1028 if (old_fun_callable == nullptr) {
1029 FAIL(fun_decl, "Identifier redefined as function.");
1030 }
1031
1032 if (!old_fun_type->missing_definition()) {
1033 FAIL(fun_decl, "Identifier redefined (function name).");
1034 }
1035
1036 if (old_fun_callable->ValidateCall(fun_type_as_function->ReturnType(),
1037 fun_type_as_function->Arguments()) ==
1038 AsmType::None()) {
1039 FAIL(fun_decl, "Signature mismatch when defining function.");
1040 }
1041
1042 old_fun_type->MarkDefined();
1043 SetTypeOf(fun, fun_type);
1044
1045 return fun_type;
1046 }
1047
1048 // 6.5 ValidateStatement
1049 AsmType* AsmTyper::ValidateStatement(Statement* statement) {
1050 switch (statement->node_type()) {
1051 default:
1052 FAIL(statement, "Statement type invalid for asm.js.");
1053 case AstNode::kBlock:
1054 return ValidateBlockStatement(statement->AsBlock());
1055 case AstNode::kExpressionStatement:
1056 return ValidateExpressionStatement(statement->AsExpressionStatement());
1057 case AstNode::kEmptyStatement:
1058 return ValidateEmptyStatement(statement->AsEmptyStatement());
1059 case AstNode::kIfStatement:
1060 return ValidateIfStatement(statement->AsIfStatement());
1061 case AstNode::kReturnStatement:
1062 return ValidateReturnStatement(statement->AsReturnStatement());
1063 case AstNode::kWhileStatement:
1064 return ValidateWhileStatement(statement->AsWhileStatement());
1065 case AstNode::kDoWhileStatement:
1066 return ValidateDoWhileStatement(statement->AsDoWhileStatement());
1067 case AstNode::kForStatement:
1068 return ValidateForStatement(statement->AsForStatement());
1069 case AstNode::kBreakStatement:
1070 return ValidateBreakStatement(statement->AsBreakStatement());
1071 case AstNode::kContinueStatement:
1072 return ValidateContinueStatement(statement->AsContinueStatement());
1073 case AstNode::kSwitchStatement:
1074 return ValidateSwitchStatement(statement->AsSwitchStatement());
1075 }
1076
1077 return AsmType::Void();
1078 }
1079
1080 // 6.5.1 BlockStatement
1081 AsmType* AsmTyper::ValidateBlockStatement(Block* block) {
1082 FlattenedStatements iter(zone_, block->statements());
1083
1084 while (auto* current = iter.Next()) {
1085 RECURSE(ValidateStatement(current));
1086 }
1087
1088 return AsmType::Void();
1089 }
1090
1091 // 6.5.2 ExpressionStatement
1092 AsmType* AsmTyper::ValidateExpressionStatement(ExpressionStatement* expr) {
1093 auto* expression = expr->expression();
1094 if (auto* call = expression->AsCall()) {
1095 RECURSE(ValidateCall(AsmType::Void(), call));
1096 } else {
1097 RECURSE(ValidateExpression(expression));
1098 }
1099
1100 return AsmType::Void();
1101 }
1102
1103 // 6.5.3 EmptyStatement
1104 AsmType* AsmTyper::ValidateEmptyStatement(EmptyStatement* empty) {
1105 return AsmType::Void();
1106 }
1107
1108 // 6.5.4 IfStatement
1109 AsmType* AsmTyper::ValidateIfStatement(IfStatement* if_stmt) {
1110 AsmType* cond_type;
1111 RECURSE(cond_type = ValidateExpression(if_stmt->condition()));
1112 if (!cond_type->IsA(AsmType::Int())) {
1113 FAIL(if_stmt->condition(), "If condition must be type int.");
1114 }
1115 RECURSE(ValidateStatement(if_stmt->then_statement()));
1116 RECURSE(ValidateStatement(if_stmt->else_statement()));
1117 return AsmType::Void();
1118 }
1119
1120 // 6.5.5 ReturnStatement
1121 AsmType* AsmTyper::ValidateReturnStatement(ReturnStatement* ret_stmt) {
1122 AsmType* ret_expr_type = AsmType::Void();
1123 if (auto* ret_expr = ret_stmt->expression()) {
1124 RECURSE(ret_expr_type = ValidateExpression(ret_expr));
1125 if (ret_expr_type == AsmType::Void()) {
1126 // *VIOLATION* The parser modifies the source code so that expressionless
1127 // returns will return undefined, so we need to allow that.
1128 if (!ret_expr->IsUndefinedLiteral()) {
1129 FAIL(ret_stmt, "Return statement expression can't be void.");
1130 }
1131 }
1132 }
1133
1134 if (!ret_expr_type->IsA(return_type_)) {
1135 FAIL(ret_stmt, "Type mismatch in return statement.");
1136 }
1137
1138 return ret_expr_type;
1139 }
1140
1141 // 6.5.6 IterationStatement
1142 // 6.5.6.a WhileStatement
1143 AsmType* AsmTyper::ValidateWhileStatement(WhileStatement* while_stmt) {
1144 AsmType* cond_type;
1145 RECURSE(cond_type = ValidateExpression(while_stmt->cond()));
1146 if (!cond_type->IsA(AsmType::Int())) {
1147 FAIL(while_stmt->cond(), "While condition must be type int.");
1148 }
1149
1150 if (auto* body = while_stmt->body()) {
1151 RECURSE(ValidateStatement(body));
1152 }
1153 return AsmType::Void();
1154 }
1155
1156 // 6.5.6.b DoWhileStatement
1157 AsmType* AsmTyper::ValidateDoWhileStatement(DoWhileStatement* do_while) {
1158 AsmType* cond_type;
1159 RECURSE(cond_type = ValidateExpression(do_while->cond()));
1160 if (!cond_type->IsA(AsmType::Int())) {
1161 FAIL(do_while->cond(), "Do {} While condition must be type int.");
1162 }
1163
1164 if (auto* body = do_while->body()) {
1165 RECURSE(ValidateStatement(body));
1166 }
1167 return AsmType::Void();
1168 }
1169
1170 // 6.5.6.c ForStatement
1171 AsmType* AsmTyper::ValidateForStatement(ForStatement* for_stmt) {
1172 if (auto* init = for_stmt->init()) {
1173 RECURSE(ValidateStatement(init));
1174 }
1175
1176 if (auto* cond = for_stmt->cond()) {
1177 AsmType* cond_type;
1178 RECURSE(cond_type = ValidateExpression(cond));
1179 if (!cond_type->IsA(AsmType::Int())) {
1180 FAIL(cond, "For condition must be type int.");
1181 }
1182 }
1183
1184 if (auto* next = for_stmt->next()) {
1185 RECURSE(ValidateStatement(next));
1186 }
1187
1188 if (auto* body = for_stmt->body()) {
1189 RECURSE(ValidateStatement(body));
1190 }
1191
1192 return AsmType::Void();
1193 }
1194
1195 // 6.5.7 BreakStatement
1196 AsmType* AsmTyper::ValidateBreakStatement(BreakStatement* brk_stmt) {
1197 return AsmType::Void();
1198 }
1199
1200 // 6.5.8 ContinueStatement
1201 AsmType* AsmTyper::ValidateContinueStatement(ContinueStatement* cont_stmt) {
1202 return AsmType::Void();
1203 }
1204
1205 // 6.5.9 LabelledStatement
1206 // No need to handle these here -- see the AsmTyper's definition.
1207
1208 // 6.5.10 SwitchStatement
1209 AsmType* AsmTyper::ValidateSwitchStatement(SwitchStatement* stmt) {
1210 AsmType* cond_type;
1211 RECURSE(cond_type = ValidateExpression(stmt->tag()));
1212 if (!cond_type->IsA(AsmType::Signed())) {
1213 FAIL(stmt, "Switch tag must be signed.");
1214 }
1215
1216 bool has_default = false;
1217
1218 ZoneSet<int32_t> cases_seen(zone_);
1219 for (auto* a_case : *stmt->cases()) {
1220 if (a_case->is_default()) {
1221 CHECK(!has_default);
1222 RECURSE(ValidateDefault(a_case));
1223 has_default = true;
1224 }
1225
1226 int32_t case_lbl;
1227 RECURSE(ValidateCase(a_case, &case_lbl));
1228 auto case_lbl_pos = cases_seen.find(case_lbl);
1229 if (case_lbl_pos != cases_seen.end() && *case_lbl_pos == case_lbl) {
1230 FAIL(a_case, "Duplicated case label.");
1231 }
1232 cases_seen.insert(case_lbl);
1233 }
1234
1235 if (!cases_seen.empty()) {
1236 const int64_t max_lbl = *cases_seen.rbegin();
1237 const int64_t min_lbl = *cases_seen.begin();
1238 if (max_lbl - min_lbl > std::numeric_limits<int32_t>::max()) {
1239 FAIL(stmt, "Out-of-bounds case label range.");
1240 }
1241 }
1242
1243 return AsmType::Void();
1244 }
1245
1246 // 6.6 ValidateCase
1247 namespace {
1248 bool ExtractInt32CaseLabel(CaseClause* clause, int32_t* lbl) {
1249 auto* lbl_expr = clause->label()->AsLiteral();
1250
1251 if (lbl_expr == nullptr) {
1252 return false;
1253 }
1254
1255 if (lbl_expr->raw_value()->ContainsDot()) {
1256 return false;
1257 }
1258
1259 return lbl_expr->value()->ToInt32(lbl);
1260 }
1261 } // namespace
1262
1263 AsmType* AsmTyper::ValidateCase(CaseClause* label, int32_t* case_lbl) {
1264 if (!ExtractInt32CaseLabel(label, case_lbl)) {
1265 FAIL(label, "Case label must be a 32-bit signed integer.");
1266 }
1267
1268 FlattenedStatements iter(zone_, label->statements());
1269 while (auto* current = iter.Next()) {
1270 RECURSE(ValidateStatement(current));
1271 }
1272 return AsmType::Void();
1273 }
1274
1275 // 6.7 ValidateDefault
1276 AsmType* AsmTyper::ValidateDefault(CaseClause* label) {
1277 FlattenedStatements iter(zone_, label->statements());
1278 while (auto* current = iter.Next()) {
1279 RECURSE(ValidateStatement(current));
1280 }
1281 return AsmType::Void();
1282 }
1283
1284 // 6.8 ValidateExpression
1285 AsmType* AsmTyper::ValidateExpression(Expression* expr) {
1286 AsmType* expr_ty = AsmType::None();
1287
1288 switch (expr->node_type()) {
1289 default:
1290 FAIL(expr, "Invalid asm.js expression.");
1291 case AstNode::kLiteral:
1292 RECURSE(expr_ty = ValidateNumericLiteral(expr->AsLiteral()));
1293 break;
1294 case AstNode::kVariableProxy:
1295 RECURSE(expr_ty = ValidateIdentifier(expr->AsVariableProxy()));
1296 break;
1297 case AstNode::kCall:
1298 RECURSE(expr_ty = ValidateCallExpression(expr->AsCall()));
1299 break;
1300 case AstNode::kProperty:
1301 RECURSE(expr_ty = ValidateMemberExpression(expr->AsProperty()));
1302 break;
1303 case AstNode::kAssignment:
1304 RECURSE(expr_ty = ValidateAssignmentExpression(expr->AsAssignment()));
1305 break;
1306 case AstNode::kUnaryOperation:
1307 RECURSE(expr_ty = ValidateUnaryExpression(expr->AsUnaryOperation()));
1308 break;
1309 case AstNode::kConditional:
1310 RECURSE(expr_ty = ValidateConditionalExpression(expr->AsConditional()));
1311 break;
1312 case AstNode::kCompareOperation:
1313 RECURSE(expr_ty = ValidateCompareOperation(expr->AsCompareOperation()));
1314 break;
1315 case AstNode::kBinaryOperation:
1316 RECURSE(expr_ty = ValidateBinaryOperation(expr->AsBinaryOperation()));
1317 break;
1318 }
1319
1320 SetTypeOf(expr, expr_ty);
1321 return expr_ty;
1322 }
1323
1324 AsmType* AsmTyper::ValidateCompareOperation(CompareOperation* cmp) {
1325 switch (cmp->op()) {
1326 default:
1327 FAIL(cmp, "Invalid asm.js comparison operator.");
1328 case Token::LT:
1329 case Token::LTE:
1330 case Token::GT:
1331 case Token::GTE:
1332 return ValidateRelationalExpression(cmp);
1333 case Token::EQ:
1334 case Token::NE:
1335 return ValidateEqualityExpression(cmp);
1336 }
1337
1338 UNREACHABLE();
1339 }
1340
1341 namespace {
1342 bool IsNegate(BinaryOperation* binop) {
1343 if (binop->op() != Token::BIT_XOR) {
1344 return false;
1345 }
1346
1347 auto* right_as_literal = binop->right()->AsLiteral();
1348 if (right_as_literal == nullptr) {
1349 return false;
1350 }
1351
1352 return !right_as_literal->raw_value()->ContainsDot() &&
1353 right_as_literal->raw_value()->AsNumber() == -1.0;
1354 }
1355
1356 bool IsUnaryMinus(BinaryOperation* binop) {
1357 // *VIOLATION* The parser replaces uses of +x with x*1.0.
1358 if (binop->op() != Token::MUL) {
1359 return false;
1360 }
1361
1362 auto* right_as_literal = binop->right()->AsLiteral();
1363 if (right_as_literal == nullptr) {
1364 return false;
1365 }
1366
1367 return right_as_literal->raw_value()->ContainsDot() &&
1368 right_as_literal->raw_value()->AsNumber() == -1.0;
1369 }
1370 } // namespace
1371
1372 AsmType* AsmTyper::ValidateBinaryOperation(BinaryOperation* expr) {
1373 #define UNOP_OVERLOAD(Src, Dest) \
1374 do { \
1375 if (left_type->IsA(AsmType::Src())) { \
1376 return AsmType::Dest(); \
1377 } \
1378 } while (0)
1379
1380 switch (expr->op()) {
1381 default:
1382 FAIL(expr, "Invalid asm.js binary expression.");
1383 case Token::COMMA:
1384 return ValidateCommaExpression(expr);
1385 case Token::MUL:
1386 if (IsDoubleAnnotation(expr)) {
1387 // *VIOLATION* We can't be 100% sure this really IS a unary + in the asm
1388 // source so we have to be lenient, and treat this as a unary +.
1389 if (auto* Call = expr->left()->AsCall()) {
1390 return ValidateCall(AsmType::Double(), Call);
1391 }
1392 AsmType* left_type;
1393 RECURSE(left_type = ValidateExpression(expr->left()));
1394 UNOP_OVERLOAD(Signed, Double);
1395 UNOP_OVERLOAD(Unsigned, Double);
1396 UNOP_OVERLOAD(DoubleQ, Double);
1397 UNOP_OVERLOAD(FloatQ, Double);
1398 FAIL(expr, "Invalid type for conversion to double.");
1399 }
1400
1401 if (IsUnaryMinus(expr)) {
1402 // *VIOLATION* the parser converts -x to x * -1.0.
1403 AsmType* left_type;
1404 RECURSE(left_type = ValidateExpression(expr->left()));
1405 UNOP_OVERLOAD(Int, Intish);
1406 UNOP_OVERLOAD(DoubleQ, Double);
1407 UNOP_OVERLOAD(FloatQ, Floatish);
1408 FAIL(expr, "Invalid type for unary -.");
1409 }
1410 // FALTHROUGH
1411 case Token::DIV:
1412 case Token::MOD:
1413 return ValidateMultiplicativeExpression(expr);
1414 case Token::ADD:
1415 case Token::SUB: {
1416 static const uint32_t kInitialIntishCount = 0;
1417 return ValidateAdditiveExpression(expr, kInitialIntishCount);
1418 }
1419 case Token::SAR:
1420 case Token::SHL:
1421 case Token::SHR:
1422 return ValidateShiftExpression(expr);
1423 case Token::BIT_AND:
1424 return ValidateBitwiseANDExpression(expr);
1425 case Token::BIT_XOR:
1426 if (IsNegate(expr)) {
1427 auto* left = expr->left();
1428 auto* left_as_binop = left->AsBinaryOperation();
1429
1430 if (left_as_binop != nullptr && IsNegate(left_as_binop)) {
1431 // This is the special ~~ operator.
1432 AsmType* left_type;
1433 RECURSE(left_type = ValidateExpression(left_as_binop->left()));
1434 UNOP_OVERLOAD(Double, Signed);
1435 UNOP_OVERLOAD(FloatQ, Signed);
1436 FAIL(left_as_binop, "Invalid type for conversion to signed.");
1437 }
1438
1439 AsmType* left_type;
1440 RECURSE(left_type = ValidateExpression(left));
1441 UNOP_OVERLOAD(Intish, Signed);
1442 FAIL(left, "Invalid type for ~.");
1443 }
1444
1445 return ValidateBitwiseXORExpression(expr);
1446 case Token::BIT_OR:
1447 return ValidateBitwiseORExpression(expr);
1448 }
1449 #undef UNOP_OVERLOAD
1450 UNREACHABLE();
1451 }
1452
1453 // 6.8.1 Expression
1454 AsmType* AsmTyper::ValidateCommaExpression(BinaryOperation* comma) {
1455 // The AST looks like:
1456 // (expr COMMA (expr COMMA (expr COMMA (... ))))
1457
1458 auto* left = comma->left();
1459 auto* left_as_binop = left->AsBinaryOperation();
1460 if (left_as_binop && left_as_binop->op() == Token::COMMA) {
1461 ValidateCommaExpression(left_as_binop);
1462 } else if (auto* left_as_call = left->AsCall()) {
1463 ValidateCall(AsmType::Void(), left_as_call);
1464 } else {
1465 ValidateExpression(left);
1466 }
1467
1468 auto* right = comma->right();
1469 auto* right_as_binop = right->AsBinaryOperation();
1470 if (right_as_binop && right_as_binop->op() == Token::COMMA) {
1471 return ValidateCommaExpression(right_as_binop);
1472 } else {
1473 return ValidateExpression(right);
1474 }
1475
1476 UNREACHABLE();
1477 }
1478
1479 // 6.8.2 NumericLiteral
1480 AsmType* AsmTyper::ValidateNumericLiteral(Literal* literal) {
1481 // *VIOLATION* asm.js does not allow the use of undefined, but our parser
1482 // inserts them, so we have to handle them.
1483 if (literal->IsUndefinedLiteral()) {
1484 return AsmType::Void();
1485 }
1486
1487 if (literal->raw_value()->ContainsDot()) {
1488 return AsmType::Double();
1489 }
1490
1491 uint32_t value;
1492 if (!literal->value()->ToUint32(&value)) {
1493 int32_t value;
1494 if (!literal->value()->ToInt32(&value)) {
1495 FAIL(literal, "Integer literal is out of range.");
1496 }
1497 // *VIOLATION* Not really a violation, but rather a different in the
1498 // validation. The spec handles -NumericLiteral in ValidateUnaryExpression,
1499 // but V8's AST represents the negative literals as Literals.
1500 return AsmType::Signed();
1501 }
1502
1503 static const uint32_t LargestFixNum = std::numeric_limits<int32_t>::max();
1504 if (value <= LargestFixNum) {
1505 return AsmType::FixNum();
1506 }
1507
1508 return AsmType::Unsigned();
1509 }
1510
1511 // 6.8.3 Identifier
1512 AsmType* AsmTyper::ValidateIdentifier(VariableProxy* proxy) {
1513 auto* proxy_info = Lookup(proxy->var());
1514 if (proxy_info == nullptr) {
1515 FAIL(proxy, "Undeclared identifier.");
1516 }
1517 if (proxy_info->type()->AsCallableType() != nullptr) {
1518 FAIL(proxy, "Identifier may not be accessed by ordinary expressions.");
1519 }
1520 DCHECK(!proxy_info->type()->IsA(AsmType::None()));
1521 return proxy_info->type();
1522 }
1523
1524 // 6.8.4 CallExpression
1525 AsmType* AsmTyper::ValidateCallExpression(Call* call) {
1526 AsmType* return_type;
1527 RECURSE(return_type = ValidateFloatCoercion(call));
1528 if (return_type == nullptr) {
1529 FAIL(call, "Unanotated call to a function must be a call to fround.");
1530 }
1531 return return_type;
1532 }
1533
1534 // 6.8.5 MemberExpression
1535 AsmType* AsmTyper::ValidateMemberExpression(Property* prop) {
1536 AsmType* return_type;
1537 RECURSE(return_type = ValidateHeapAccess(prop, LoadFromHeap));
1538 return return_type;
1539 }
1540
1541 // 6.8.6 AssignmentExpression
1542 AsmType* AsmTyper::ValidateAssignmentExpression(Assignment* assignment) {
1543 AsmType* value_type;
1544 RECURSE(value_type = ValidateExpression(assignment->value()));
1545
1546 if (assignment->op() == Token::INIT) {
1547 FAIL(assignment,
1548 "Local variable declaration must be at the top of the function.");
1549 }
1550
1551 if (auto* target_as_proxy = assignment->target()->AsVariableProxy()) {
1552 auto* var = target_as_proxy->var();
1553 auto* target_info = Lookup(var);
1554
1555 if (target_info == nullptr) {
1556 if (var->mode() != TEMPORARY) {
1557 FAIL(target_as_proxy, "Undeclared identifier.");
1558 }
1559 // Temporary variables are special: we add them to the local symbol table
1560 // as we see them, with the exact type of the variable's initializer. This
1561 // means that temporary variables might have nonsensical types (i.e.,
1562 // intish, float?, fixnum, and not just the "canonical" types.)
1563 auto* var_info = new (zone_) VariableInfo(value_type);
1564 var_info->set_mutability(VariableInfo::kLocal);
1565 if (!ValidAsmIdentifier(target_as_proxy->name())) {
1566 FAIL(target_as_proxy,
1567 "Invalid asm.js identifier in temporary variable.");
1568 }
1569
1570 if (!AddLocal(var, var_info)) {
1571 FAIL(assignment, "Failed to add temporary variable to symbol table.");
1572 }
1573 return value_type;
1574 }
1575
1576 DCHECK(target_info->type() != AsmType::None());
1577 if (!value_type->IsA(target_info->type())) {
1578 FAIL(assignment, "Type mismatch in assignment.");
1579 }
1580
1581 return value_type;
1582 }
1583
1584 if (auto* target_as_property = assignment->target()->AsProperty()) {
1585 AsmType* allowed_store_types;
1586 RECURSE(allowed_store_types =
1587 ValidateHeapAccess(target_as_property, StoreToHeap));
1588
1589 // TODO(jpp): Change FloatishDoubleQ and FloatQDoubleQ so that they are base
1590 // classes for Floatish, DoubleQ, and FloatQ, and then invert this if so
1591 // that it reads more naturally as
1592 //
1593 // if (!value_type->IsA(allowed_store_types))
1594 if (allowed_store_types == AsmType::FloatishDoubleQ() ||
1595 allowed_store_types == AsmType::FloatQDoubleQ()) {
1596 if (!allowed_store_types->IsA(value_type)) {
1597 FAIL(assignment, "Type mismatch in heap assignment.");
1598 }
1599 } else {
1600 if (!value_type->IsA(allowed_store_types)) {
1601 FAIL(assignment, "Type mismatch in heap assignment.");
1602 }
1603 }
1604
1605 return value_type;
1606 }
1607
1608 FAIL(assignment, "Invalid asm.js assignment.");
1609 }
1610
1611 // 6.8.7 UnaryExpression
1612 AsmType* AsmTyper::ValidateUnaryExpression(UnaryOperation* unop) {
1613 // *VIOLATION* -NumericLiteral is validated in ValidateLiteral.
1614 // *VIOLATION* +UnaryExpression is validated in ValidateBinaryOperation.
1615 // *VIOLATION* ~UnaryOperation is validated in ValidateBinaryOperation.
1616 // *VIOLATION* ~~UnaryOperation is validated in ValidateBinaryOperation.
1617 DCHECK(unop->op() != Token::BIT_NOT);
1618 DCHECK(unop->op() != Token::ADD);
1619 AsmType* exp_type;
1620 RECURSE(exp_type = ValidateExpression(unop->expression()));
1621 #define UNOP_OVERLOAD(Src, Dest) \
1622 do { \
1623 if (exp_type->IsA(AsmType::Src())) { \
1624 return AsmType::Dest(); \
1625 } \
1626 } while (0)
1627
1628 // 8.1 Unary Operators
1629 switch (unop->op()) {
1630 default:
1631 FAIL(unop, "Invalid unary operator.");
1632 case Token::ADD:
1633 // We can't test this because of the +x -> x * 1.0 transformation.
1634 DCHECK(false);
1635 UNOP_OVERLOAD(Signed, Double);
1636 UNOP_OVERLOAD(Unsigned, Double);
1637 UNOP_OVERLOAD(DoubleQ, Double);
1638 UNOP_OVERLOAD(FloatQ, Double);
1639 FAIL(unop, "Invalid type for unary +.");
1640 case Token::SUB:
1641 // We can't test this because of the -x -> x * -1.0 transformation.
1642 DCHECK(false);
1643 UNOP_OVERLOAD(Int, Intish);
1644 UNOP_OVERLOAD(DoubleQ, Double);
1645 UNOP_OVERLOAD(FloatQ, Floatish);
1646 FAIL(unop, "Invalid type for unary -.");
1647 case Token::BIT_NOT:
1648 // We can't test this because of the ~x -> x ^ -1 transformation.
1649 DCHECK(false);
1650 UNOP_OVERLOAD(Intish, Signed);
1651 FAIL(unop, "Invalid type for ~.");
1652 case Token::NOT:
1653 UNOP_OVERLOAD(Int, Int);
1654 FAIL(unop, "Invalid type for !.");
1655 }
1656
1657 #undef UNOP_OVERLOAD
1658
1659 UNREACHABLE();
1660 }
1661
1662 // 6.8.8 MultiplicativeExpression
1663 namespace {
1664 bool IsIntishLiteralFactor(Expression* expr, int32_t* factor) {
1665 auto* literal = expr->AsLiteral();
1666 if (literal == nullptr) {
1667 return false;
1668 }
1669
1670 if (literal->raw_value()->ContainsDot()) {
1671 return false;
1672 }
1673
1674 if (!literal->value()->ToInt32(factor)) {
1675 return false;
1676 }
1677 static const int32_t kIntishBound = 1 << 20;
1678 return -kIntishBound < *factor && *factor < kIntishBound;
1679 }
1680 } // namespace
1681
1682 AsmType* AsmTyper::ValidateMultiplicativeExpression(BinaryOperation* binop) {
1683 DCHECK(!IsDoubleAnnotation(binop));
1684
1685 auto* left = binop->left();
1686 auto* right = binop->right();
1687
1688 bool intish_mul_failed = false;
1689 if (binop->op() == Token::MUL) {
1690 int32_t factor;
1691 if (IsIntishLiteralFactor(left, &factor)) {
1692 AsmType* right_type;
1693 RECURSE(right_type = ValidateExpression(right));
1694 if (right_type->IsA(AsmType::Int())) {
1695 return AsmType::Intish();
1696 }
1697 // Can't fail here, because the rhs might contain a valid intish factor.
1698 //
1699 // The solution is to flag that there was an error, and later on -- when
1700 // both lhs and rhs are evaluated -- complain.
1701 intish_mul_failed = true;
1702 }
1703
1704 if (IsIntishLiteralFactor(right, &factor)) {
1705 AsmType* left_type;
1706 RECURSE(left_type = ValidateExpression(left));
1707 if (left_type->IsA(AsmType::Int())) {
1708 // *VIOLATION* This will also (and correctly) handle -X, when X is an
1709 // integer. Therefore, we don't need to handle this case within the if
1710 // block below.
1711 return AsmType::Intish();
1712 }
1713 intish_mul_failed = true;
1714
1715 if (factor == -1) {
1716 // *VIOLATION* The frontend transforms -x into x * -1 (not -1.0, because
1717 // consistency is overrated.)
1718 if (left_type->IsA(AsmType::DoubleQ())) {
1719 return AsmType::Double();
1720 } else if (left_type->IsA(AsmType::FloatQ())) {
1721 return AsmType::Floatish();
1722 }
1723 }
1724 }
1725 }
1726
1727 if (intish_mul_failed) {
1728 FAIL(binop, "Invalid types for intish * (or unary -).");
1729 }
1730
1731 AsmType* left_type;
1732 AsmType* right_type;
1733 RECURSE(left_type = ValidateExpression(left));
1734 RECURSE(right_type = ValidateExpression(right));
1735
1736 #define BINOP_OVERLOAD(Src0, Src1, Dest) \
1737 do { \
1738 if (left_type->IsA(AsmType::Src0()) && right_type->IsA(AsmType::Src1())) { \
1739 return AsmType::Dest(); \
1740 } \
1741 } while (0)
1742 switch (binop->op()) {
1743 default:
1744 FAIL(binop, "Invalid multiplicative expression.");
1745 case Token::MUL:
1746 BINOP_OVERLOAD(DoubleQ, DoubleQ, Double);
1747 BINOP_OVERLOAD(FloatQ, FloatQ, Floatish);
1748 FAIL(binop, "Invalid operands for *.");
1749 case Token::DIV:
1750 BINOP_OVERLOAD(Signed, Signed, Intish);
1751 BINOP_OVERLOAD(Unsigned, Unsigned, Intish);
1752 BINOP_OVERLOAD(DoubleQ, DoubleQ, Double);
1753 BINOP_OVERLOAD(FloatQ, FloatQ, Floatish);
1754 FAIL(binop, "Invalid operands for /.");
1755 case Token::MOD:
1756 BINOP_OVERLOAD(Signed, Signed, Intish);
1757 BINOP_OVERLOAD(Unsigned, Unsigned, Intish);
1758 BINOP_OVERLOAD(DoubleQ, DoubleQ, Double);
1759 FAIL(binop, "Invalid operands for %.");
1760 }
1761 #undef BINOP_OVERLOAD
1762
1763 UNREACHABLE();
1764 }
1765
1766 // 6.8.9 AdditiveExpression
1767 AsmType* AsmTyper::ValidateAdditiveExpression(BinaryOperation* binop,
1768 uint32_t intish_count) {
1769 static const uint32_t kMaxIntish = 1 << 20;
1770
1771 auto* left = binop->left();
1772 auto* left_as_binop = left->AsBinaryOperation();
1773 AsmType* left_type;
1774
1775 // TODO(jpp): maybe use an iterative approach instead of the recursion to
1776 // ValidateAdditiveExpression.
1777 if (left_as_binop != nullptr && (left_as_binop->op() == Token::ADD ||
1778 left_as_binop->op() == Token::SUB)) {
1779 RECURSE(left_type =
1780 ValidateAdditiveExpression(left_as_binop, intish_count + 1));
1781 } else {
1782 RECURSE(left_type = ValidateExpression(left));
1783 }
1784
1785 auto* right = binop->right();
1786 auto* right_as_binop = right->AsBinaryOperation();
1787 AsmType* right_type;
1788
1789 if (right_as_binop != nullptr && (right_as_binop->op() == Token::ADD ||
1790 right_as_binop->op() == Token::SUB)) {
1791 RECURSE(right_type =
1792 ValidateAdditiveExpression(right_as_binop, intish_count + 1));
1793 } else {
1794 RECURSE(right_type = ValidateExpression(right));
1795 }
1796
1797 if (left_type->IsA(AsmType::FloatQ()) && right_type->IsA(AsmType::FloatQ())) {
1798 return AsmType::Floatish();
1799 }
1800
1801 if (left_type->IsA(AsmType::Int()) && right_type->IsA(AsmType::Int())) {
1802 if (intish_count == 0) {
1803 return AsmType::Intish();
1804 }
1805 if (intish_count < kMaxIntish) {
1806 return AsmType::Int();
1807 }
1808 FAIL(binop, "Too many uncoerced integer additive expressions.");
1809 }
1810
1811 if (left_type->IsA(AsmType::Double()) && right_type->IsA(AsmType::Double())) {
1812 return AsmType::Double();
1813 }
1814
1815 if (binop->op() == Token::SUB) {
1816 if (left_type->IsA(AsmType::DoubleQ()) &&
1817 right_type->IsA(AsmType::DoubleQ())) {
1818 return AsmType::Double();
1819 }
1820 }
1821
1822 FAIL(binop, "Invalid operands for additive expression.");
1823 }
1824
1825 // 6.8.10 ShiftExpression
1826 AsmType* AsmTyper::ValidateShiftExpression(BinaryOperation* binop) {
1827 auto* left = binop->left();
1828 auto* right = binop->right();
1829
1830 AsmType* left_type;
1831 AsmType* right_type;
1832 RECURSE(left_type = ValidateExpression(left));
1833 RECURSE(right_type = ValidateExpression(right));
1834
1835 #define BINOP_OVERLOAD(Src0, Src1, Dest) \
1836 do { \
1837 if (left_type->IsA(AsmType::Src0()) && right_type->IsA(AsmType::Src1())) { \
1838 return AsmType::Dest(); \
1839 } \
1840 } while (0)
1841 switch (binop->op()) {
1842 default:
1843 FAIL(binop, "Invalid shift expression.");
1844 case Token::SHL:
1845 BINOP_OVERLOAD(Intish, Intish, Signed);
1846 FAIL(binop, "Invalid operands for <<.");
1847 case Token::SAR:
1848 BINOP_OVERLOAD(Intish, Intish, Signed);
1849 FAIL(binop, "Invalid operands for >>.");
1850 case Token::SHR:
1851 BINOP_OVERLOAD(Intish, Intish, Unsigned);
1852 FAIL(binop, "Invalid operands for >>>.");
1853 }
1854 #undef BINOP_OVERLOAD
1855
1856 UNREACHABLE();
1857 }
1858
1859 // 6.8.11 RelationalExpression
1860 AsmType* AsmTyper::ValidateRelationalExpression(CompareOperation* cmpop) {
1861 auto* left = cmpop->left();
1862 auto* right = cmpop->right();
1863
1864 AsmType* left_type;
1865 AsmType* right_type;
1866 RECURSE(left_type = ValidateExpression(left));
1867 RECURSE(right_type = ValidateExpression(right));
1868
1869 #define CMPOP_OVERLOAD(Src0, Src1, Dest) \
1870 do { \
1871 if (left_type->IsA(AsmType::Src0()) && right_type->IsA(AsmType::Src1())) { \
1872 return AsmType::Dest(); \
1873 } \
1874 } while (0)
1875 switch (cmpop->op()) {
1876 default:
1877 FAIL(cmpop, "Invalid relational expression.");
1878 case Token::LT:
1879 CMPOP_OVERLOAD(Signed, Signed, Int);
1880 CMPOP_OVERLOAD(Unsigned, Unsigned, Int);
1881 CMPOP_OVERLOAD(Float, Float, Int);
1882 CMPOP_OVERLOAD(Double, Double, Int);
1883 FAIL(cmpop, "Invalid operands for <.");
1884 case Token::GT:
1885 CMPOP_OVERLOAD(Signed, Signed, Int);
1886 CMPOP_OVERLOAD(Unsigned, Unsigned, Int);
1887 CMPOP_OVERLOAD(Float, Float, Int);
1888 CMPOP_OVERLOAD(Double, Double, Int);
1889 FAIL(cmpop, "Invalid operands for >.");
1890 case Token::LTE:
1891 CMPOP_OVERLOAD(Signed, Signed, Int);
1892 CMPOP_OVERLOAD(Unsigned, Unsigned, Int);
1893 CMPOP_OVERLOAD(Float, Float, Int);
1894 CMPOP_OVERLOAD(Double, Double, Int);
1895 FAIL(cmpop, "Invalid operands for <=.");
1896 case Token::GTE:
1897 CMPOP_OVERLOAD(Signed, Signed, Int);
1898 CMPOP_OVERLOAD(Unsigned, Unsigned, Int);
1899 CMPOP_OVERLOAD(Float, Float, Int);
1900 CMPOP_OVERLOAD(Double, Double, Int);
1901 FAIL(cmpop, "Invalid operands for >=.");
1902 }
1903 #undef CMPOP_OVERLOAD
1904
1905 UNREACHABLE();
1906 }
1907
1908 // 6.8.12 EqualityExpression
1909 AsmType* AsmTyper::ValidateEqualityExpression(CompareOperation* cmpop) {
1910 auto* left = cmpop->left();
1911 auto* right = cmpop->right();
1912
1913 AsmType* left_type;
1914 AsmType* right_type;
1915 RECURSE(left_type = ValidateExpression(left));
1916 RECURSE(right_type = ValidateExpression(right));
1917
1918 #define CMPOP_OVERLOAD(Src0, Src1, Dest) \
1919 do { \
1920 if (left_type->IsA(AsmType::Src0()) && right_type->IsA(AsmType::Src1())) { \
1921 return AsmType::Dest(); \
1922 } \
1923 } while (0)
1924 switch (cmpop->op()) {
1925 default:
1926 FAIL(cmpop, "Invalid equality expression.");
1927 case Token::EQ:
1928 CMPOP_OVERLOAD(Signed, Signed, Int);
1929 CMPOP_OVERLOAD(Unsigned, Unsigned, Int);
1930 CMPOP_OVERLOAD(Float, Float, Int);
1931 CMPOP_OVERLOAD(Double, Double, Int);
1932 FAIL(cmpop, "Invalid operands for ==.");
1933 case Token::NE:
1934 CMPOP_OVERLOAD(Signed, Signed, Int);
1935 CMPOP_OVERLOAD(Unsigned, Unsigned, Int);
1936 CMPOP_OVERLOAD(Float, Float, Int);
1937 CMPOP_OVERLOAD(Double, Double, Int);
1938 FAIL(cmpop, "Invalid operands for !=.");
1939 }
1940 #undef CMPOP_OVERLOAD
1941
1942 UNREACHABLE();
1943 }
1944
1945 // 6.8.13 BitwiseANDExpression
1946 AsmType* AsmTyper::ValidateBitwiseANDExpression(BinaryOperation* binop) {
1947 auto* left = binop->left();
1948 auto* right = binop->right();
1949
1950 AsmType* left_type;
1951 AsmType* right_type;
1952 RECURSE(left_type = ValidateExpression(left));
1953 RECURSE(right_type = ValidateExpression(right));
1954
1955 if (binop->op() != Token::BIT_AND) {
1956 FAIL(binop, "Invalid & expression.");
1957 }
1958
1959 #define BINOP_OVERLOAD(Src0, Src1, Dest) \
1960 do { \
1961 if (left_type->IsA(AsmType::Src0()) && right_type->IsA(AsmType::Src1())) { \
1962 return AsmType::Dest(); \
1963 } \
1964 } while (0)
1965 BINOP_OVERLOAD(Intish, Intish, Signed);
1966 FAIL(binop, "Invalid operands for &.");
1967 #undef BINOP_OVERLOAD
1968
1969 UNREACHABLE();
1970 }
1971
1972 // 6.8.14 BitwiseXORExpression
1973 AsmType* AsmTyper::ValidateBitwiseXORExpression(BinaryOperation* binop) {
1974 auto* left = binop->left();
1975 auto* right = binop->right();
1976
1977 AsmType* left_type;
1978 AsmType* right_type;
1979 RECURSE(left_type = ValidateExpression(left));
1980 RECURSE(right_type = ValidateExpression(right));
1981
1982 if (binop->op() != Token::BIT_XOR) {
1983 FAIL(binop, "Invalid ^ expression.");
1984 }
1985
1986 #define BINOP_OVERLOAD(Src0, Src1, Dest) \
1987 do { \
1988 if (left_type->IsA(AsmType::Src0()) && right_type->IsA(AsmType::Src1())) { \
1989 return AsmType::Dest(); \
1990 } \
1991 } while (0)
1992 BINOP_OVERLOAD(Intish, Intish, Signed);
1993 FAIL(binop, "Invalid operands for ^.");
1994 #undef BINOP_OVERLOAD
1995
1996 UNREACHABLE();
1997 }
1998
1999 // 6.8.15 BitwiseORExpression
2000 AsmType* AsmTyper::ValidateBitwiseORExpression(BinaryOperation* binop) {
2001 auto* left = binop->left();
2002 if (IsIntAnnotation(binop)) {
2003 if (auto* left_as_call = left->AsCall()) {
2004 AsmType* type;
2005 RECURSE(type = ValidateCall(AsmType::Signed(), left_as_call));
2006 return type;
2007 }
2008
2009 // TODO(jpp): at this point we know that binop is expr|0. We could sinply
2010 //
2011 // RECURSE(t = ValidateExpression(left));
2012 // FAIL_IF(t->IsNotA(Intish));
2013 // return Signed;
2014 }
2015
2016 auto* right = binop->right();
2017 AsmType* left_type;
2018 AsmType* right_type;
2019 RECURSE(left_type = ValidateExpression(left));
2020 RECURSE(right_type = ValidateExpression(right));
2021
2022 if (binop->op() != Token::BIT_OR) {
2023 FAIL(binop, "Invalid | expression.");
2024 }
2025
2026 #define BINOP_OVERLOAD(Src0, Src1, Dest) \
2027 do { \
2028 if (left_type->IsA(AsmType::Src0()) && right_type->IsA(AsmType::Src1())) { \
2029 return AsmType::Dest(); \
2030 } \
2031 } while (0)
2032 BINOP_OVERLOAD(Intish, Intish, Signed);
2033 FAIL(binop, "Invalid operands for |.");
2034 #undef BINOP_OVERLOAD
2035
2036 UNREACHABLE();
2037 }
2038
2039 // 6.8.16 ConditionalExpression
2040 AsmType* AsmTyper::ValidateConditionalExpression(Conditional* cond) {
2041 AsmType* cond_type;
2042 RECURSE(cond_type = ValidateExpression(cond->condition()));
2043 if (!cond_type->IsA(AsmType::Int())) {
2044 FAIL(cond, "Ternary operation condition should be int.");
2045 }
2046
2047 AsmType* then_type;
2048 RECURSE(then_type = ValidateExpression(cond->then_expression()));
2049 AsmType* else_type;
2050 RECURSE(else_type = ValidateExpression(cond->else_expression()));
2051
2052 #define SUCCEED_IF_BOTH_ARE(type) \
2053 do { \
2054 if (then_type->IsA(AsmType::type())) { \
2055 if (!else_type->IsA(AsmType::type())) { \
2056 FAIL(cond, "Type mismatch for ternary operation result type."); \
2057 } \
2058 return AsmType::type(); \
2059 } \
2060 } while (0)
2061 SUCCEED_IF_BOTH_ARE(Int);
2062 SUCCEED_IF_BOTH_ARE(Float);
2063 SUCCEED_IF_BOTH_ARE(Double);
2064 #undef SUCCEED_IF_BOTH_ARE
2065
2066 FAIL(cond, "Ternary operator must return int, float, or double.");
2067 }
2068
2069 // 6.9 ValidateCall
2070 namespace {
2071 bool ExtractIndirectCallMask(Expression* expr, uint32_t* value) {
2072 auto* as_literal = expr->AsLiteral();
2073 if (as_literal == nullptr) {
2074 return false;
2075 }
2076
2077 if (as_literal->raw_value()->ContainsDot()) {
2078 return false;
2079 }
2080
2081 if (!as_literal->value()->ToUint32(value)) {
2082 return false;
2083 }
2084
2085 return base::bits::IsPowerOfTwo32(1 + *value);
2086 }
2087
2088 // TODO(jpp): Add a AsmType::ValidateCall is poorly designed. It can only handle
2089 // function declarations, not invocations. CheckInvocationOf temporarily works
2090 // around this limitation by converting each actual in actuals to a parameter
2091 // type before invoking prototype->ValidateCall. This is the wrong behavior for
2092 // FFIs (we need to pass Signed integers to FFIs, not Ints), so that case is
2093 // handled separately.
2094 bool CheckInvocationOf(AsmCallableType* prototype, AsmType* return_type,
2095 ZoneVector<AsmType*>* actuals) {
2096 if (auto* ffi = prototype->AsFFIType()) {
2097 return ffi->ValidateCall(return_type, *actuals) != AsmType::None();
2098 }
2099
2100 for (size_t ii = 0; ii < actuals->size(); ++ii) {
2101 (*actuals)[ii] = (*actuals)[ii]->ToParameterType();
2102 }
2103 return prototype->ValidateCall(return_type, *actuals) != AsmType::None();
2104 }
2105
2106 } // namespace
2107
2108 AsmType* AsmTyper::ValidateCall(AsmType* return_type, Call* call) {
2109 AsmType* float_coercion_type;
2110 RECURSE(float_coercion_type = ValidateFloatCoercion(call));
2111 if (float_coercion_type == AsmType::Float()) {
2112 return AsmType::Float();
2113 }
2114
2115 // TODO(jpp): we should be able to reuse the args vector's storage space.
2116 ZoneVector<AsmType*> args(zone_);
2117 args.reserve(call->arguments()->length());
2118
2119 for (auto* arg : *call->arguments()) {
2120 AsmType* arg_type;
2121 RECURSE(arg_type = ValidateExpression(arg));
2122 args.emplace_back(arg_type);
2123 }
2124
2125 auto* call_expr = call->expression();
2126
2127 // identifier(Expression...)
2128 if (auto* call_var_proxy = call_expr->AsVariableProxy()) {
2129 auto* call_var_info = Lookup(call_var_proxy->var());
2130
2131 if (call_var_info == nullptr) {
2132 // We can't fail here: the validator performs a single pass over the AST,
2133 // so it is possible for some calls to be currently unresolved. We eagerly
2134 // add the function to the table of globals.
2135 auto* call_type = AsmType::Function(zone_, return_type)->AsFunctionType();
2136 for (auto* arg : args) {
2137 call_type->AddArgument(arg->ToParameterType());
2138 }
2139 auto* fun_info =
2140 new (zone_) VariableInfo(reinterpret_cast<AsmType*>(call_type));
2141 fun_info->set_mutability(VariableInfo::kImmutableGlobal);
2142 AddForwardReference(call_var_proxy, fun_info);
2143 if (!ValidAsmIdentifier(call_var_proxy->name())) {
2144 FAIL(call_var_proxy,
2145 "Invalid asm.js identifier in (forward) function name.");
2146 }
2147 if (!AddGlobal(call_var_proxy->var(), fun_info)) {
2148 DCHECK(false);
2149 FAIL(call, "Redeclared global identifier.");
2150 }
2151 return return_type;
2152 }
2153
2154 auto* callee_type = call_var_info->type()->AsCallableType();
2155 if (callee_type == nullptr) {
2156 FAIL(call, "Calling something that's not a function.");
2157 }
2158
2159 if (callee_type->AsFFIType() != nullptr &&
2160 return_type == AsmType::Float()) {
2161 FAIL(call, "Foreign functions can't return float.");
2162 }
2163
2164 if (!CheckInvocationOf(callee_type, return_type, &args)) {
2165 FAIL(call, "Function invocation does not match function type.");
2166 }
2167
2168 return return_type;
2169 }
2170
2171 // identifier[expr & n](Expression...)
2172 if (auto* call_property = call_expr->AsProperty()) {
2173 auto* index = call_property->key()->AsBinaryOperation();
2174 if (index == nullptr || index->op() != Token::BIT_AND) {
2175 FAIL(call_property->key(),
2176 "Indirect call index must be in the expr & mask form.");
2177 }
2178
2179 auto* left = index->left();
2180 auto* right = index->right();
2181 uint32_t mask;
2182 if (!ExtractIndirectCallMask(right, &mask)) {
2183 if (!ExtractIndirectCallMask(left, &mask)) {
2184 FAIL(right, "Invalid indirect call mask.");
2185 } else {
2186 left = right;
2187 }
2188 }
2189 const uint32_t table_length = mask + 1;
2190
2191 AsmType* left_type;
2192 RECURSE(left_type = ValidateExpression(left));
2193 if (!left_type->IsA(AsmType::Intish())) {
2194 FAIL(left, "Indirect call index should be an intish.");
2195 }
2196
2197 auto* name_var = call_property->obj()->AsVariableProxy();
2198
2199 if (name_var == nullptr) {
2200 FAIL(call_property, "Invalid call.");
2201 }
2202
2203 auto* name_info = Lookup(name_var->var());
2204 if (name_info == nullptr) {
2205 // We can't fail here -- just like above.
2206 auto* call_type = AsmType::Function(zone_, return_type)->AsFunctionType();
2207 for (auto* arg : args) {
2208 call_type->AddArgument(arg->ToParameterType());
2209 }
2210 auto* table_type = AsmType::FunctionTableType(
2211 zone_, table_length, reinterpret_cast<AsmType*>(call_type));
2212 auto* fun_info =
2213 new (zone_) VariableInfo(reinterpret_cast<AsmType*>(table_type));
2214 fun_info->set_mutability(VariableInfo::kImmutableGlobal);
2215 AddForwardReference(name_var, fun_info);
2216 if (!ValidAsmIdentifier(name_var->name())) {
2217 FAIL(name_var,
2218 "Invalid asm.js identifier in (forward) function table name.");
2219 }
2220 if (!AddGlobal(name_var->var(), fun_info)) {
2221 DCHECK(false);
2222 FAIL(call, "Redeclared global identifier.");
2223 }
2224 return return_type;
2225 }
2226
2227 auto* previous_type = name_info->type()->AsFunctionTableType();
2228 if (previous_type == nullptr) {
2229 FAIL(call, "Identifier does not name a function table.");
2230 }
2231
2232 if (table_length != previous_type->length()) {
2233 FAIL(call, "Function table size does not match expected size.");
2234 }
2235
2236 auto* previous_type_signature =
2237 previous_type->signature()->AsFunctionType();
2238 DCHECK(previous_type_signature != nullptr);
2239 if (!CheckInvocationOf(previous_type_signature, return_type, &args)) {
2240 FAIL(call,
2241 "Function pointer table signature does not match previous "
2242 "signature.");
2243 }
2244
2245 return return_type;
2246 }
2247
2248 FAIL(call, "Invalid call.");
2249 }
2250
2251 // 6.10 ValidateHeapAccess
2252 namespace {
2253 bool ExtractHeapAccessShift(Expression* expr, uint32_t* value) {
2254 auto* as_literal = expr->AsLiteral();
2255 if (as_literal == nullptr) {
2256 return false;
2257 }
2258
2259 if (as_literal->raw_value()->ContainsDot()) {
2260 return false;
2261 }
2262
2263 return as_literal->value()->ToUint32(value);
2264 }
2265 } // namespace
2266
2267 AsmType* AsmTyper::ValidateHeapAccess(Property* heap,
2268 HeapAccessType access_type) {
2269 auto* obj = heap->obj()->AsVariableProxy();
2270 if (obj == nullptr) {
2271 FAIL(heap, "Invalid heap access.");
2272 }
2273
2274 auto* obj_info = Lookup(obj->var());
2275 if (obj_info == nullptr) {
2276 FAIL(heap, "Undeclared identifier in heap access.");
2277 }
2278
2279 auto* obj_type = obj_info->type();
2280 if (!obj_type->IsA(AsmType::Heap())) {
2281 FAIL(heap, "Identifier does not represent a heap view.");
2282 }
2283
2284 if (auto* key_as_literal = heap->key()->AsLiteral()) {
2285 if (key_as_literal->raw_value()->ContainsDot()) {
2286 FAIL(key_as_literal, "Heap access index must be intish.");
2287 }
2288
2289 uint32_t _;
2290 if (!key_as_literal->value()->ToUint32(&_)) {
2291 FAIL(key_as_literal,
2292 "Heap access index must be a 32-bit unsigned integer.");
2293 }
2294
2295 if (access_type == LoadFromHeap) {
2296 return obj_type->LoadType();
2297 }
2298 return obj_type->StoreType();
2299 }
2300
2301 if (auto* key_as_binop = heap->key()->AsBinaryOperation()) {
2302 uint32_t shift;
2303 if (key_as_binop->op() == Token::SAR &&
2304 ExtractHeapAccessShift(key_as_binop->right(), &shift) &&
2305 (1 << shift) == obj_type->ElementSizeInBytes()) {
2306 AsmType* type;
2307 RECURSE(type = ValidateExpression(key_as_binop->left()));
2308 if (type->IsA(AsmType::Intish())) {
2309 if (access_type == LoadFromHeap) {
2310 return obj_type->LoadType();
2311 }
2312 return obj_type->StoreType();
2313 }
2314 // TODO(jpp): it may be the case that, if type is not an Intish, we could
2315 // fail here instead of letting the validator try using the "leniency"
2316 // rule (i.e., allow unshifted indexes for heap views of 8-bit integers.
2317 }
2318 }
2319
2320 if (obj_type->ElementSizeInBytes() == 1) {
2321 // Leniency: if this is a byte array, we don't require the shift operation
2322 // to be present.
2323 AsmType* index_type;
2324 RECURSE(index_type = ValidateExpression(heap->key()));
2325 if (!index_type->IsA(AsmType::Int())) {
2326 FAIL(heap, "Invalid heap access index for byte array.");
2327 }
2328 if (access_type == LoadFromHeap) {
2329 return obj_type->LoadType();
2330 }
2331 return obj_type->StoreType();
2332 }
2333
2334 FAIL(heap, "Invalid heap access index.");
2335 }
2336
2337 // 6.11 ValidateFloatCoercion
2338 bool AsmTyper::IsCallToFround(Call* call) {
2339 if (call->arguments()->length() != 1) {
2340 return false;
2341 }
2342
2343 auto* call_var_proxy = call->expression()->AsVariableProxy();
2344 if (call_var_proxy == nullptr) {
2345 return false;
2346 }
2347
2348 auto* call_var_info = Lookup(call_var_proxy->var());
2349 if (call_var_info == nullptr) {
2350 return false;
2351 }
2352
2353 return call_var_info->standard_member() == kMathFround;
2354 }
2355
2356 AsmType* AsmTyper::ValidateFloatCoercion(Call* call) {
2357 if (!IsCallToFround(call)) {
2358 return nullptr;
2359 }
2360
2361 auto* arg = call->arguments()->at(0);
2362 // call is a fround() node. From now, there can be two possible outcomes:
2363 // 1. fround is used as a return type annotation.
2364 if (auto* arg_as_call = arg->AsCall()) {
2365 RECURSE(ValidateCall(AsmType::Float(), arg_as_call));
2366 return AsmType::Float();
2367 }
2368
2369 // 2. fround is used for converting to float.
2370 AsmType* arg_type;
2371 RECURSE(arg_type = ValidateExpression(arg));
2372 if (arg_type->IsA(AsmType::Floatish()) || arg_type->IsA(AsmType::DoubleQ()) ||
2373 arg_type->IsA(AsmType::Signed()) || arg_type->IsA(AsmType::Unsigned())) {
2374 return AsmType::Float();
2375 }
2376
2377 FAIL(call, "Invalid argument type to fround.");
2378 }
2379
2380 // 5.1 ParameterTypeAnnotations
2381 AsmType* AsmTyper::ParameterTypeAnnotations(Variable* parameter,
2382 Expression* annotation) {
2383 if (auto* binop = annotation->AsBinaryOperation()) {
2384 // Must be:
2385 // * x|0
2386 // * x*1 (*VIOLATION* i.e.,, +x)
2387 auto* left = binop->left()->AsVariableProxy();
2388 if (left == nullptr) {
2389 FAIL(
2390 binop->left(),
2391 "Invalid parameter type annotation - should annotate an identifier.");
2392 }
2393 if (left->var() != parameter) {
2394 FAIL(binop->left(),
2395 "Invalid parameter type annotation - should annotate a parameter.");
2396 }
2397 if (IsDoubleAnnotation(binop)) {
2398 return AsmType::Double();
2399 }
2400 if (IsIntAnnotation(binop)) {
2401 return AsmType::Int();
2402 }
2403 FAIL(binop, "Invalid parameter type annotation.");
2404 }
2405
2406 auto* call = annotation->AsCall();
2407 if (call == nullptr) {
2408 FAIL(
2409 annotation,
2410 "Invalid float parameter type annotation - must be fround(parameter).");
2411 }
2412
2413 if (!IsCallToFround(call)) {
2414 FAIL(annotation,
2415 "Invalid float parameter type annotation - must be call to fround.");
2416 }
2417
2418 auto* src_expr = call->arguments()->at(0)->AsVariableProxy();
2419 if (src_expr == nullptr) {
2420 FAIL(annotation,
2421 "Invalid float parameter type annotation - argument to fround is not "
2422 "an identifier.");
2423 }
2424
2425 if (src_expr->var() != parameter) {
2426 FAIL(annotation,
2427 "Invalid float parameter type annotation - argument to fround is not "
2428 "a parameter.");
2429 }
2430
2431 return AsmType::Float();
2432 }
2433
2434 // 5.2 ReturnTypeAnnotations
2435 AsmType* AsmTyper::ReturnTypeAnnotations(ReturnStatement* statement) {
2436 if (statement == nullptr) {
2437 return AsmType::Void();
2438 }
2439
2440 auto* ret_expr = statement->expression();
2441 if (ret_expr == nullptr) {
2442 return AsmType::Void();
2443 }
2444
2445 if (auto* binop = ret_expr->AsBinaryOperation()) {
2446 if (IsDoubleAnnotation(binop)) {
2447 return AsmType::Double();
2448 } else if (IsIntAnnotation(binop)) {
2449 return AsmType::Signed();
2450 }
2451 FAIL(statement, "Invalid return type annotation.");
2452 }
2453
2454 if (auto* call = ret_expr->AsCall()) {
2455 if (IsCallToFround(call)) {
2456 return AsmType::Float();
2457 }
2458 FAIL(statement, "Invalid function call in return statement.");
2459 }
2460
2461 if (auto* literal = ret_expr->AsLiteral()) {
2462 int32_t _;
2463 if (literal->raw_value()->ContainsDot()) {
2464 return AsmType::Double();
2465 } else if (literal->value()->ToInt32(&_)) {
2466 return AsmType::Signed();
2467 } else if (literal->IsUndefinedLiteral()) {
2468 // *VIOLATION* The parser changes
2469 //
2470 // return;
2471 //
2472 // into
2473 //
2474 // return undefined
2475 return AsmType::Void();
2476 }
2477 FAIL(statement, "Invalid literal in return statement.");
2478 }
2479
2480 FAIL(statement, "Invalid return type expression.");
2481 }
2482
2483 // 5.4 VariableTypeAnnotations
2484 // Also used for 5.5 GlobalVariableTypeAnnotations
2485 AsmType* AsmTyper::VariableTypeAnnotations(Expression* initializer) {
2486 if (auto* literal = initializer->AsLiteral()) {
2487 if (literal->raw_value()->ContainsDot()) {
2488 return AsmType::Double();
2489 }
2490 int32_t i32;
2491 uint32_t u32;
2492 if (literal->value()->ToInt32(&i32) || literal->value()->ToUint32(&u32)) {
2493 return AsmType::Int();
2494 }
2495 FAIL(initializer, "Invalid type annotation - forbidden literal.");
2496 }
2497
2498 auto* call = initializer->AsCall();
2499 DCHECK(call != nullptr);
2500 if (call == nullptr) {
2501 FAIL(initializer,
2502 "Invalid variable initialization - it should be a literal, or "
2503 "fround(literal).");
2504 }
2505
2506 if (!IsCallToFround(call)) {
2507 FAIL(initializer,
2508 "Invalid float coercion - expected call fround(literal).");
2509 }
2510
2511 auto* src_expr = call->arguments()->at(0)->AsLiteral();
2512 if (src_expr == nullptr) {
2513 FAIL(initializer,
2514 "Invalid float type annotation - expected literal argument for call "
2515 "to fround.");
2516 }
2517
2518 if (!src_expr->raw_value()->ContainsDot()) {
2519 FAIL(initializer,
2520 "Invalid float type annotation - expected literal argument to be a "
2521 "floating point literal.");
2522 }
2523
2524 return AsmType::Float();
2525 }
2526
2527 // 5.5 GlobalVariableTypeAnnotations
2528 AsmType* AsmTyper::NewHeapView(CallNew* new_heap_view) {
2529 auto* heap_type = new_heap_view->expression()->AsProperty();
2530 if (heap_type == nullptr) {
2531 FAIL(new_heap_view, "Invalid type after new.");
2532 }
2533 auto* heap_view_info = ImportLookup(heap_type);
2534
2535 if (heap_view_info == nullptr) {
2536 FAIL(new_heap_view, "Unknown stdlib member in heap view declaration.");
2537 }
2538
2539 if (!heap_view_info->type()->IsA(AsmType::Heap())) {
2540 FAIL(new_heap_view, "Type is not a heap view type.");
2541 }
2542
2543 if (new_heap_view->arguments()->length() != 1) {
2544 FAIL(new_heap_view, "Invalid number of arguments when creating heap view.");
2545 }
2546
2547 auto* heap = new_heap_view->arguments()->at(0);
2548 auto* heap_var_proxy = heap->AsVariableProxy();
2549
2550 if (heap_var_proxy == nullptr) {
2551 FAIL(heap,
2552 "Heap view creation parameter should be the module's heap parameter.");
2553 }
2554
2555 auto* heap_var_info = Lookup(heap_var_proxy->var());
2556
2557 if (heap_var_info == nullptr) {
2558 FAIL(heap, "Undeclared identifier instead of heap parameter.");
2559 }
2560
2561 if (!heap_var_info->IsHeap()) {
2562 FAIL(heap,
2563 "Heap view creation parameter should be the module's heap parameter.");
2564 }
2565
2566 DCHECK(heap_view_info->type()->IsA(AsmType::Heap()));
2567 return heap_view_info->type();
2568 }
2569
2570 bool IsValidAsm(Isolate* isolate, Zone* zone, Script* script,
2571 FunctionLiteral* root, std::string* error_message) {
2572 error_message->clear();
2573
2574 AsmTyper typer(isolate, zone, script, root);
2575 if (typer.Validate()) {
2576 return true;
2577 }
2578
2579 *error_message = typer.error_message();
2580 return false;
2581 }
2582
2583 } // namespace wasm
2584 } // namespace internal
2585 } // namespace v8
OLDNEW
« no previous file with comments | « src/asmjs/asm-typer.h ('k') | src/asmjs/asm-types.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698