Line data Source code
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<FixedArray>::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 :
79 2954 : AsmTyper::FlattenedStatements::FlattenedStatements(Zone* zone,
80 : ZoneList<Statement*>* s)
81 : : context_stack_(zone) {
82 111004 : context_stack_.emplace_back(Context(s));
83 2954 : }
84 :
85 501869 : Statement* AsmTyper::FlattenedStatements::Next() {
86 : for (;;) {
87 658161 : if (context_stack_.empty()) {
88 : return nullptr;
89 : }
90 :
91 : Context* current = &context_stack_.back();
92 :
93 548922 : if (current->statements_->length() <= current->next_index_) {
94 : context_stack_.pop_back();
95 : continue;
96 : }
97 :
98 : Statement* current_statement =
99 832962 : current->statements_->at(current->next_index_++);
100 416481 : if (current_statement->IsBlock()) {
101 : context_stack_.emplace_back(
102 71553 : Context(current_statement->AsBlock()->statements()));
103 23851 : continue;
104 : }
105 :
106 : return current_statement;
107 : }
108 : }
109 :
110 : // ----------------------------------------------------------------------------
111 : // Implementation of AsmTyper::SourceLayoutTracker
112 :
113 3158 : bool AsmTyper::SourceLayoutTracker::IsValid() const {
114 : const Section* kAllSections[] = {&use_asm_, &globals_, &functions_, &tables_,
115 3158 : &exports_};
116 21784 : for (size_t ii = 0; ii < arraysize(kAllSections); ++ii) {
117 15559 : const auto& curr_section = *kAllSections[ii];
118 46726 : for (size_t jj = ii + 1; jj < arraysize(kAllSections); ++jj) {
119 62516 : if (curr_section.IsPrecededBy(*kAllSections[jj])) {
120 : return false;
121 : }
122 : }
123 : }
124 : return true;
125 : }
126 :
127 33310 : void AsmTyper::SourceLayoutTracker::Section::AddNewElement(
128 33310 : const AstNode& node) {
129 33310 : const int node_pos = node.position();
130 33310 : if (start_ == kNoSourcePosition) {
131 13593 : start_ = node_pos;
132 : } else {
133 39434 : start_ = std::min(start_, node_pos);
134 : }
135 33310 : if (end_ == kNoSourcePosition) {
136 13593 : end_ = node_pos;
137 : } else {
138 39434 : end_ = std::max(end_, node_pos);
139 : }
140 33310 : }
141 :
142 0 : bool AsmTyper::SourceLayoutTracker::Section::IsPrecededBy(
143 : const Section& other) const {
144 31258 : if (start_ == kNoSourcePosition) {
145 : DCHECK_EQ(end_, kNoSourcePosition);
146 : return false;
147 : }
148 24761 : 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 15187 : return other.start_ <= end_;
155 : }
156 :
157 : // ----------------------------------------------------------------------------
158 : // Implementation of AsmTyper::VariableInfo
159 :
160 366888 : 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 366888 : new_var_info->standard_member_ = standard_member;
166 366888 : new_var_info->mutability_ = kImmutableGlobal;
167 366888 : return new_var_info;
168 : }
169 :
170 10446 : AsmTyper::VariableInfo* AsmTyper::VariableInfo::Clone(Zone* zone) const {
171 10446 : CHECK(standard_member_ != kNone);
172 10446 : CHECK(!type_->IsA(AsmType::None()));
173 10446 : auto* new_var_info = new (zone) VariableInfo(type_);
174 10446 : new_var_info->standard_member_ = standard_member_;
175 10446 : new_var_info->mutability_ = mutability_;
176 10446 : return new_var_info;
177 : }
178 :
179 210 : void AsmTyper::VariableInfo::SetFirstForwardUse(
180 : const MessageLocation& source_location) {
181 3023 : missing_definition_ = true;
182 3023 : source_location_ = source_location;
183 210 : }
184 :
185 : // ----------------------------------------------------------------------------
186 : // Implementation of AsmTyper
187 :
188 358819 : 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 358819 : module_info_(VariableInfo::ForSpecialSymbol(zone_, kModule)),
199 : global_scope_(ZoneHashMap::kDefaultHashMapCapacity,
200 : ZoneAllocationPolicy(zone)),
201 : local_scope_(ZoneHashMap::kDefaultHashMapCapacity,
202 : ZoneAllocationPolicy(zone)),
203 358818 : stack_limit_(isolate->stack_guard()->real_climit()),
204 358819 : fround_type_(AsmType::FroundType(zone_)),
205 358819 : ffi_type_(AsmType::FFIType(zone_)),
206 3229369 : function_pointer_tables_(zone_) {
207 358819 : InitializeStdlib();
208 358818 : }
209 :
210 : namespace {
211 84027 : bool ValidAsmIdentifier(Handle<String> name) {
212 : static const char* kInvalidAsmNames[] = {"eval", "arguments"};
213 :
214 251752 : for (size_t ii = 0; ii < arraysize(kInvalidAsmNames); ++ii) {
215 671768 : if (strcmp(name->ToCString().get(), kInvalidAsmNames[ii]) == 0) {
216 : return false;
217 : }
218 : }
219 : return true;
220 : }
221 : } // namespace
222 :
223 358819 : void AsmTyper::InitializeStdlib() {
224 : auto* d = AsmType::Double();
225 : auto* dq = AsmType::DoubleQ();
226 358819 : auto* dq2d = AsmType::Function(zone_, d);
227 : dq2d->AsFunctionType()->AddArgument(dq);
228 :
229 358819 : 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 358818 : auto* fq2f = AsmType::Function(zone_, f);
236 : fq2f->AsFunctionType()->AddArgument(fq);
237 :
238 : auto* s = AsmType::Signed();
239 358819 : auto* s2s = AsmType::Function(zone_, s);
240 : s2s->AsFunctionType()->AddArgument(s);
241 :
242 : auto* i = AsmType::Int();
243 358818 : auto* i2s = AsmType::Function(zone_, s);
244 : i2s->AsFunctionType()->AddArgument(i);
245 :
246 358818 : auto* ii2s = AsmType::Function(zone_, s);
247 : ii2s->AsFunctionType()->AddArgument(i);
248 : ii2s->AsFunctionType()->AddArgument(i);
249 :
250 358819 : 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 358819 : auto* minmax_f = AsmType::MinMaxType(zone_, f, f);
254 358819 : auto* minmax_i = AsmType::MinMaxType(zone_, s, i);
255 358819 : auto* minmax = AsmType::OverloadedFunction(zone_);
256 358817 : minmax->AsOverloadedFunctionType()->AddOverload(minmax_i);
257 358820 : minmax->AsOverloadedFunctionType()->AddOverload(minmax_f);
258 358819 : minmax->AsOverloadedFunctionType()->AddOverload(minmax_d);
259 :
260 358819 : auto* fround = fround_type_;
261 :
262 358819 : auto* abs = AsmType::OverloadedFunction(zone_);
263 358820 : abs->AsOverloadedFunctionType()->AddOverload(s2s);
264 358819 : abs->AsOverloadedFunctionType()->AddOverload(dq2d);
265 358820 : abs->AsOverloadedFunctionType()->AddOverload(fq2f);
266 :
267 358819 : auto* ceil = AsmType::OverloadedFunction(zone_);
268 358819 : ceil->AsOverloadedFunctionType()->AddOverload(dq2d);
269 358819 : 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 358806 : };
297 3946996 : for (size_t ii = 0; ii < arraysize(stdlib); ++ii) {
298 14352741 : stdlib_types_[stdlib[ii].name] = new (zone_) VariableInfo(stdlib[ii].type);
299 7176371 : stdlib_types_[stdlib[ii].name]->set_standard_member(
300 7176369 : stdlib[ii].standard_member);
301 7176378 : stdlib_types_[stdlib[ii].name]->set_mutability(
302 3588180 : 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 358806 : };
337 10046909 : for (size_t ii = 0; ii < arraysize(math); ++ii) {
338 38752360 : stdlib_math_types_[math[ii].name] = new (zone_) VariableInfo(math[ii].type);
339 19376198 : stdlib_math_types_[math[ii].name]->set_standard_member(
340 19376161 : math[ii].standard_member);
341 19376211 : stdlib_math_types_[math[ii].name]->set_mutability(
342 9688045 : VariableInfo::kImmutableGlobal);
343 : }
344 358817 : }
345 :
346 : // Used for 5.5 GlobalVariableTypeAnnotations
347 11780 : AsmTyper::VariableInfo* AsmTyper::ImportLookup(Property* import) {
348 : auto* obj = import->obj();
349 20686 : auto* key = import->key()->AsLiteral();
350 11780 : if (key == nullptr) {
351 : return nullptr;
352 : }
353 :
354 11774 : ObjectTypeMap* stdlib = &stdlib_types_;
355 30897 : if (auto* obj_as_property = obj->AsProperty()) {
356 : // This can only be stdlib.Math
357 14754 : auto* math_name = obj_as_property->key()->AsLiteral();
358 14754 : if (math_name == nullptr || !math_name->IsPropertyName()) {
359 : return nullptr;
360 : }
361 :
362 7377 : if (!math_name->AsPropertyName()->IsUtf8EqualTo(CStrVector("Math"))) {
363 : return nullptr;
364 : }
365 :
366 7349 : auto* stdlib_var_proxy = obj_as_property->obj()->AsVariableProxy();
367 7349 : if (stdlib_var_proxy == nullptr) {
368 : return nullptr;
369 : }
370 : obj = stdlib_var_proxy;
371 7349 : stdlib = &stdlib_math_types_;
372 : }
373 :
374 23478 : auto* obj_as_var_proxy = obj->AsVariableProxy();
375 11746 : if (obj_as_var_proxy == nullptr) {
376 : return nullptr;
377 : }
378 :
379 23423 : auto* obj_info = Lookup(obj_as_var_proxy->var());
380 11732 : if (obj_info == nullptr) {
381 : return nullptr;
382 : }
383 :
384 11691 : 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 8906 : if (!key->IsPropertyName()) {
390 : return nullptr;
391 : }
392 :
393 8900 : std::unique_ptr<char[]> aname = key->AsPropertyName()->ToCString();
394 17800 : ObjectTypeMap::iterator i = stdlib->find(std::string(aname.get()));
395 8900 : if (i == stdlib->end()) {
396 : return nullptr;
397 : }
398 17744 : stdlib_uses_.insert(i->second->standard_member());
399 8872 : return i->second;
400 : }
401 :
402 1614664 : AsmTyper::VariableInfo* AsmTyper::Lookup(Variable* variable) const {
403 1208321 : const ZoneHashMap* scope = in_function_ ? &local_scope_ : &global_scope_;
404 : ZoneHashMap::Entry* entry =
405 1208321 : scope->Lookup(variable, ComputePointerHash(variable));
406 1208321 : if (entry == nullptr && in_function_) {
407 201779 : entry = global_scope_.Lookup(variable, ComputePointerHash(variable));
408 : }
409 :
410 2021196 : if (entry == nullptr && !module_name_.is_null() &&
411 406343 : module_name_->Equals(*variable->name())) {
412 35 : return module_info_;
413 : }
414 :
415 1208286 : return entry ? reinterpret_cast<VariableInfo*>(entry->value) : nullptr;
416 : }
417 :
418 2813 : void AsmTyper::AddForwardReference(VariableProxy* proxy, VariableInfo* info) {
419 2813 : MessageLocation location(script_, proxy->position(), proxy->position());
420 2813 : info->SetFirstForwardUse(location);
421 2813 : forward_definitions_.push_back(info);
422 2813 : }
423 :
424 82711 : 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 82711 : if (!module_name_.is_null() && module_name_->Equals(*variable->name())) {
432 : return false;
433 : }
434 :
435 : ZoneHashMap::Entry* entry = global_scope_.LookupOrInsert(
436 156921 : variable, ComputePointerHash(variable), ZoneAllocationPolicy(zone_));
437 :
438 52307 : if (entry->value != nullptr) {
439 : return false;
440 : }
441 :
442 52286 : entry->value = info;
443 52286 : return true;
444 : }
445 :
446 64825 : 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 194475 : variable, ComputePointerHash(variable), ZoneAllocationPolicy(zone_));
454 :
455 64825 : if (entry->value != nullptr) {
456 : return false;
457 : }
458 :
459 64804 : entry->value = info;
460 64804 : return true;
461 : }
462 :
463 1793160 : void AsmTyper::SetTypeOf(AstNode* node, AsmType* type) {
464 : DCHECK_NE(type, AsmType::None());
465 1793160 : if (in_function_) {
466 : DCHECK(function_node_types_.find(node) == function_node_types_.end());
467 3503356 : function_node_types_.insert(std::make_pair(node, type));
468 : } else {
469 : DCHECK(module_node_types_.find(node) == module_node_types_.end());
470 82964 : module_node_types_.insert(std::make_pair(node, type));
471 : }
472 1793160 : }
473 :
474 : namespace {
475 335024 : bool IsLiteralDouble(Literal* literal) {
476 668475 : return literal->raw_value()->IsNumber() &&
477 335024 : literal->raw_value()->ContainsDot();
478 : }
479 :
480 393569 : bool IsLiteralInt(Literal* literal) {
481 785571 : return literal->raw_value()->IsNumber() &&
482 393569 : !literal->raw_value()->ContainsDot();
483 : }
484 :
485 12034 : bool IsLiteralMinus1(Literal* literal) {
486 12034 : return IsLiteralInt(literal) && literal->raw_value()->AsNumber() == -1.0;
487 : }
488 :
489 35913 : bool IsLiteral1Dot0(Literal* literal) {
490 35913 : return IsLiteralDouble(literal) && literal->raw_value()->AsNumber() == 1.0;
491 : }
492 :
493 389296 : bool IsLiteral0(Literal* literal) {
494 389296 : return IsLiteralInt(literal) && literal->raw_value()->AsNumber() == 0.0;
495 : }
496 : } // namespace
497 :
498 2222678 : AsmType* AsmTyper::TypeOf(AstNode* node) const {
499 : auto node_type_iter = function_node_types_.find(node);
500 2222678 : if (node_type_iter != function_node_types_.end()) {
501 2204409 : return node_type_iter->second;
502 : }
503 : node_type_iter = module_node_types_.find(node);
504 18269 : if (node_type_iter != module_node_types_.end()) {
505 6365 : 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 37126 : if (auto* literal = node->AsLiteral()) {
511 11850 : if (IsLiteralDouble(literal)) {
512 11850 : return AsmType::Double();
513 : }
514 11850 : if (!IsLiteralInt(literal)) {
515 : return AsmType::None();
516 : }
517 : uint32_t u;
518 11850 : if (literal->value()->ToUint32(&u)) {
519 10382 : if (u > LargestFixNum) {
520 : return AsmType::Unsigned();
521 : }
522 10358 : return AsmType::FixNum();
523 : }
524 : int32_t i;
525 1468 : if (literal->value()->ToInt32(&i)) {
526 : return AsmType::Signed();
527 : }
528 : }
529 :
530 : return AsmType::None();
531 : }
532 :
533 11154 : AsmType* AsmTyper::TypeOf(Variable* v) const { return Lookup(v)->type(); }
534 :
535 420760 : AsmTyper::StandardMember AsmTyper::VariableAsStandardMember(Variable* var) {
536 461956 : auto* var_info = Lookup(var);
537 420760 : if (var_info == nullptr) {
538 : return kNone;
539 : }
540 : StandardMember member = var_info->standard_member();
541 41196 : return member;
542 : }
543 :
544 0 : AsmType* AsmTyper::FailWithMessage(const char* text) {
545 0 : FAIL_RAW(root_, OneByteVector(text));
546 : }
547 :
548 1169 : bool AsmTyper::Validate() {
549 1806 : return ValidateBeforeFunctionsPhase() &&
550 1505 : !AsmType::None()->IsExactly(ValidateModuleFunctions(root_)) &&
551 1505 : ValidateAfterFunctionsPhase();
552 : }
553 :
554 4701 : bool AsmTyper::ValidateBeforeFunctionsPhase() {
555 4701 : if (!AsmType::None()->IsExactly(ValidateModuleBeforeFunctionsPhase(root_))) {
556 : return true;
557 : }
558 653 : return false;
559 : }
560 :
561 11256 : bool AsmTyper::ValidateInnerFunction(FunctionDeclaration* fun_decl) {
562 11256 : if (!AsmType::None()->IsExactly(ValidateModuleFunction(fun_decl))) {
563 : return true;
564 : }
565 300 : return false;
566 : }
567 :
568 3441 : bool AsmTyper::ValidateAfterFunctionsPhase() {
569 3441 : if (!AsmType::None()->IsExactly(ValidateModuleAfterFunctionsPhase(root_))) {
570 : return true;
571 : }
572 374 : return false;
573 : }
574 :
575 21912 : void AsmTyper::ClearFunctionNodeTypes() { function_node_types_.clear(); }
576 :
577 24 : AsmType* AsmTyper::TriggerParsingError() { FAIL(root_, "Parsing error"); }
578 :
579 : namespace {
580 4570 : bool IsUseAsmDirective(Statement* first_statement) {
581 9140 : ExpressionStatement* use_asm = first_statement->AsExpressionStatement();
582 4570 : if (use_asm == nullptr) {
583 : return false;
584 : }
585 :
586 9133 : Literal* use_asm_literal = use_asm->expression()->AsLiteral();
587 :
588 4570 : if (use_asm_literal == nullptr) {
589 : return false;
590 : }
591 :
592 9126 : return use_asm_literal->raw_value()->AsString()->IsOneByteEqualTo("use asm");
593 : }
594 :
595 59574 : Assignment* ExtractInitializerExpression(Statement* statement) {
596 111327 : auto* expr_stmt = statement->AsExpressionStatement();
597 59574 : if (expr_stmt == nullptr) {
598 : // Done with initializers.
599 : return nullptr;
600 : }
601 103047 : auto* assign = expr_stmt->expression()->AsAssignment();
602 51753 : if (assign == nullptr) {
603 : // Done with initializers.
604 : return nullptr;
605 : }
606 51294 : if (assign->op() != Token::INIT) {
607 : // Done with initializers.
608 : return nullptr;
609 : }
610 45304 : return assign;
611 : }
612 :
613 : } // namespace
614 :
615 : // 6.1 ValidateModule
616 18654 : AsmType* AsmTyper::ValidateModuleBeforeFunctionsPhase(FunctionLiteral* fun) {
617 : DeclarationScope* scope = fun->scope();
618 4860 : if (!scope->is_function_scope()) FAIL(fun, "Not at function scope.");
619 4701 : if (scope->inner_scope_calls_eval()) {
620 24 : FAIL(fun, "Invalid asm.js module using eval.");
621 : }
622 4695 : if (!ValidAsmIdentifier(fun->name()))
623 56 : FAIL(fun, "Invalid asm.js identifier in module name.");
624 4681 : module_name_ = fun->name();
625 :
626 : // Allowed parameters: Stdlib, FFI, Mem
627 : static const int MaxModuleParameters = 3;
628 4681 : if (scope->num_parameters() > MaxModuleParameters) {
629 80 : 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 4661 : };
637 :
638 19748 : for (int ii = 0; ii < scope->num_parameters(); ++ii) {
639 5297 : Variable* param = scope->parameter(ii);
640 : DCHECK(param);
641 :
642 5297 : if (!ValidAsmIdentifier(param->name())) {
643 168 : FAIL(fun, "Invalid asm.js identifier in module parameter.");
644 : }
645 :
646 : auto* param_info = VariableInfo::ForSpecialSymbol(
647 5255 : zone_, kModuleParamInfo[ii].standard_member);
648 :
649 5255 : if (!AddGlobal(param, param_info)) {
650 168 : FAIL(fun, "Redeclared identifier in module parameter.");
651 : }
652 : }
653 :
654 4577 : FlattenedStatements iter(zone_, fun->body());
655 4577 : auto* use_asm_directive = iter.Next();
656 4577 : if (use_asm_directive == nullptr) {
657 28 : 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 9140 : ExpressionStatement* estatement = use_asm_directive->AsExpressionStatement();
662 4570 : if (estatement != nullptr) {
663 9334 : Assignment* assignment = estatement->expression()->AsAssignment();
664 9334 : if (assignment != nullptr && assignment->target()->IsVariableProxy() &&
665 : assignment->target()
666 : ->AsVariableProxy()
667 : ->var()
668 4764 : ->is_sloppy_function_name()) {
669 2382 : use_asm_directive = iter.Next();
670 : }
671 : }
672 4570 : if (!IsUseAsmDirective(use_asm_directive)) {
673 112 : FAIL(fun, "Missing \"use asm\".");
674 : }
675 4542 : source_layout_.AddUseAsm(*use_asm_directive);
676 4542 : 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 22338 : while (Statement* current = iter.Next()) {
683 18290 : if (auto* assign = ExtractInitializerExpression(current)) {
684 14565 : if (assign->value()->IsArrayLiteral()) {
685 : // Save function tables for later validation.
686 381 : function_pointer_tables_.push_back(assign);
687 : } else {
688 14184 : RECURSE(ValidateGlobalDeclaration(assign));
689 13738 : source_layout_.AddGlobal(*assign);
690 : }
691 14119 : continue;
692 : }
693 :
694 7498 : if (auto* current_as_return = current->AsReturnStatement()) {
695 3677 : if (module_return_ != nullptr) {
696 0 : FAIL(fun, "Multiple export statements.");
697 : }
698 3677 : module_return_ = current_as_return;
699 3677 : source_layout_.AddExport(*module_return_);
700 : continue;
701 : }
702 :
703 192 : 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 :
709 11690 : AsmType* AsmTyper::ValidateModuleFunction(FunctionDeclaration* fun_decl) {
710 11690 : RECURSE(ValidateFunction(fun_decl));
711 11089 : source_layout_.AddFunction(*fun_decl);
712 :
713 11089 : return AsmType::Int(); // Any type that is not AsmType::None();
714 : }
715 :
716 637 : AsmType* AsmTyper::ValidateModuleFunctions(FunctionLiteral* fun) {
717 : DeclarationScope* scope = fun->scope();
718 : Declaration::List* decls = scope->declarations();
719 1736 : for (Declaration* decl : *decls) {
720 1526 : if (FunctionDeclaration* fun_decl = decl->AsFunctionDeclaration()) {
721 434 : RECURSE(ValidateModuleFunction(fun_decl));
722 : continue;
723 : }
724 : }
725 :
726 : return AsmType::Int(); // Any type that is not AsmType::None();
727 : }
728 :
729 6777 : AsmType* AsmTyper::ValidateModuleAfterFunctionsPhase(FunctionLiteral* fun) {
730 7146 : for (auto* function_table : function_pointer_tables_) {
731 369 : RECURSE(ValidateFunctionTable(function_table));
732 264 : source_layout_.AddTable(*function_table);
733 : }
734 :
735 : DeclarationScope* scope = fun->scope();
736 : Declaration::List* decls = scope->declarations();
737 31565 : for (Declaration* decl : *decls) {
738 24907 : if (decl->IsFunctionDeclaration()) {
739 : continue;
740 : }
741 :
742 13841 : VariableDeclaration* var_decl = decl->AsVariableDeclaration();
743 13841 : if (var_decl == nullptr) {
744 0 : FAIL(decl, "Invalid asm.js declaration.");
745 : }
746 :
747 27682 : auto* var_proxy = var_decl->proxy();
748 13841 : if (var_proxy == nullptr) {
749 0 : FAIL(decl, "Invalid asm.js declaration.");
750 : }
751 :
752 13841 : if (Lookup(var_proxy->var()) == nullptr) {
753 28 : FAIL(decl, "Global variable missing initializer in asm.js module.");
754 : }
755 : }
756 :
757 : // 6.2 ValidateExport
758 3329 : if (module_return_ == nullptr) {
759 119 : FAIL(fun, "Missing asm.js module export.");
760 : }
761 :
762 9315 : for (auto* forward_def : forward_definitions_) {
763 2683 : if (forward_def->missing_definition()) {
764 36 : FAIL_LOCATION(forward_def->source_location(),
765 : "Missing definition for forward declared identifier.");
766 : }
767 : }
768 :
769 3310 : RECURSE(ValidateExport(module_return_));
770 :
771 3158 : if (!source_layout_.IsValid()) {
772 364 : 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 {
779 74492 : bool IsDoubleAnnotation(BinaryOperation* binop) {
780 : // *VIOLATION* The parser replaces uses of +x with x*1.0.
781 47017 : if (binop->op() != Token::MUL) {
782 : return false;
783 : }
784 :
785 27475 : auto* right_as_literal = binop->right()->AsLiteral();
786 27475 : if (right_as_literal == nullptr) {
787 : return false;
788 : }
789 :
790 20203 : return IsLiteral1Dot0(right_as_literal);
791 : }
792 :
793 397375 : bool IsIntAnnotation(BinaryOperation* binop) {
794 198701 : if (binop->op() != Token::BIT_OR) {
795 : return false;
796 : }
797 :
798 198674 : auto* right_as_literal = binop->right()->AsLiteral();
799 198674 : if (right_as_literal == nullptr) {
800 : return false;
801 : }
802 :
803 194651 : return IsLiteral0(right_as_literal);
804 : }
805 : } // namespace
806 :
807 42524 : AsmType* AsmTyper::ValidateGlobalDeclaration(Assignment* assign) {
808 : DCHECK(!assign->is_compound());
809 14184 : if (assign->is_compound()) {
810 89 : FAIL(assign,
811 : "Compound assignment not supported when declaring global variables.");
812 : }
813 :
814 : auto* target = assign->target();
815 14310 : if (!target->IsVariableProxy()) {
816 0 : FAIL(target, "Module assignments may only assign to globals.");
817 : }
818 44524 : auto* target_variable = target->AsVariableProxy()->var();
819 94754 : auto* target_info = Lookup(target_variable);
820 :
821 14184 : if (target_info != nullptr) {
822 112 : 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 26154 : if (value->IsLiteral() || value->IsCall()) {
830 : AsmType* type = nullptr;
831 : VariableInfo::Mutability mutability;
832 2314 : if (target_variable->mode() == CONST) {
833 : mutability = VariableInfo::kConstGlobal;
834 : } else {
835 : mutability = VariableInfo::kMutableGlobal;
836 : }
837 2314 : RECURSE(type = VariableTypeAnnotations(value, mutability));
838 2267 : target_info = new (zone_) VariableInfo(type);
839 : target_info->set_mutability(mutability);
840 : global_variable = true;
841 11842 : } else if (value->IsProperty()) {
842 19594 : target_info = ImportLookup(value->AsProperty());
843 9797 : if (target_info == nullptr) {
844 300 : FAIL(assign, "Invalid import.");
845 : }
846 9722 : CHECK(target_info->mutability() == VariableInfo::kImmutableGlobal);
847 9722 : if (target_info->IsFFI()) {
848 : // create a new target info that represents a foreign variable.
849 4614 : target_info = new (zone_) VariableInfo(ffi_type_);
850 : target_info->set_mutability(VariableInfo::kImmutableGlobal);
851 7415 : } else if (target_info->type()->IsA(AsmType::Heap())) {
852 28 : FAIL(assign, "Heap view types can not be aliased.");
853 : } else {
854 7408 : target_info = target_info->Clone(zone_);
855 : }
856 2045 : } else if (value->IsBinaryOperation()) {
857 : // This should either be:
858 : //
859 : // var <> = ffi.<>|0
860 : //
861 : // or
862 : //
863 : // var <> = +ffi.<>
864 1108 : auto* value_binop = value->AsBinaryOperation();
865 : auto* left = value_binop->left();
866 : AsmType* import_type = nullptr;
867 :
868 554 : if (IsDoubleAnnotation(value_binop)) {
869 : import_type = AsmType::Double();
870 380 : } else if (IsIntAnnotation(value_binop)) {
871 : import_type = AsmType::Int();
872 : } else {
873 56 : FAIL(value,
874 : "Invalid initializer for foreign import - unrecognized annotation.");
875 : }
876 :
877 540 : if (!left->IsProperty()) {
878 56 : FAIL(value,
879 : "Invalid initializer for foreign import - must import member.");
880 : }
881 1052 : target_info = ImportLookup(left->AsProperty());
882 526 : 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 136 : FAIL(value,
887 : "Invalid initializer for foreign import - object lookup failed.");
888 : }
889 492 : CHECK(target_info->mutability() == VariableInfo::kImmutableGlobal);
890 492 : if (!target_info->IsFFI()) {
891 56 : 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 478 : target_info = new (zone_) VariableInfo(import_type);
897 : target_info->set_mutability(VariableInfo::kMutableGlobal);
898 1491 : } else if (value->IsCallNew()) {
899 : AsmType* type = nullptr;
900 2928 : RECURSE(type = NewHeapView(value->AsCallNew()));
901 1370 : target_info = new (zone_) VariableInfo(type);
902 : target_info->set_mutability(VariableInfo::kImmutableGlobal);
903 54 : } else if (auto* proxy = value->AsVariableProxy()) {
904 39 : auto* var_info = Lookup(proxy->var());
905 :
906 20 : if (var_info == nullptr) {
907 28 : FAIL(value, "Undeclared identifier in global initializer");
908 : }
909 :
910 13 : if (var_info->mutability() != VariableInfo::kConstGlobal) {
911 28 : FAIL(value, "Identifier used to initialize a global must be a const");
912 : }
913 :
914 6 : target_info = new (zone_) VariableInfo(var_info->type());
915 6 : 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 13843 : if (target_info == nullptr) {
923 28 : FAIL(assign, "Invalid global variable initializer.");
924 : }
925 :
926 13836 : if (!ValidAsmIdentifier(target_variable->name())) {
927 392 : FAIL(target, "Invalid asm.js identifier in global variable.");
928 : }
929 :
930 13738 : if (!AddGlobal(target_variable, target_info)) {
931 0 : FAIL(assign, "Redeclared global identifier.");
932 : }
933 :
934 : DCHECK(target_info->type() != AsmType::None());
935 13738 : if (!global_variable) {
936 : // Global variables have their types set in VariableTypeAnnotations.
937 11513 : SetTypeOf(value, target_info->type());
938 : }
939 13738 : SetTypeOf(assign, target_info->type());
940 13738 : SetTypeOf(target, target_info->type());
941 13738 : return target_info->type();
942 : }
943 :
944 : // 6.2 ValidateExport
945 9316 : AsmType* AsmTyper::ExportType(VariableProxy* fun_export) {
946 18667 : auto* fun_info = Lookup(fun_export->var());
947 4707 : if (fun_info == nullptr) {
948 167 : FAIL(fun_export, "Undefined identifier in asm.js module export.");
949 : }
950 :
951 4686 : if (fun_info->standard_member() != kNone) {
952 112 : FAIL(fun_export, "Module cannot export standard library functions.");
953 : }
954 :
955 : auto* type = fun_info->type();
956 4658 : if (type->AsFFIType() != nullptr) {
957 84 : FAIL(fun_export, "Module cannot export foreign functions.");
958 : }
959 :
960 4637 : if (type->AsFunctionTableType() != nullptr) {
961 84 : FAIL(fun_export, "Module cannot export function tables.");
962 : }
963 :
964 4616 : if (fun_info->type()->AsFunctionType() == nullptr) {
965 28 : FAIL(fun_export, "Module export is not an asm.js function.");
966 : }
967 :
968 4609 : if (!fun_export->var()->is_function()) {
969 24 : FAIL(fun_export, "Module exports must be function declarations.");
970 : }
971 :
972 : return type;
973 : }
974 :
975 6399 : AsmType* AsmTyper::ValidateExport(ReturnStatement* exports) {
976 : // asm.js modules can export single functions, or multiple functions in an
977 : // object literal.
978 6620 : if (auto* fun_export = exports->expression()->AsVariableProxy()) {
979 : // Exporting single function.
980 : AsmType* export_type;
981 221 : RECURSE(export_type = ExportType(fun_export));
982 173 : return export_type;
983 : }
984 :
985 6178 : if (auto* obj_export = exports->expression()->AsObjectLiteral()) {
986 : // Exporting object literal.
987 10552 : for (auto* prop : *obj_export->properties()) {
988 18038 : if (!prop->key()->IsLiteral()) {
989 0 : FAIL(prop->key(),
990 : "Only normal object properties may be used in the export object "
991 : "literal.");
992 : }
993 13518 : if (!prop->key()->AsLiteral()->IsPropertyName()) {
994 24 : FAIL(prop->key(),
995 : "Exported functions must have valid identifier names.");
996 : }
997 :
998 4500 : auto* export_obj = prop->value()->AsVariableProxy();
999 4500 : if (export_obj == nullptr) {
1000 56 : FAIL(prop->value(), "Exported value must be an asm.js function name.");
1001 : }
1002 :
1003 4486 : RECURSE(ExportType(export_obj));
1004 : }
1005 :
1006 : return AsmType::Int();
1007 : }
1008 :
1009 112 : FAIL(exports, "Unrecognized expression in asm.js module export expression.");
1010 : }
1011 :
1012 : // 6.3 ValidateFunctionTable
1013 1107 : AsmType* AsmTyper::ValidateFunctionTable(Assignment* assign) {
1014 369 : if (assign->is_compound()) {
1015 42 : FAIL(assign,
1016 : "Compound assignment not supported when declaring global variables.");
1017 : }
1018 :
1019 : auto* target = assign->target();
1020 383 : if (!target->IsVariableProxy()) {
1021 0 : FAIL(target, "Module assignments may only assign to globals.");
1022 : }
1023 829 : auto* target_variable = target->AsVariableProxy()->var();
1024 :
1025 738 : auto* value = assign->value()->AsArrayLiteral();
1026 369 : 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 1030 : if (!base::bits::IsPowerOfTwo32(pointers->length())) {
1032 28 : FAIL(assign, "Invalid length for function pointer table.");
1033 : }
1034 :
1035 : AsmType* table_element_type = nullptr;
1036 3476 : for (auto* initializer : *pointers) {
1037 5637 : auto* var_proxy = initializer->AsVariableProxy();
1038 2801 : if (var_proxy == nullptr) {
1039 28 : FAIL(initializer,
1040 : "Function pointer table initializer must be a function name.");
1041 : }
1042 :
1043 8354 : auto* var_info = Lookup(var_proxy->var());
1044 2794 : if (var_info == nullptr) {
1045 28 : FAIL(var_proxy,
1046 : "Undefined identifier in function pointer table initializer.");
1047 : }
1048 :
1049 2787 : if (var_info->standard_member() != kNone) {
1050 56 : 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 2773 : if (initializer_type->AsFunctionType() == nullptr) {
1057 56 : 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 2759 : if (table_element_type == nullptr) {
1065 : table_element_type = initializer_type;
1066 2439 : } else if (!initializer_type->IsA(table_element_type)) {
1067 28 : FAIL(initializer, "Type mismatch in function pointer table initializer.");
1068 : }
1069 : }
1070 :
1071 1264 : auto* target_info = Lookup(target_variable);
1072 313 : 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 182 : zone_, pointers->length(), table_element_type));
1078 : target_info->set_mutability(VariableInfo::kImmutableGlobal);
1079 91 : if (!ValidAsmIdentifier(target_variable->name())) {
1080 56 : FAIL(target, "Invalid asm.js identifier in function table name.");
1081 : }
1082 77 : if (!AddGlobal(target_variable, target_info)) {
1083 : DCHECK(false);
1084 0 : FAIL(assign, "Redeclared global identifier in function table name.");
1085 : }
1086 77 : SetTypeOf(value, target_info->type());
1087 77 : return target_info->type();
1088 : }
1089 :
1090 395 : auto* target_info_table = target_info->type()->AsFunctionTableType();
1091 222 : if (target_info_table == nullptr) {
1092 84 : FAIL(assign, "Identifier redefined as function pointer table.");
1093 : }
1094 :
1095 201 : if (!target_info->missing_definition()) {
1096 0 : FAIL(assign, "Identifier redefined (function table name).");
1097 : }
1098 :
1099 402 : if (static_cast<int>(target_info_table->length()) != pointers->length()) {
1100 28 : FAIL(assign, "Function table size mismatch.");
1101 : }
1102 :
1103 : DCHECK(target_info_table->signature()->AsFunctionType());
1104 194 : if (!table_element_type->IsA(target_info_table->signature())) {
1105 28 : FAIL(assign, "Function table initializer does not match previous type.");
1106 : }
1107 :
1108 : target_info->MarkDefined();
1109 : DCHECK(target_info->type() != AsmType::None());
1110 187 : SetTypeOf(value, target_info->type());
1111 :
1112 187 : return target_info->type();
1113 : }
1114 :
1115 : // 6.4 ValidateFunction
1116 23380 : AsmType* AsmTyper::ValidateFunction(FunctionDeclaration* fun_decl) {
1117 : FunctionScope _(this);
1118 :
1119 : // Extract parameter types.
1120 46335 : auto* fun = fun_decl->fun();
1121 :
1122 22820 : auto* fun_decl_proxy = fun_decl->proxy();
1123 11690 : if (fun_decl_proxy == nullptr) {
1124 82 : FAIL(fun_decl, "Anonymous functions are not support in asm.js.");
1125 : }
1126 :
1127 : Statement* current;
1128 11690 : FlattenedStatements iter(zone_, fun->body());
1129 :
1130 : size_t annotated_parameters = 0;
1131 :
1132 : // 5.3 Function type annotations
1133 : // * parameters
1134 11690 : ZoneVector<AsmType*> parameter_types(zone_);
1135 17430 : for (; (current = iter.Next()) != nullptr; ++annotated_parameters) {
1136 52609 : auto* stmt = current->AsExpressionStatement();
1137 28121 : if (stmt == nullptr) {
1138 : // Done with parameters.
1139 : break;
1140 : }
1141 83462 : auto* expr = stmt->expression()->AsAssignment();
1142 48570 : if (expr == nullptr || expr->is_compound()) {
1143 : // Done with parameters.
1144 : break;
1145 : }
1146 47991 : auto* proxy = expr->target()->AsVariableProxy();
1147 24082 : if (proxy == nullptr) {
1148 : // Done with parameters.
1149 : break;
1150 : }
1151 41536 : auto* param = proxy->var();
1152 41536 : if (param->location() != VariableLocation::PARAMETER ||
1153 17627 : param->index() != static_cast<int>(annotated_parameters)) {
1154 : // Done with parameters.
1155 : break;
1156 : }
1157 :
1158 : AsmType* type;
1159 34924 : RECURSE(type = ParameterTypeAnnotations(param, expr->value()));
1160 : DCHECK(type->IsParameterType());
1161 34888 : auto* param_info = new (zone_) VariableInfo(type);
1162 : param_info->set_mutability(VariableInfo::kLocal);
1163 17444 : if (!ValidAsmIdentifier(proxy->name())) {
1164 56 : FAIL(proxy, "Invalid asm.js identifier in parameter name.");
1165 : }
1166 :
1167 17430 : if (!AddLocal(param, param_info)) {
1168 0 : FAIL(proxy, "Redeclared parameter.");
1169 : }
1170 17430 : parameter_types.push_back(type);
1171 17430 : SetTypeOf(proxy, type);
1172 17430 : SetTypeOf(expr, type);
1173 34860 : SetTypeOf(expr->value(), type);
1174 : }
1175 :
1176 23316 : if (static_cast<int>(annotated_parameters) != fun->parameter_count()) {
1177 164 : FAIL(fun_decl, "Incorrect parameter type annotations.");
1178 : }
1179 :
1180 : // 5.3 Function type annotations
1181 : // * locals
1182 30666 : for (; current; current = iter.Next()) {
1183 102762 : auto* initializer = ExtractInitializerExpression(current);
1184 41284 : if (initializer == nullptr) {
1185 : // Done with locals.
1186 : break;
1187 : }
1188 :
1189 61426 : auto* local = initializer->target()->AsVariableProxy();
1190 30739 : 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 61478 : RECURSE(type = VariableTypeAnnotations(initializer->value()));
1201 30694 : auto* local_info = new (zone_) VariableInfo(type);
1202 : local_info->set_mutability(VariableInfo::kLocal);
1203 30694 : if (!ValidAsmIdentifier(local->name())) {
1204 28 : FAIL(local, "Invalid asm.js identifier in local variable.");
1205 : }
1206 :
1207 30687 : if (!AddLocal(local->var(), local_info)) {
1208 84 : FAIL(initializer, "Redeclared local.");
1209 : }
1210 :
1211 30666 : SetTypeOf(local, type);
1212 30666 : 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 11498 : do {
1221 11599 : if (statements->length() == 0) {
1222 999 : return_type_ = AsmType::Void();
1223 : } else {
1224 10600 : auto* last_statement = statements->last();
1225 10600 : auto* as_block = last_statement->AsBlock();
1226 10600 : if (as_block != nullptr) {
1227 55 : statements = as_block->statements();
1228 : } else {
1229 19473 : if (auto* ret_statement = last_statement->AsReturnStatement()) {
1230 17856 : RECURSE(return_type_ =
1231 : ReturnTypeAnnotations(ret_statement->expression()));
1232 : } else {
1233 1617 : return_type_ = AsmType::Void();
1234 : }
1235 : }
1236 : }
1237 11498 : } while (return_type_ == AsmType::None());
1238 :
1239 : DCHECK(return_type_->IsReturnType());
1240 :
1241 53514 : for (Declaration* decl : *fun->scope()->declarations()) {
1242 30692 : auto* var_decl = decl->AsVariableDeclaration();
1243 30660 : if (var_decl == nullptr) {
1244 28 : FAIL(decl, "Functions may only define inner variables.");
1245 : }
1246 :
1247 61306 : auto* var_proxy = var_decl->proxy();
1248 30653 : if (var_proxy == nullptr) {
1249 0 : FAIL(decl, "Invalid local declaration declaration.");
1250 : }
1251 :
1252 61281 : auto* var_info = Lookup(var_proxy->var());
1253 61281 : if (var_info == nullptr || var_info->IsGlobal()) {
1254 100 : FAIL(decl, "Local variable missing initializer in asm.js module.");
1255 : }
1256 : }
1257 :
1258 74542 : for (; current; current = iter.Next()) {
1259 : AsmType* current_type;
1260 74823 : RECURSE(current_type = ValidateStatement(current));
1261 : }
1262 :
1263 11130 : auto* fun_type = AsmType::Function(zone_, return_type_);
1264 : auto* fun_type_as_function = fun_type->AsFunctionType();
1265 39486 : for (auto* param_type : parameter_types) {
1266 : fun_type_as_function->AddArgument(param_type);
1267 : }
1268 :
1269 8605 : auto* fun_var = fun_decl_proxy->var();
1270 11130 : auto* fun_info = new (zone_) VariableInfo(fun_type);
1271 : fun_info->set_mutability(VariableInfo::kImmutableGlobal);
1272 16166 : auto* old_fun_info = Lookup(fun_var);
1273 11130 : if (old_fun_info == nullptr) {
1274 8605 : if (!ValidAsmIdentifier(fun_var->name())) {
1275 0 : FAIL(fun_decl_proxy, "Invalid asm.js identifier in function name.");
1276 : }
1277 8605 : if (!AddGlobal(fun_var, fun_info)) {
1278 : DCHECK(false);
1279 0 : FAIL(fun_decl, "Redeclared global identifier.");
1280 : }
1281 :
1282 8605 : SetTypeOf(fun, fun_type);
1283 8605 : 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 2525 : if (old_fun_type->AsFunctionType() == nullptr) {
1291 56 : FAIL(fun_decl, "Identifier redefined as function.");
1292 : }
1293 :
1294 2511 : if (!old_fun_info->missing_definition()) {
1295 108 : FAIL(fun_decl, "Identifier redefined (function name).");
1296 : }
1297 :
1298 2484 : if (!fun_type->IsA(old_fun_type)) {
1299 0 : FAIL(fun_decl, "Signature mismatch when defining function.");
1300 : }
1301 :
1302 : old_fun_info->MarkDefined();
1303 2484 : SetTypeOf(fun, fun_type);
1304 :
1305 2484 : return fun_type;
1306 : }
1307 :
1308 : // 6.5 ValidateStatement
1309 406935 : AsmType* AsmTyper::ValidateStatement(Statement* statement) {
1310 813870 : switch (statement->node_type()) {
1311 : default:
1312 0 : FAIL(statement, "Statement type invalid for asm.js.");
1313 : case AstNode::kBlock:
1314 126548 : return ValidateBlockStatement(statement->AsBlock());
1315 : case AstNode::kExpressionStatement:
1316 424436 : return ValidateExpressionStatement(statement->AsExpressionStatement());
1317 : case AstNode::kEmptyStatement:
1318 : return ValidateEmptyStatement(statement->AsEmptyStatement());
1319 : case AstNode::kIfStatement:
1320 81430 : return ValidateIfStatement(statement->AsIfStatement());
1321 : case AstNode::kReturnStatement:
1322 78480 : return ValidateReturnStatement(statement->AsReturnStatement());
1323 : case AstNode::kWhileStatement:
1324 7382 : return ValidateWhileStatement(statement->AsWhileStatement());
1325 : case AstNode::kDoWhileStatement:
1326 10586 : return ValidateDoWhileStatement(statement->AsDoWhileStatement());
1327 : case AstNode::kForStatement:
1328 374 : 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 1104 : return ValidateSwitchStatement(statement->AsSwitchStatement());
1335 : }
1336 :
1337 : return AsmType::Void();
1338 : }
1339 :
1340 : // 6.5.1 BlockStatement
1341 63274 : AsmType* AsmTyper::ValidateBlockStatement(Block* block) {
1342 63274 : FlattenedStatements iter(zone_, block->statements());
1343 :
1344 266882 : while (auto* current = iter.Next()) {
1345 203626 : RECURSE(ValidateStatement(current));
1346 : }
1347 :
1348 : return AsmType::Void();
1349 : }
1350 :
1351 : // 6.5.2 ExpressionStatement
1352 212218 : AsmType* AsmTyper::ValidateExpressionStatement(ExpressionStatement* expr) {
1353 : auto* expression = expr->expression();
1354 424436 : if (auto* call = expression->AsCall()) {
1355 16331 : RECURSE(ValidateCall(AsmType::Void(), call));
1356 : } else {
1357 195887 : RECURSE(ValidateExpression(expression));
1358 : }
1359 :
1360 : return AsmType::Void();
1361 : }
1362 :
1363 : // 6.5.3 EmptyStatement
1364 0 : AsmType* AsmTyper::ValidateEmptyStatement(EmptyStatement* empty) {
1365 0 : return AsmType::Void();
1366 : }
1367 :
1368 : // 6.5.4 IfStatement
1369 162775 : AsmType* AsmTyper::ValidateIfStatement(IfStatement* if_stmt) {
1370 : AsmType* cond_type;
1371 81430 : RECURSE(cond_type = ValidateExpression(if_stmt->condition()));
1372 40679 : if (!cond_type->IsA(AsmType::Int())) {
1373 28 : FAIL(if_stmt->condition(), "If condition must be type int.");
1374 : }
1375 81344 : RECURSE(ValidateStatement(if_stmt->then_statement()));
1376 81332 : RECURSE(ValidateStatement(if_stmt->else_statement()));
1377 40666 : return AsmType::Void();
1378 : }
1379 :
1380 : // 6.5.5 ReturnStatement
1381 39240 : AsmType* AsmTyper::ValidateReturnStatement(ReturnStatement* ret_stmt) {
1382 : AsmType* ret_expr_type = AsmType::Void();
1383 39240 : if (auto* ret_expr = ret_stmt->expression()) {
1384 39240 : RECURSE(ret_expr_type = ValidateExpression(ret_expr));
1385 39198 : 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 4393 : if (!ret_expr->IsUndefinedLiteral()) {
1389 34 : FAIL(ret_stmt, "Return statement expression can't be void.");
1390 : }
1391 : }
1392 : }
1393 :
1394 39198 : if (!ret_expr_type->IsA(return_type_)) {
1395 136 : 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
1403 7389 : AsmType* AsmTyper::ValidateWhileStatement(WhileStatement* while_stmt) {
1404 : AsmType* cond_type;
1405 7382 : RECURSE(cond_type = ValidateExpression(while_stmt->cond()));
1406 3673 : if (!cond_type->IsA(AsmType::Int())) {
1407 28 : FAIL(while_stmt->cond(), "While condition must be type int.");
1408 : }
1409 :
1410 3666 : if (auto* body = while_stmt->body()) {
1411 3666 : RECURSE(ValidateStatement(body));
1412 : }
1413 : return AsmType::Void();
1414 : }
1415 :
1416 : // 6.5.6.b DoWhileStatement
1417 10593 : AsmType* AsmTyper::ValidateDoWhileStatement(DoWhileStatement* do_while) {
1418 : AsmType* cond_type;
1419 10586 : RECURSE(cond_type = ValidateExpression(do_while->cond()));
1420 5287 : if (!cond_type->IsA(AsmType::Int())) {
1421 28 : FAIL(do_while->cond(), "Do {} While condition must be type int.");
1422 : }
1423 :
1424 5280 : if (auto* body = do_while->body()) {
1425 5280 : RECURSE(ValidateStatement(body));
1426 : }
1427 : return AsmType::Void();
1428 : }
1429 :
1430 : // 6.5.6.c ForStatement
1431 530 : AsmType* AsmTyper::ValidateForStatement(ForStatement* for_stmt) {
1432 187 : if (auto* init = for_stmt->init()) {
1433 168 : RECURSE(ValidateStatement(init));
1434 : }
1435 :
1436 181 : if (auto* cond = for_stmt->cond()) {
1437 : AsmType* cond_type;
1438 169 : RECURSE(cond_type = ValidateExpression(cond));
1439 157 : if (!cond_type->IsA(AsmType::Int())) {
1440 28 : FAIL(cond, "For condition must be type int.");
1441 : }
1442 : }
1443 :
1444 162 : if (auto* next = for_stmt->next()) {
1445 150 : RECURSE(ValidateStatement(next));
1446 : }
1447 :
1448 162 : if (auto* body = for_stmt->body()) {
1449 162 : RECURSE(ValidateStatement(body));
1450 : }
1451 :
1452 : return AsmType::Void();
1453 : }
1454 :
1455 : // 6.5.7 BreakStatement
1456 0 : AsmType* AsmTyper::ValidateBreakStatement(BreakStatement* brk_stmt) {
1457 0 : return AsmType::Void();
1458 : }
1459 :
1460 : // 6.5.8 ContinueStatement
1461 0 : AsmType* AsmTyper::ValidateContinueStatement(ContinueStatement* cont_stmt) {
1462 0 : 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
1469 1649 : AsmType* AsmTyper::ValidateSwitchStatement(SwitchStatement* stmt) {
1470 : AsmType* cond_type;
1471 1104 : RECURSE(cond_type = ValidateExpression(stmt->tag()));
1472 552 : if (!cond_type->IsA(AsmType::Signed())) {
1473 42 : FAIL(stmt, "Switch tag must be signed.");
1474 : }
1475 :
1476 : int default_pos = kNoSourcePosition;
1477 545 : int last_case_pos = kNoSourcePosition;
1478 545 : ZoneSet<int32_t> cases_seen(zone_);
1479 29585 : for (auto* a_case : *stmt->cases()) {
1480 28536 : if (a_case->is_default()) {
1481 473 : CHECK(default_pos == kNoSourcePosition);
1482 473 : RECURSE(ValidateDefault(a_case));
1483 28550 : default_pos = a_case->position();
1484 473 : continue;
1485 : }
1486 :
1487 28063 : if (last_case_pos == kNoSourcePosition) {
1488 533 : last_case_pos = a_case->position();
1489 : } else {
1490 55060 : last_case_pos = std::max(last_case_pos, a_case->position());
1491 : }
1492 :
1493 : int32_t case_lbl;
1494 28063 : RECURSE(ValidateCase(a_case, &case_lbl));
1495 : auto case_lbl_pos = cases_seen.find(case_lbl);
1496 28036 : if (case_lbl_pos != cases_seen.end() && *case_lbl_pos == case_lbl) {
1497 56 : FAIL(a_case, "Duplicated case label.");
1498 : }
1499 : cases_seen.insert(case_lbl);
1500 : }
1501 :
1502 504 : if (!cases_seen.empty()) {
1503 492 : const int64_t max_lbl = *cases_seen.rbegin();
1504 492 : const int64_t min_lbl = *cases_seen.begin();
1505 492 : if (max_lbl - min_lbl > std::numeric_limits<int32_t>::max()) {
1506 28 : FAIL(stmt, "Out-of-bounds case label range.");
1507 : }
1508 : }
1509 :
1510 497 : if (last_case_pos != kNoSourcePosition && default_pos != kNoSourcePosition &&
1511 : default_pos < last_case_pos) {
1512 28 : FAIL(stmt, "Switch default must appear last.");
1513 : }
1514 :
1515 : return AsmType::Void();
1516 : }
1517 :
1518 : // 6.6 ValidateCase
1519 : namespace {
1520 28063 : bool ExtractInt32CaseLabel(CaseClause* clause, int32_t* lbl) {
1521 56106 : auto* lbl_expr = clause->label()->AsLiteral();
1522 :
1523 28063 : if (lbl_expr == nullptr) {
1524 : return false;
1525 : }
1526 :
1527 28063 : if (!IsLiteralInt(lbl_expr)) {
1528 : return false;
1529 : }
1530 :
1531 28043 : return lbl_expr->value()->ToInt32(lbl);
1532 : }
1533 : } // namespace
1534 :
1535 56099 : AsmType* AsmTyper::ValidateCase(CaseClause* label, int32_t* case_lbl) {
1536 28063 : if (!ExtractInt32CaseLabel(label, case_lbl)) {
1537 108 : FAIL(label, "Case label must be a 32-bit signed integer.");
1538 : }
1539 :
1540 28036 : FlattenedStatements iter(zone_, label->statements());
1541 64589 : while (auto* current = iter.Next()) {
1542 36553 : RECURSE(ValidateStatement(current));
1543 : }
1544 : return AsmType::Void();
1545 : }
1546 :
1547 : // 6.7 ValidateDefault
1548 473 : AsmType* AsmTyper::ValidateDefault(CaseClause* label) {
1549 473 : FlattenedStatements iter(zone_, label->statements());
1550 1425 : while (auto* current = iter.Next()) {
1551 952 : RECURSE(ValidateStatement(current));
1552 : }
1553 : return AsmType::Void();
1554 : }
1555 :
1556 : // 6.8 ValidateExpression
1557 1361586 : AsmType* AsmTyper::ValidateExpression(Expression* expr) {
1558 : AsmType* expr_ty = AsmType::None();
1559 :
1560 2723172 : switch (expr->node_type()) {
1561 : default:
1562 0 : FAIL(expr, "Invalid asm.js expression.");
1563 : case AstNode::kLiteral:
1564 541842 : RECURSE(expr_ty = ValidateNumericLiteral(expr->AsLiteral()));
1565 : break;
1566 : case AstNode::kVariableProxy:
1567 746262 : RECURSE(expr_ty = ValidateIdentifier(expr->AsVariableProxy()));
1568 : break;
1569 : case AstNode::kCall:
1570 1672 : RECURSE(expr_ty = ValidateCallExpression(expr->AsCall()));
1571 : break;
1572 : case AstNode::kProperty:
1573 150132 : RECURSE(expr_ty = ValidateMemberExpression(expr->AsProperty()));
1574 : break;
1575 : case AstNode::kAssignment:
1576 392672 : RECURSE(expr_ty = ValidateAssignmentExpression(expr->AsAssignment()));
1577 : break;
1578 : case AstNode::kUnaryOperation:
1579 26944 : RECURSE(expr_ty = ValidateUnaryExpression(expr->AsUnaryOperation()));
1580 : break;
1581 : case AstNode::kConditional:
1582 13180 : RECURSE(expr_ty = ValidateConditionalExpression(expr->AsConditional()));
1583 : break;
1584 : case AstNode::kCompareOperation:
1585 102072 : RECURSE(expr_ty = ValidateCompareOperation(expr->AsCompareOperation()));
1586 : break;
1587 : case AstNode::kBinaryOperation:
1588 748396 : RECURSE(expr_ty = ValidateBinaryOperation(expr->AsBinaryOperation()));
1589 : break;
1590 : }
1591 :
1592 1360500 : SetTypeOf(expr, expr_ty);
1593 1360500 : return expr_ty;
1594 : }
1595 :
1596 51036 : AsmType* AsmTyper::ValidateCompareOperation(CompareOperation* cmp) {
1597 51036 : switch (cmp->op()) {
1598 : default:
1599 0 : FAIL(cmp, "Invalid asm.js comparison operator.");
1600 : case Token::LT:
1601 : case Token::LTE:
1602 : case Token::GT:
1603 : case Token::GTE:
1604 18884 : return ValidateRelationalExpression(cmp);
1605 : case Token::EQ:
1606 : case Token::NE:
1607 32152 : return ValidateEqualityExpression(cmp);
1608 : }
1609 :
1610 : UNREACHABLE();
1611 : }
1612 :
1613 : namespace {
1614 3942 : bool IsInvert(BinaryOperation* binop) {
1615 2184 : if (binop->op() != Token::BIT_XOR) {
1616 : return false;
1617 : }
1618 :
1619 1758 : auto* right_as_literal = binop->right()->AsLiteral();
1620 1758 : if (right_as_literal == nullptr) {
1621 : return false;
1622 : }
1623 :
1624 1281 : return IsLiteralMinus1(right_as_literal);
1625 : }
1626 :
1627 24502 : bool IsUnaryMinus(BinaryOperation* binop) {
1628 : // *VIOLATION* The parser replaces uses of -x with x*-1.
1629 12251 : if (binop->op() != Token::MUL) {
1630 : return false;
1631 : }
1632 :
1633 12251 : auto* right_as_literal = binop->right()->AsLiteral();
1634 12251 : if (right_as_literal == nullptr) {
1635 : return false;
1636 : }
1637 :
1638 4979 : return IsLiteralMinus1(right_as_literal);
1639 : }
1640 : } // namespace
1641 :
1642 412598 : 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 374198 : switch (expr->op()) {
1651 : default:
1652 6 : FAIL(expr, "Invalid asm.js binary expression.");
1653 : case Token::COMMA:
1654 3822 : return ValidateCommaExpression(expr);
1655 : case Token::MUL:
1656 25308 : 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 26114 : if (auto* Call = expr->left()->AsCall()) {
1660 1583 : return ValidateCall(AsmType::Double(), Call);
1661 : }
1662 : AsmType* left_type;
1663 22948 : RECURSE(left_type = ValidateExpression(expr->left()));
1664 11462 : SetTypeOf(expr->right(), AsmType::Double());
1665 11462 : UNOP_OVERLOAD(Signed, Double);
1666 11060 : UNOP_OVERLOAD(Unsigned, Double);
1667 10882 : UNOP_OVERLOAD(DoubleQ, Double);
1668 7112 : UNOP_OVERLOAD(FloatQ, Double);
1669 24 : FAIL(expr, "Invalid type for conversion to double.");
1670 : }
1671 :
1672 12251 : if (IsUnaryMinus(expr)) {
1673 : // *VIOLATION* the parser converts -x to x * -1.
1674 : AsmType* left_type;
1675 1432 : RECURSE(left_type = ValidateExpression(expr->left()));
1676 716 : SetTypeOf(expr->right(), left_type);
1677 716 : UNOP_OVERLOAD(Int, Intish);
1678 686 : UNOP_OVERLOAD(DoubleQ, Double);
1679 22 : UNOP_OVERLOAD(FloatQ, Floatish);
1680 0 : FAIL(expr, "Invalid type for unary -.");
1681 : }
1682 : // FALTHROUGH
1683 : case Token::DIV:
1684 : case Token::MOD:
1685 12652 : return ValidateMultiplicativeExpression(expr);
1686 : case Token::ADD:
1687 : case Token::SUB: {
1688 : static const uint32_t kInitialIntishCount = 0;
1689 111982 : return ValidateAdditiveExpression(expr, kInitialIntishCount);
1690 : }
1691 : case Token::SAR:
1692 : case Token::SHL:
1693 : case Token::SHR:
1694 38133 : return ValidateShiftExpression(expr);
1695 : case Token::BIT_AND:
1696 13036 : return ValidateBitwiseANDExpression(expr);
1697 : case Token::BIT_XOR:
1698 1648 : if (IsInvert(expr)) {
1699 : auto* left = expr->left();
1700 1085 : auto* left_as_binop = left->AsBinaryOperation();
1701 :
1702 865 : if (left_as_binop != nullptr && IsInvert(left_as_binop)) {
1703 : // This is the special ~~ operator.
1704 : AsmType* left_type;
1705 220 : RECURSE(left_type = ValidateExpression(left_as_binop->left()));
1706 110 : SetTypeOf(left_as_binop->right(), AsmType::FixNum());
1707 110 : SetTypeOf(left_as_binop, AsmType::Signed());
1708 110 : SetTypeOf(expr->right(), AsmType::FixNum());
1709 110 : UNOP_OVERLOAD(Double, Signed);
1710 19 : UNOP_OVERLOAD(FloatQ, Signed);
1711 0 : FAIL(left_as_binop, "Invalid type for conversion to signed.");
1712 : }
1713 :
1714 : AsmType* left_type;
1715 755 : RECURSE(left_type = ValidateExpression(left));
1716 755 : UNOP_OVERLOAD(Intish, Signed);
1717 0 : FAIL(left, "Invalid type for ~.");
1718 : }
1719 :
1720 783 : return ValidateBitwiseXORExpression(expr);
1721 : case Token::BIT_OR:
1722 179152 : return ValidateBitwiseORExpression(expr);
1723 : }
1724 : #undef UNOP_OVERLOAD
1725 : UNREACHABLE();
1726 : }
1727 :
1728 : // 6.8.1 Expression
1729 7644 : AsmType* AsmTyper::ValidateCommaExpression(BinaryOperation* comma) {
1730 : // The AST looks like:
1731 : // (expr COMMA (expr COMMA (expr COMMA (... ))))
1732 :
1733 : auto* left = comma->left();
1734 7644 : if (auto* left_as_call = left->AsCall()) {
1735 48 : RECURSE(ValidateCall(AsmType::Void(), left_as_call));
1736 : } else {
1737 3774 : RECURSE(ValidateExpression(left));
1738 : }
1739 :
1740 : auto* right = comma->right();
1741 : AsmType* right_type = nullptr;
1742 7644 : if (auto* right_as_call = right->AsCall()) {
1743 30 : RECURSE(right_type = ValidateFloatCoercion(right_as_call));
1744 30 : if (right_type != AsmType::Float()) {
1745 : // right_type == nullptr <-> right_as_call is not a call to fround.
1746 : DCHECK(right_type == nullptr);
1747 30 : 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 3792 : RECURSE(right_type = ValidateExpression(right));
1754 : }
1755 :
1756 3822 : return right_type;
1757 : }
1758 :
1759 : // 6.8.2 NumericLiteral
1760 553595 : 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 270921 : if (literal->IsUndefinedLiteral()) {
1764 : return AsmType::Void();
1765 : }
1766 :
1767 265976 : 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 783771 : if (literal->raw_value()->IsTrue() || literal->raw_value()->IsFalse()) {
1774 : return AsmType::Int();
1775 : }
1776 :
1777 : uint32_t value;
1778 261247 : if (!literal->value()->ToUint32(&value)) {
1779 : int32_t value;
1780 21415 : if (!literal->value()->ToInt32(&value)) {
1781 24 : 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 239832 : if (value <= LargestFixNum) {
1790 : return AsmType::FixNum();
1791 : }
1792 :
1793 178 : return AsmType::Unsigned();
1794 : }
1795 :
1796 : // 6.8.3 Identifier
1797 373131 : AsmType* AsmTyper::ValidateIdentifier(VariableProxy* proxy) {
1798 746232 : auto* proxy_info = Lookup(proxy->var());
1799 373131 : if (proxy_info == nullptr) {
1800 169 : FAIL(proxy, "Undeclared identifier.");
1801 : }
1802 : auto* type = proxy_info->type();
1803 373101 : if (type->IsA(AsmType::None()) || type->AsCallableType() != nullptr) {
1804 196 : FAIL(proxy, "Identifier may not be accessed by ordinary expressions.");
1805 : }
1806 : return type;
1807 : }
1808 :
1809 : // 6.8.4 CallExpression
1810 836 : AsmType* AsmTyper::ValidateCallExpression(Call* call) {
1811 : AsmType* return_type;
1812 836 : RECURSE(return_type = ValidateFloatCoercion(call));
1813 808 : if (return_type == nullptr) {
1814 148 : 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
1820 75066 : AsmType* AsmTyper::ValidateMemberExpression(Property* prop) {
1821 : AsmType* return_type;
1822 75066 : RECURSE(return_type = ValidateHeapAccess(prop, LoadFromHeap));
1823 75034 : return return_type;
1824 : }
1825 :
1826 : // 6.8.6 AssignmentExpression
1827 836984 : AsmType* AsmTyper::ValidateAssignmentExpression(Assignment* assignment) {
1828 : AsmType* value_type;
1829 392672 : RECURSE(value_type = ValidateExpression(assignment->value()));
1830 :
1831 196288 : if (assignment->op() == Token::INIT) {
1832 61 : FAIL(assignment,
1833 : "Local variable declaration must be at the top of the function.");
1834 : }
1835 :
1836 392576 : if (auto* target_as_proxy = assignment->target()->AsVariableProxy()) {
1837 565 : auto* var = target_as_proxy->var();
1838 432484 : auto* target_info = Lookup(var);
1839 :
1840 144552 : if (target_info == nullptr) {
1841 565 : if (var->mode() != TEMPORARY) {
1842 52 : 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 552 : auto* var_info = new (zone_) VariableInfo(value_type);
1849 : var_info->set_mutability(VariableInfo::kLocal);
1850 552 : if (!ValidAsmIdentifier(target_as_proxy->name())) {
1851 0 : FAIL(target_as_proxy,
1852 : "Invalid asm.js identifier in temporary variable.");
1853 : }
1854 :
1855 552 : if (!AddLocal(var, var_info)) {
1856 0 : FAIL(assignment, "Failed to add temporary variable to symbol table.");
1857 : }
1858 : return value_type;
1859 : }
1860 :
1861 143987 : if (!target_info->IsMutable()) {
1862 168 : FAIL(assignment, "Can't assign to immutable symbol.");
1863 : }
1864 :
1865 : DCHECK_NE(AsmType::None(), target_info->type());
1866 143945 : if (!value_type->IsA(target_info->type())) {
1867 76 : FAIL(assignment, "Type mismatch in assignment.");
1868 : }
1869 :
1870 : return value_type;
1871 : }
1872 :
1873 103472 : if (auto* target_as_property = assignment->target()->AsProperty()) {
1874 : AsmType* allowed_store_types;
1875 51736 : RECURSE(allowed_store_types =
1876 : ValidateHeapAccess(target_as_property, StoreToHeap));
1877 :
1878 51680 : if (!value_type->IsA(allowed_store_types)) {
1879 0 : FAIL(assignment, "Type mismatch in heap assignment.");
1880 : }
1881 :
1882 : return value_type;
1883 : }
1884 :
1885 0 : FAIL(assignment, "Invalid asm.js assignment.");
1886 : }
1887 :
1888 : // 6.8.7 UnaryExpression
1889 40396 : 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 26944 : 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 13452 : switch (unop->op()) {
1907 : default:
1908 7 : 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 0 : UNOP_OVERLOAD(Signed, Double);
1913 0 : UNOP_OVERLOAD(Unsigned, Double);
1914 0 : UNOP_OVERLOAD(DoubleQ, Double);
1915 0 : UNOP_OVERLOAD(FloatQ, Double);
1916 0 : 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 0 : UNOP_OVERLOAD(Int, Intish);
1921 0 : UNOP_OVERLOAD(DoubleQ, Double);
1922 0 : UNOP_OVERLOAD(FloatQ, Floatish);
1923 0 : 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 0 : UNOP_OVERLOAD(Intish, Signed);
1928 0 : FAIL(unop, "Invalid type for ~.");
1929 : case Token::NOT:
1930 13452 : UNOP_OVERLOAD(Int, Int);
1931 28 : FAIL(unop, "Invalid type for !.");
1932 : }
1933 :
1934 : #undef UNOP_OVERLOAD
1935 :
1936 : UNREACHABLE();
1937 : }
1938 :
1939 : // 6.8.8 MultiplicativeExpression
1940 : namespace {
1941 23044 : bool IsIntishLiteralFactor(Expression* expr, int32_t* factor) {
1942 26868 : auto* literal = expr->AsLiteral();
1943 23044 : if (literal == nullptr) {
1944 : return false;
1945 : }
1946 :
1947 4310 : if (!IsLiteralInt(literal)) {
1948 : return false;
1949 : }
1950 :
1951 3824 : if (!literal->value()->ToInt32(factor)) {
1952 : return false;
1953 : }
1954 : static const int32_t kIntishBound = 1 << 20;
1955 3824 : return -kIntishBound < *factor && *factor < kIntishBound;
1956 : }
1957 : } // namespace
1958 :
1959 21494 : 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 12652 : if (binop->op() == Token::MUL) {
1967 : int32_t factor;
1968 11535 : if (IsIntishLiteralFactor(left, &factor)) {
1969 : AsmType* right_type;
1970 33 : RECURSE(right_type = ValidateExpression(right));
1971 33 : 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 11509 : if (IsIntishLiteralFactor(right, &factor)) {
1982 : AsmType* left_type;
1983 3777 : RECURSE(left_type = ValidateExpression(left));
1984 3777 : 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 13 : if (factor == -1) {
1993 : // *VIOLATION* The frontend transforms -x into x * -1 (not -1.0, because
1994 : // consistency is overrated.)
1995 0 : if (left_type->IsA(AsmType::DoubleQ())) {
1996 : return AsmType::Double();
1997 0 : } else if (left_type->IsA(AsmType::FloatQ())) {
1998 : return AsmType::Floatish();
1999 : }
2000 : }
2001 : }
2002 : }
2003 :
2004 8862 : if (intish_mul_failed) {
2005 143 : FAIL(binop, "Invalid types for intish * (or unary -).");
2006 : }
2007 :
2008 : AsmType* left_type;
2009 : AsmType* right_type;
2010 8842 : RECURSE(left_type = ValidateExpression(left));
2011 8842 : 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 8842 : switch (binop->op()) {
2020 : default:
2021 0 : FAIL(binop, "Invalid multiplicative expression.");
2022 : case Token::MUL:
2023 7725 : BINOP_OVERLOAD(DoubleQ, DoubleQ, Double);
2024 36 : BINOP_OVERLOAD(FloatQ, FloatQ, Floatish);
2025 84 : FAIL(binop, "Invalid operands for *.");
2026 : case Token::DIV:
2027 681 : BINOP_OVERLOAD(Signed, Signed, Intish);
2028 504 : BINOP_OVERLOAD(Unsigned, Unsigned, Intish);
2029 435 : BINOP_OVERLOAD(DoubleQ, DoubleQ, Double);
2030 36 : BINOP_OVERLOAD(FloatQ, FloatQ, Floatish);
2031 84 : FAIL(binop, "Invalid operands for /.");
2032 : case Token::MOD:
2033 436 : BINOP_OVERLOAD(Signed, Signed, Intish);
2034 175 : BINOP_OVERLOAD(Unsigned, Unsigned, Intish);
2035 52 : BINOP_OVERLOAD(DoubleQ, DoubleQ, Double);
2036 84 : FAIL(binop, "Invalid operands for %.");
2037 : }
2038 : #undef BINOP_OVERLOAD
2039 :
2040 : UNREACHABLE();
2041 : }
2042 :
2043 : // 6.8.9 AdditiveExpression
2044 250855 : 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 149334 : 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 149334 : if (left_as_binop != nullptr && (left_as_binop->op() == Token::ADD ||
2055 : left_as_binop->op() == Token::SUB)) {
2056 8376 : RECURSE(left_type =
2057 : ValidateAdditiveExpression(left_as_binop, intish_count + 1));
2058 8376 : SetTypeOf(left_as_binop, left_type);
2059 : } else {
2060 117046 : RECURSE(left_type = ValidateExpression(left));
2061 : }
2062 :
2063 : auto* right = binop->right();
2064 149488 : auto* right_as_binop = right->AsBinaryOperation();
2065 : AsmType* right_type;
2066 :
2067 149488 : if (right_as_binop != nullptr && (right_as_binop->op() == Token::ADD ||
2068 : right_as_binop->op() == Token::SUB)) {
2069 5064 : RECURSE(right_type =
2070 : ValidateAdditiveExpression(right_as_binop, intish_count + 1));
2071 5064 : SetTypeOf(right_as_binop, right_type);
2072 : } else {
2073 120334 : RECURSE(right_type = ValidateExpression(right));
2074 : }
2075 :
2076 125392 : if (left_type->IsA(AsmType::FloatQ()) && right_type->IsA(AsmType::FloatQ())) {
2077 : return AsmType::Floatish();
2078 : }
2079 :
2080 125338 : if (left_type->IsA(AsmType::Int()) && right_type->IsA(AsmType::Int())) {
2081 117848 : if (intish_count == 0) {
2082 : return AsmType::Intish();
2083 : }
2084 11358 : if (intish_count < kMaxIntish) {
2085 : return AsmType::Int();
2086 : }
2087 28 : FAIL(binop, "Too many uncoerced integer additive expressions.");
2088 : }
2089 :
2090 7490 : if (left_type->IsA(AsmType::Double()) && right_type->IsA(AsmType::Double())) {
2091 : return AsmType::Double();
2092 : }
2093 :
2094 35 : if (binop->op() == Token::SUB) {
2095 28 : if (left_type->IsA(AsmType::DoubleQ()) &&
2096 7 : right_type->IsA(AsmType::DoubleQ())) {
2097 : return AsmType::Double();
2098 : }
2099 : }
2100 :
2101 112 : FAIL(binop, "Invalid operands for additive expression.");
2102 : }
2103 :
2104 : // 6.8.10 ShiftExpression
2105 76260 : 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 38133 : RECURSE(left_type = ValidateExpression(left));
2112 38127 : 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 38127 : switch (binop->op()) {
2121 : default:
2122 42 : FAIL(binop, "Invalid shift expression.");
2123 : case Token::SHL:
2124 15751 : BINOP_OVERLOAD(Intish, Intish, Signed);
2125 56 : FAIL(binop, "Invalid operands for <<.");
2126 : case Token::SAR:
2127 2233 : BINOP_OVERLOAD(Intish, Intish, Signed);
2128 56 : FAIL(binop, "Invalid operands for >>.");
2129 : case Token::SHR:
2130 20143 : BINOP_OVERLOAD(Intish, Intish, Unsigned);
2131 56 : FAIL(binop, "Invalid operands for >>>.");
2132 : }
2133 : #undef BINOP_OVERLOAD
2134 :
2135 : UNREACHABLE();
2136 : }
2137 :
2138 : // 6.8.11 RelationalExpression
2139 37756 : 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 18884 : RECURSE(left_type = ValidateExpression(left));
2146 18872 : 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 18872 : switch (cmpop->op()) {
2155 : default:
2156 92 : FAIL(cmpop, "Invalid relational expression.");
2157 : case Token::LT:
2158 9464 : CMPOP_OVERLOAD(Signed, Signed, Int);
2159 6661 : CMPOP_OVERLOAD(Unsigned, Unsigned, Int);
2160 870 : CMPOP_OVERLOAD(Float, Float, Int);
2161 841 : CMPOP_OVERLOAD(Double, Double, Int);
2162 128 : FAIL(cmpop, "Invalid operands for <.");
2163 : case Token::GT:
2164 6316 : CMPOP_OVERLOAD(Signed, Signed, Int);
2165 3227 : CMPOP_OVERLOAD(Unsigned, Unsigned, Int);
2166 882 : CMPOP_OVERLOAD(Float, Float, Int);
2167 853 : CMPOP_OVERLOAD(Double, Double, Int);
2168 104 : FAIL(cmpop, "Invalid operands for >.");
2169 : case Token::LTE:
2170 1786 : CMPOP_OVERLOAD(Signed, Signed, Int);
2171 407 : CMPOP_OVERLOAD(Unsigned, Unsigned, Int);
2172 288 : CMPOP_OVERLOAD(Float, Float, Int);
2173 259 : CMPOP_OVERLOAD(Double, Double, Int);
2174 80 : FAIL(cmpop, "Invalid operands for <=.");
2175 : case Token::GTE:
2176 1306 : CMPOP_OVERLOAD(Signed, Signed, Int);
2177 395 : CMPOP_OVERLOAD(Unsigned, Unsigned, Int);
2178 324 : CMPOP_OVERLOAD(Float, Float, Int);
2179 295 : CMPOP_OVERLOAD(Double, Double, Int);
2180 56 : FAIL(cmpop, "Invalid operands for >=.");
2181 : }
2182 : #undef CMPOP_OVERLOAD
2183 :
2184 : UNREACHABLE();
2185 : }
2186 :
2187 : // 6.8.12 EqualityExpression
2188 64304 : 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 32152 : RECURSE(left_type = ValidateExpression(left));
2195 32152 : 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 32152 : switch (cmpop->op()) {
2204 : default:
2205 52 : FAIL(cmpop, "Invalid equality expression.");
2206 : case Token::EQ:
2207 32152 : CMPOP_OVERLOAD(Signed, Signed, Int);
2208 726 : CMPOP_OVERLOAD(Unsigned, Unsigned, Int);
2209 670 : CMPOP_OVERLOAD(Float, Float, Int);
2210 576 : CMPOP_OVERLOAD(Double, Double, Int);
2211 208 : FAIL(cmpop, "Invalid operands for ==.");
2212 : case Token::NE:
2213 0 : CMPOP_OVERLOAD(Signed, Signed, Int);
2214 0 : CMPOP_OVERLOAD(Unsigned, Unsigned, Int);
2215 0 : CMPOP_OVERLOAD(Float, Float, Int);
2216 0 : CMPOP_OVERLOAD(Double, Double, Int);
2217 0 : FAIL(cmpop, "Invalid operands for !=.");
2218 : }
2219 : #undef CMPOP_OVERLOAD
2220 :
2221 : UNREACHABLE();
2222 : }
2223 :
2224 : // 6.8.13 BitwiseANDExpression
2225 26072 : 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 13036 : RECURSE(left_type = ValidateExpression(left));
2232 13036 : RECURSE(right_type = ValidateExpression(right));
2233 :
2234 13036 : if (binop->op() != Token::BIT_AND) {
2235 27 : 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 13036 : BINOP_OVERLOAD(Intish, Intish, Signed);
2245 108 : FAIL(binop, "Invalid operands for &.");
2246 : #undef BINOP_OVERLOAD
2247 :
2248 : UNREACHABLE();
2249 : }
2250 :
2251 : // 6.8.14 BitwiseXORExpression
2252 1566 : 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 783 : RECURSE(left_type = ValidateExpression(left));
2259 783 : RECURSE(right_type = ValidateExpression(right));
2260 :
2261 783 : if (binop->op() != Token::BIT_XOR) {
2262 21 : 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 783 : BINOP_OVERLOAD(Intish, Intish, Signed);
2272 84 : FAIL(binop, "Invalid operands for ^.");
2273 : #undef BINOP_OVERLOAD
2274 :
2275 : UNREACHABLE();
2276 : }
2277 :
2278 : // 6.8.15 BitwiseORExpression
2279 192902 : AsmType* AsmTyper::ValidateBitwiseORExpression(BinaryOperation* binop) {
2280 : auto* left = binop->left();
2281 179152 : if (IsIntAnnotation(binop)) {
2282 344480 : if (auto* left_as_call = left->AsCall()) {
2283 : AsmType* type;
2284 14498 : RECURSE(type = ValidateCall(AsmType::Signed(), left_as_call));
2285 14402 : return type;
2286 : }
2287 : AsmType* left_type;
2288 157742 : RECURSE(left_type = ValidateExpression(left));
2289 157686 : if (!left_type->IsA(AsmType::Intish())) {
2290 0 : 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 6912 : RECURSE(left_type = ValidateExpression(left));
2299 6844 : RECURSE(right_type = ValidateExpression(right));
2300 :
2301 6838 : if (binop->op() != Token::BIT_OR) {
2302 21 : 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 6838 : BINOP_OVERLOAD(Intish, Intish, Signed);
2312 84 : FAIL(binop, "Invalid operands for |.");
2313 : #undef BINOP_OVERLOAD
2314 :
2315 : UNREACHABLE();
2316 : }
2317 :
2318 : // 6.8.16 ConditionalExpression
2319 26334 : AsmType* AsmTyper::ValidateConditionalExpression(Conditional* cond) {
2320 : AsmType* cond_type;
2321 13180 : RECURSE(cond_type = ValidateExpression(cond->condition()));
2322 6584 : if (!cond_type->IsA(AsmType::Int())) {
2323 42 : FAIL(cond, "Ternary operation condition should be int.");
2324 : }
2325 :
2326 : AsmType* then_type;
2327 13154 : RECURSE(then_type = ValidateExpression(cond->then_expression()));
2328 : AsmType* else_type;
2329 13154 : 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 6605 : SUCCEED_IF_BOTH_ARE(Int);
2341 669 : SUCCEED_IF_BOTH_ARE(Float);
2342 690 : SUCCEED_IF_BOTH_ARE(Double);
2343 : #undef SUCCEED_IF_BOTH_ARE
2344 :
2345 0 : FAIL(cond, "Ternary operator must return int, float, or double.");
2346 : }
2347 :
2348 : // 6.9 ValidateCall
2349 : namespace {
2350 1234 : bool ExtractIndirectCallMask(Expression* expr, uint32_t* value) {
2351 2468 : auto* as_literal = expr->AsLiteral();
2352 1234 : if (as_literal == nullptr) {
2353 : return false;
2354 : }
2355 :
2356 1234 : if (!IsLiteralInt(as_literal)) {
2357 : return false;
2358 : }
2359 :
2360 1234 : if (!as_literal->value()->ToUint32(value)) {
2361 : return false;
2362 : }
2363 :
2364 2468 : return base::bits::IsPowerOfTwo32(1 + *value);
2365 : }
2366 : } // namespace
2367 :
2368 130495 : AsmType* AsmTyper::ValidateCall(AsmType* return_type, Call* call) {
2369 : AsmType* float_coercion_type;
2370 32641 : RECURSE(float_coercion_type = ValidateFloatCoercion(call));
2371 32641 : if (float_coercion_type == AsmType::Float()) {
2372 19 : SetTypeOf(call, AsmType::Float());
2373 19 : return return_type;
2374 : }
2375 :
2376 : // TODO(jpp): we should be able to reuse the args vector's storage space.
2377 32622 : ZoneVector<AsmType*> args(zone_);
2378 32622 : args.reserve(call->arguments()->length());
2379 :
2380 133174 : for (auto* arg : *call->arguments()) {
2381 : AsmType* arg_type;
2382 67942 : RECURSE(arg_type = ValidateExpression(arg));
2383 67930 : args.emplace_back(arg_type);
2384 : }
2385 :
2386 : auto* call_expr = call->expression();
2387 :
2388 : // identifier(Expression...)
2389 74799 : if (auto* call_var_proxy = call_expr->AsVariableProxy()) {
2390 88816 : auto* call_var_info = Lookup(call_var_proxy->var());
2391 :
2392 31363 : 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 2612 : auto* call_type = AsmType::Function(zone_, return_type)->AsFunctionType();
2397 11367 : for (auto* arg : args) {
2398 6143 : call_type->AddArgument(arg->ToParameterType());
2399 : }
2400 : auto* fun_info =
2401 2612 : new (zone_) VariableInfo(reinterpret_cast<AsmType*>(call_type));
2402 : fun_info->set_mutability(VariableInfo::kImmutableGlobal);
2403 2612 : AddForwardReference(call_var_proxy, fun_info);
2404 2612 : if (!ValidAsmIdentifier(call_var_proxy->name())) {
2405 56 : FAIL(call_var_proxy,
2406 : "Invalid asm.js identifier in (forward) function name.");
2407 : }
2408 2598 : if (!AddGlobal(call_var_proxy->var(), fun_info)) {
2409 : DCHECK(false);
2410 90 : FAIL(call, "Redeclared global identifier.");
2411 : }
2412 2598 : if (call->GetCallType() != Call::OTHER_CALL) {
2413 52 : FAIL(call, "Invalid call of existing global function.");
2414 : }
2415 2585 : SetTypeOf(call_var_proxy, reinterpret_cast<AsmType*>(call_type));
2416 2585 : SetTypeOf(call, return_type);
2417 2585 : return return_type;
2418 : }
2419 :
2420 28751 : auto* callee_type = call_var_info->type()->AsCallableType();
2421 28751 : if (callee_type == nullptr) {
2422 28 : FAIL(call, "Calling something that's not a function.");
2423 : }
2424 :
2425 28744 : if (callee_type->AsFFIType() != nullptr) {
2426 6988 : if (return_type == AsmType::Float()) {
2427 28 : 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 13962 : FFIUseSignature(call_var_proxy->var(), zone_));
2433 : FFIUseSignature* sig = &ffi_use_signatures_.back();
2434 6981 : sig->return_type_ = return_type;
2435 13962 : sig->arg_types_.reserve(args.size());
2436 28946 : for (size_t i = 0; i < args.size(); ++i) {
2437 7492 : sig->arg_types_.emplace_back(args[i]);
2438 : }
2439 : }
2440 :
2441 28737 : if (!callee_type->CanBeInvokedWith(return_type, args)) {
2442 140 : FAIL(call, "Function invocation does not match function type.");
2443 : }
2444 :
2445 28702 : if (call->GetCallType() != Call::OTHER_CALL) {
2446 0 : FAIL(call, "Invalid forward call of global function.");
2447 : }
2448 :
2449 28702 : SetTypeOf(call_var_proxy, call_var_info->type());
2450 28702 : SetTypeOf(call, return_type);
2451 28702 : return return_type;
2452 : }
2453 :
2454 : // identifier[expr & n](Expression...)
2455 2494 : if (auto* call_property = call_expr->AsProperty()) {
2456 3715 : auto* index = call_property->key()->AsBinaryOperation();
2457 2481 : if (index == nullptr || index->op() != Token::BIT_AND) {
2458 52 : 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 1234 : if (!ExtractIndirectCallMask(right, &mask)) {
2466 0 : if (!ExtractIndirectCallMask(left, &mask)) {
2467 0 : FAIL(right, "Invalid indirect call mask.");
2468 : } else {
2469 : left = right;
2470 : }
2471 : }
2472 1234 : const uint32_t table_length = mask + 1;
2473 :
2474 : AsmType* left_type;
2475 1234 : RECURSE(left_type = ValidateExpression(left));
2476 1234 : if (!left_type->IsA(AsmType::Intish())) {
2477 0 : FAIL(left, "Indirect call index should be an intish.");
2478 : }
2479 :
2480 2655 : auto* name_var = call_property->obj()->AsVariableProxy();
2481 :
2482 1234 : if (name_var == nullptr) {
2483 0 : FAIL(call_property, "Invalid call.");
2484 : }
2485 :
2486 2267 : auto* name_info = Lookup(name_var->var());
2487 1234 : if (name_info == nullptr) {
2488 : // We can't fail here -- just like above.
2489 201 : auto* call_type = AsmType::Function(zone_, return_type)->AsFunctionType();
2490 780 : for (auto* arg : args) {
2491 378 : call_type->AddArgument(arg->ToParameterType());
2492 : }
2493 : auto* table_type = AsmType::FunctionTableType(
2494 201 : zone_, table_length, reinterpret_cast<AsmType*>(call_type));
2495 : auto* fun_info =
2496 201 : new (zone_) VariableInfo(reinterpret_cast<AsmType*>(table_type));
2497 : fun_info->set_mutability(VariableInfo::kImmutableGlobal);
2498 201 : AddForwardReference(name_var, fun_info);
2499 201 : if (!ValidAsmIdentifier(name_var->name())) {
2500 56 : FAIL(name_var,
2501 : "Invalid asm.js identifier in (forward) function table name.");
2502 : }
2503 187 : if (!AddGlobal(name_var->var(), fun_info)) {
2504 : DCHECK(false);
2505 0 : FAIL(call, "Redeclared global identifier.");
2506 : }
2507 187 : if (call->GetCallType() != Call::KEYED_PROPERTY_CALL) {
2508 0 : FAIL(call, "Invalid call of existing function table.");
2509 : }
2510 187 : SetTypeOf(call_property, reinterpret_cast<AsmType*>(call_type));
2511 187 : SetTypeOf(call, return_type);
2512 187 : return return_type;
2513 : }
2514 :
2515 3050 : auto* previous_type = name_info->type()->AsFunctionTableType();
2516 1033 : if (previous_type == nullptr) {
2517 28 : FAIL(call, "Identifier does not name a function table.");
2518 : }
2519 :
2520 2052 : if (table_length != previous_type->length()) {
2521 28 : 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 1019 : if (!previous_type_signature->CanBeInvokedWith(return_type, args)) {
2528 : // TODO(jpp): better error messages.
2529 56 : FAIL(call,
2530 : "Function pointer table signature does not match previous "
2531 : "signature.");
2532 : }
2533 :
2534 1005 : if (call->GetCallType() != Call::KEYED_PROPERTY_CALL) {
2535 0 : FAIL(call, "Invalid forward call of function table.");
2536 : }
2537 1005 : SetTypeOf(call_property, previous_type->signature());
2538 1005 : SetTypeOf(call, return_type);
2539 1005 : return return_type;
2540 : }
2541 :
2542 0 : FAIL(call, "Invalid call.");
2543 : }
2544 :
2545 : // 6.10 ValidateHeapAccess
2546 : namespace {
2547 104173 : bool ExtractHeapAccessShift(Expression* expr, uint32_t* value) {
2548 208346 : auto* as_literal = expr->AsLiteral();
2549 104173 : if (as_literal == nullptr) {
2550 : return false;
2551 : }
2552 :
2553 104173 : if (!IsLiteralInt(as_literal)) {
2554 : return false;
2555 : }
2556 :
2557 104173 : return as_literal->value()->ToUint32(value);
2558 : }
2559 :
2560 : // Returns whether index is too large to access a heap with the given type.
2561 9916 : bool LiteralIndexOutOfBounds(AsmType* obj_type, uint32_t index) {
2562 9916 : switch (obj_type->ElementSizeInBytes()) {
2563 : case 1:
2564 : return false;
2565 : case 2:
2566 244 : return (index & 0x80000000u) != 0;
2567 : case 4:
2568 9020 : return (index & 0xC0000000u) != 0;
2569 : case 8:
2570 76 : return (index & 0xE0000000u) != 0;
2571 : }
2572 0 : UNREACHABLE();
2573 : return true;
2574 : }
2575 :
2576 : } // namespace
2577 :
2578 383136 : AsmType* AsmTyper::ValidateHeapAccess(Property* heap,
2579 : HeapAccessType access_type) {
2580 253597 : auto* obj = heap->obj()->AsVariableProxy();
2581 126802 : if (obj == nullptr) {
2582 63 : FAIL(heap, "Invalid heap access.");
2583 : }
2584 :
2585 253583 : auto* obj_info = Lookup(obj->var());
2586 126795 : if (obj_info == nullptr) {
2587 28 : FAIL(heap, "Undeclared identifier in heap access.");
2588 : }
2589 :
2590 : auto* obj_type = obj_info->type();
2591 126788 : if (!obj_type->IsA(AsmType::Heap())) {
2592 28 : FAIL(heap, "Identifier does not represent a heap view.");
2593 : }
2594 126781 : SetTypeOf(obj, obj_type);
2595 :
2596 263485 : if (auto* key_as_literal = heap->key()->AsLiteral()) {
2597 9930 : if (!IsLiteralInt(key_as_literal)) {
2598 53 : FAIL(key_as_literal, "Heap access index must be int.");
2599 : }
2600 :
2601 : uint32_t index;
2602 9923 : if (!key_as_literal->value()->ToUint32(&index)) {
2603 28 : FAIL(key_as_literal,
2604 : "Heap access index must be a 32-bit unsigned integer.");
2605 : }
2606 :
2607 9916 : if (LiteralIndexOutOfBounds(obj_type, index)) {
2608 72 : FAIL(key_as_literal, "Heap access index is out of bounds");
2609 : }
2610 :
2611 9898 : if (access_type == LoadFromHeap) {
2612 5574 : return obj_type->LoadType();
2613 : }
2614 4324 : return obj_type->StoreType();
2615 : }
2616 :
2617 442017 : if (auto* key_as_binop = heap->key()->AsBinaryOperation()) {
2618 : uint32_t shift;
2619 215910 : if (key_as_binop->op() == Token::SAR &&
2620 320083 : ExtractHeapAccessShift(key_as_binop->right(), &shift) &&
2621 104173 : (1 << shift) == obj_type->ElementSizeInBytes()) {
2622 : AsmType* type;
2623 208284 : RECURSE(type = ValidateExpression(key_as_binop->left()));
2624 104142 : if (type->IsA(AsmType::Intish())) {
2625 104128 : if (access_type == LoadFromHeap) {
2626 61690 : return obj_type->LoadType();
2627 : }
2628 42438 : return obj_type->StoreType();
2629 : }
2630 56 : FAIL(key_as_binop, "Invalid heap access index.");
2631 : }
2632 : }
2633 :
2634 12709 : 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 25404 : RECURSE(index_type = ValidateExpression(heap->key()));
2639 12702 : if (!index_type->IsA(AsmType::Int())) {
2640 56 : FAIL(heap, "Invalid heap access index for byte array.");
2641 : }
2642 12688 : if (access_type == LoadFromHeap) {
2643 7770 : return obj_type->LoadType();
2644 : }
2645 4918 : return obj_type->StoreType();
2646 : }
2647 :
2648 28 : FAIL(heap, "Invalid heap access index.");
2649 : }
2650 :
2651 : // 6.11 ValidateFloatCoercion
2652 43147 : bool AsmTyper::IsCallToFround(Call* call) {
2653 34690 : if (call->arguments()->length() != 1) {
2654 : return false;
2655 : }
2656 :
2657 16719 : auto* call_var_proxy = call->expression()->AsVariableProxy();
2658 8457 : if (call_var_proxy == nullptr) {
2659 : return false;
2660 : }
2661 :
2662 15987 : auto* call_var_info = Lookup(call_var_proxy->var());
2663 8262 : if (call_var_info == nullptr) {
2664 : return false;
2665 : }
2666 :
2667 7725 : return call_var_info->standard_member() == kMathFround;
2668 : }
2669 :
2670 34978 : AsmType* AsmTyper::ValidateFloatCoercion(Call* call) {
2671 33507 : if (!IsCallToFround(call)) {
2672 : return nullptr;
2673 : }
2674 :
2675 818 : 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 1636 : if (auto* arg_as_call = arg->AsCall()) {
2679 151 : RECURSE(ValidateCall(AsmType::Float(), arg_as_call));
2680 137 : return AsmType::Float();
2681 : }
2682 :
2683 : // 2. fround is used for converting to float.
2684 : AsmType* arg_type;
2685 667 : RECURSE(arg_type = ValidateExpression(arg));
2686 1887 : if (arg_type->IsA(AsmType::Floatish()) || arg_type->IsA(AsmType::DoubleQ()) ||
2687 877 : arg_type->IsA(AsmType::Signed()) || arg_type->IsA(AsmType::Unsigned())) {
2688 1306 : SetTypeOf(call->expression(), fround_type_);
2689 653 : return AsmType::Float();
2690 : }
2691 :
2692 56 : FAIL(call, "Invalid argument type to fround.");
2693 : }
2694 :
2695 : // 5.1 ParameterTypeAnnotations
2696 17462 : AsmType* AsmTyper::ParameterTypeAnnotations(Variable* parameter,
2697 : Expression* annotation) {
2698 34924 : if (auto* binop = annotation->AsBinaryOperation()) {
2699 : // Must be:
2700 : // * x|0
2701 : // * x*1 (*VIOLATION* i.e.,, +x)
2702 33056 : auto* left = binop->left()->AsVariableProxy();
2703 16528 : if (left == nullptr) {
2704 0 : FAIL(
2705 : binop->left(),
2706 : "Invalid parameter type annotation - should annotate an identifier.");
2707 : }
2708 16528 : if (left->var() != parameter) {
2709 0 : FAIL(binop->left(),
2710 : "Invalid parameter type annotation - should annotate a parameter.");
2711 : }
2712 16528 : if (IsDoubleAnnotation(binop)) {
2713 1364 : SetTypeOf(left, AsmType::Double());
2714 1364 : return AsmType::Double();
2715 : }
2716 15164 : if (IsIntAnnotation(binop)) {
2717 15146 : SetTypeOf(left, AsmType::Int());
2718 15146 : return AsmType::Int();
2719 : }
2720 72 : FAIL(binop, "Invalid parameter type annotation.");
2721 : }
2722 :
2723 934 : auto* call = annotation->AsCall();
2724 934 : if (call == nullptr) {
2725 0 : FAIL(
2726 : annotation,
2727 : "Invalid float parameter type annotation - must be fround(parameter).");
2728 : }
2729 :
2730 934 : if (!IsCallToFround(call)) {
2731 0 : FAIL(annotation,
2732 : "Invalid float parameter type annotation - must be call to fround.");
2733 : }
2734 :
2735 1868 : auto* src_expr = call->arguments()->at(0)->AsVariableProxy();
2736 934 : if (src_expr == nullptr) {
2737 0 : FAIL(annotation,
2738 : "Invalid float parameter type annotation - argument to fround is not "
2739 : "an identifier.");
2740 : }
2741 :
2742 934 : if (src_expr->var() != parameter) {
2743 0 : FAIL(annotation,
2744 : "Invalid float parameter type annotation - argument to fround is not "
2745 : "a parameter.");
2746 : }
2747 :
2748 934 : SetTypeOf(src_expr, AsmType::Float());
2749 934 : return AsmType::Float();
2750 : }
2751 :
2752 : // 5.2 ReturnTypeAnnotations
2753 8972 : AsmType* AsmTyper::ReturnTypeAnnotations(Expression* ret_expr) {
2754 : DCHECK_NOT_NULL(ret_expr);
2755 :
2756 18045 : if (auto* binop = ret_expr->AsBinaryOperation()) {
2757 4627 : if (IsDoubleAnnotation(binop)) {
2758 : return AsmType::Double();
2759 4005 : } else if (IsIntAnnotation(binop)) {
2760 : return AsmType::Signed();
2761 : }
2762 104 : FAIL(ret_expr, "Invalid return type annotation.");
2763 : }
2764 :
2765 4345 : if (auto* call = ret_expr->AsCall()) {
2766 147 : if (IsCallToFround(call)) {
2767 : return AsmType::Float();
2768 : }
2769 28 : FAIL(ret_expr, "Invalid function call in return statement.");
2770 : }
2771 :
2772 6653 : if (auto* literal = ret_expr->AsLiteral()) {
2773 : int32_t _;
2774 4101 : if (IsLiteralDouble(literal)) {
2775 : return AsmType::Double();
2776 6453 : } else if (IsLiteralInt(literal) && literal->value()->ToInt32(&_)) {
2777 : return AsmType::Signed();
2778 1550 : } 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 56 : FAIL(ret_expr, "Invalid literal in return statement.");
2789 : }
2790 :
2791 97 : if (auto* proxy = ret_expr->AsVariableProxy()) {
2792 147 : auto* var_info = Lookup(proxy->var());
2793 :
2794 58 : if (var_info == nullptr) {
2795 28 : FAIL(ret_expr, "Undeclared identifier in return statement.");
2796 : }
2797 :
2798 51 : if (var_info->mutability() != VariableInfo::kConstGlobal) {
2799 52 : FAIL(ret_expr, "Identifier in return statement is not const.");
2800 : }
2801 :
2802 38 : if (!var_info->type()->IsReturnType()) {
2803 80 : 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 83 : if (auto* cond = ret_expr->AsConditional()) {
2812 : AsmType* a = AsmType::None();
2813 : AsmType* b = AsmType::None();
2814 50 : RECURSE(a = ReturnTypeAnnotations(cond->then_expression()));
2815 19 : if (a->IsA(AsmType::None())) {
2816 : return a;
2817 : }
2818 38 : RECURSE(b = ReturnTypeAnnotations(cond->else_expression()));
2819 19 : if (b->IsA(AsmType::None())) {
2820 : return b;
2821 : }
2822 19 : if (a->IsExactly(b)) {
2823 : return a;
2824 : }
2825 : }
2826 :
2827 56 : FAIL(ret_expr, "Invalid return type expression.");
2828 : }
2829 :
2830 : // 5.4 VariableTypeAnnotations
2831 : // Also used for 5.5 GlobalVariableTypeAnnotations
2832 33053 : AsmType* AsmTyper::VariableTypeAnnotations(
2833 : Expression* initializer, VariableInfo::Mutability mutability_type) {
2834 95317 : if (auto* literal = initializer->AsLiteral()) {
2835 32894 : if (IsLiteralDouble(literal)) {
2836 3794 : SetTypeOf(initializer, AsmType::Double());
2837 3794 : return AsmType::Double();
2838 : }
2839 29100 : if (!IsLiteralInt(literal)) {
2840 48 : FAIL(initializer, "Invalid type annotation - forbidden literal.");
2841 : }
2842 : int32_t i32;
2843 : uint32_t u32;
2844 : AsmType* initializer_type = nullptr;
2845 29088 : if (literal->value()->ToUint32(&u32)) {
2846 29057 : if (u32 > LargestFixNum) {
2847 : initializer_type = AsmType::Unsigned();
2848 128 : SetTypeOf(initializer, initializer_type);
2849 : } else {
2850 : initializer_type = AsmType::FixNum();
2851 28929 : SetTypeOf(initializer, initializer_type);
2852 : initializer_type = AsmType::Signed();
2853 : }
2854 31 : } else if (literal->value()->ToInt32(&i32)) {
2855 : initializer_type = AsmType::Signed();
2856 24 : SetTypeOf(initializer, initializer_type);
2857 : } else {
2858 28 : FAIL(initializer, "Invalid type annotation - forbidden literal.");
2859 : }
2860 29081 : if (mutability_type != VariableInfo::kConstGlobal) {
2861 : return AsmType::Int();
2862 : }
2863 26 : return initializer_type;
2864 : }
2865 :
2866 159 : if (auto* proxy = initializer->AsVariableProxy()) {
2867 93 : auto* var_info = Lookup(proxy->var());
2868 :
2869 32 : if (var_info == nullptr) {
2870 28 : FAIL(initializer,
2871 : "Undeclared identifier in variable declaration initializer.");
2872 : }
2873 :
2874 25 : if (var_info->mutability() != VariableInfo::kConstGlobal) {
2875 28 : FAIL(initializer,
2876 : "Identifier in variable declaration initializer must be const.");
2877 : }
2878 :
2879 18 : SetTypeOf(initializer, var_info->type());
2880 18 : return var_info->type();
2881 : }
2882 :
2883 81 : auto* call = initializer->AsCall();
2884 127 : if (call == nullptr) {
2885 100 : FAIL(initializer,
2886 : "Invalid variable initialization - it should be a literal, const, or "
2887 : "fround(literal).");
2888 : }
2889 :
2890 102 : if (!IsCallToFround(call)) {
2891 84 : FAIL(initializer,
2892 : "Invalid float coercion - expected call fround(literal).");
2893 : }
2894 :
2895 155 : auto* src_expr = call->arguments()->at(0)->AsLiteral();
2896 81 : if (src_expr == nullptr) {
2897 28 : 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 74 : if (!src_expr->raw_value()->IsNumber()) {
2910 24 : 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
2919 2900 : AsmType* AsmTyper::NewHeapView(CallNew* new_heap_view) {
2920 1464 : auto* heap_type = new_heap_view->expression()->AsProperty();
2921 1464 : if (heap_type == nullptr) {
2922 82 : FAIL(new_heap_view, "Invalid type after new.");
2923 : }
2924 4270 : auto* heap_view_info = ImportLookup(heap_type);
2925 :
2926 1457 : if (heap_view_info == nullptr) {
2927 56 : FAIL(new_heap_view, "Unknown stdlib member in heap view declaration.");
2928 : }
2929 :
2930 1443 : if (!heap_view_info->type()->IsA(AsmType::Heap())) {
2931 28 : FAIL(new_heap_view, "Type is not a heap view type.");
2932 : }
2933 :
2934 1436 : if (new_heap_view->arguments()->length() != 1) {
2935 132 : FAIL(new_heap_view, "Invalid number of arguments when creating heap view.");
2936 : }
2937 :
2938 1403 : auto* heap = new_heap_view->arguments()->at(0);
2939 2832 : auto* heap_var_proxy = heap->AsVariableProxy();
2940 :
2941 1403 : if (heap_var_proxy == nullptr) {
2942 28 : FAIL(heap,
2943 : "Heap view creation parameter should be the module's heap parameter.");
2944 : }
2945 :
2946 2785 : auto* heap_var_info = Lookup(heap_var_proxy->var());
2947 :
2948 1396 : if (heap_var_info == nullptr) {
2949 28 : FAIL(heap, "Undeclared identifier instead of heap parameter.");
2950 : }
2951 :
2952 1389 : if (!heap_var_info->IsHeap()) {
2953 76 : 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 1370 : return heap_view_info->type();
2959 : }
2960 :
2961 : } // namespace wasm
2962 : } // namespace internal
2963 : } // namespace v8
|