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