1 // Copyright 2012 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/ast/ast.h" 6 7 #include <cmath> // For isfinite. 8 #include <vector> 9 10 #include "src/ast/prettyprinter.h" 11 #include "src/ast/scopes.h" 12 #include "src/base/hashmap.h" 13 #include "src/builtins/builtins-constructor.h" 14 #include "src/builtins/builtins.h" 15 #include "src/code-stubs.h" 16 #include "src/contexts.h" 17 #include "src/conversions-inl.h" 18 #include "src/double.h" 19 #include "src/elements.h" 20 #include "src/objects-inl.h" 21 #include "src/objects/literal-objects-inl.h" 22 #include "src/objects/literal-objects.h" 23 #include "src/objects/map.h" 24 #include "src/property-details.h" 25 #include "src/property.h" 26 #include "src/string-stream.h" 27 28 namespace v8 { 29 namespace internal { 30 31 // ---------------------------------------------------------------------------- 32 // Implementation of other node functionality. 33 34 #ifdef DEBUG 35 36 static const char* NameForNativeContextIntrinsicIndex(uint32_t idx) { 37 switch (idx) { 38 #define NATIVE_CONTEXT_FIELDS_IDX(NAME, Type, name) \ 39 case Context::NAME: \ 40 return #name; 41 42 NATIVE_CONTEXT_FIELDS(NATIVE_CONTEXT_FIELDS_IDX) 43 #undef NATIVE_CONTEXT_FIELDS_IDX 44 45 default: 46 break; 47 } 48 49 return "UnknownIntrinsicIndex"; 50 } 51 52 void AstNode::Print() { Print(Isolate::Current()); } 53 54 void AstNode::Print(Isolate* isolate) { 55 AllowHandleDereference allow_deref; 56 AstPrinter::PrintOut(isolate, this); 57 } 58 59 60 #endif // DEBUG 61 62 #define RETURN_NODE(Node) \ 63 case k##Node: \ 64 return static_cast<Node*>(this); 65 66 IterationStatement* AstNode::AsIterationStatement() { 67 switch (node_type()) { 68 ITERATION_NODE_LIST(RETURN_NODE); 69 default: 70 return nullptr; 71 } 72 } 73 74 BreakableStatement* AstNode::AsBreakableStatement() { 75 switch (node_type()) { 76 BREAKABLE_NODE_LIST(RETURN_NODE); 77 ITERATION_NODE_LIST(RETURN_NODE); 78 default: 79 return nullptr; 80 } 81 } 82 83 MaterializedLiteral* AstNode::AsMaterializedLiteral() { 84 switch (node_type()) { 85 LITERAL_NODE_LIST(RETURN_NODE); 86 default: 87 return nullptr; 88 } 89 } 90 91 #undef RETURN_NODE 92 93 bool Expression::IsSmiLiteral() const { 94 return IsLiteral() && AsLiteral()->type() == Literal::kSmi; 95 } 96 97 bool Expression::IsNumberLiteral() const { 98 return IsLiteral() && AsLiteral()->IsNumber(); 99 } 100 101 bool Expression::IsStringLiteral() const { 102 return IsLiteral() && AsLiteral()->type() == Literal::kString; 103 } 104 105 bool Expression::IsPropertyName() const { 106 return IsLiteral() && AsLiteral()->IsPropertyName(); 107 } 108 109 bool Expression::IsNullLiteral() const { 110 return IsLiteral() && AsLiteral()->type() == Literal::kNull; 111 } 112 113 bool Expression::IsTheHoleLiteral() const { 114 return IsLiteral() && AsLiteral()->type() == Literal::kTheHole; 115 } 116 117 bool Expression::IsCompileTimeValue() { 118 if (IsLiteral()) return true; 119 MaterializedLiteral* literal = AsMaterializedLiteral(); 120 if (literal == nullptr) return false; 121 return literal->IsSimple(); 122 } 123 124 bool Expression::IsUndefinedLiteral() const { 125 if (IsLiteral() && AsLiteral()->type() == Literal::kUndefined) return true; 126 127 const VariableProxy* var_proxy = AsVariableProxy(); 128 if (var_proxy == nullptr) return false; 129 Variable* var = var_proxy->var(); 130 // The global identifier "undefined" is immutable. Everything 131 // else could be reassigned. 132 return var != nullptr && var->IsUnallocated() && 133 var_proxy->raw_name()->IsOneByteEqualTo("undefined"); 134 } 135 136 bool Expression::ToBooleanIsTrue() const { 137 return IsLiteral() && AsLiteral()->ToBooleanIsTrue(); 138 } 139 140 bool Expression::ToBooleanIsFalse() const { 141 return IsLiteral() && AsLiteral()->ToBooleanIsFalse(); 142 } 143 144 bool Expression::IsValidReferenceExpression() const { 145 // We don't want expressions wrapped inside RewritableExpression to be 146 // considered as valid reference expressions, as they will be rewritten 147 // to something (most probably involving a do expression). 148 if (IsRewritableExpression()) return false; 149 return IsProperty() || 150 (IsVariableProxy() && AsVariableProxy()->IsValidReferenceExpression()); 151 } 152 153 bool Expression::IsAnonymousFunctionDefinition() const { 154 return (IsFunctionLiteral() && 155 AsFunctionLiteral()->IsAnonymousFunctionDefinition()) || 156 (IsClassLiteral() && 157 AsClassLiteral()->IsAnonymousFunctionDefinition()); 158 } 159 160 bool Expression::IsConciseMethodDefinition() const { 161 return IsFunctionLiteral() && IsConciseMethod(AsFunctionLiteral()->kind()); 162 } 163 164 bool Expression::IsAccessorFunctionDefinition() const { 165 return IsFunctionLiteral() && IsAccessorFunction(AsFunctionLiteral()->kind()); 166 } 167 168 bool Statement::IsJump() const { 169 switch (node_type()) { 170 #define JUMP_NODE_LIST(V) \ 171 V(Block) \ 172 V(ExpressionStatement) \ 173 V(ContinueStatement) \ 174 V(BreakStatement) \ 175 V(ReturnStatement) \ 176 V(IfStatement) 177 #define GENERATE_CASE(Node) \ 178 case k##Node: \ 179 return static_cast<const Node*>(this)->IsJump(); 180 JUMP_NODE_LIST(GENERATE_CASE) 181 #undef GENERATE_CASE 182 #undef JUMP_NODE_LIST 183 default: 184 return false; 185 } 186 } 187 188 VariableProxy::VariableProxy(Variable* var, int start_position) 189 : Expression(start_position, kVariableProxy), 190 raw_name_(var->raw_name()), 191 next_unresolved_(nullptr) { 192 bit_field_ |= IsThisField::encode(var->is_this()) | 193 IsAssignedField::encode(false) | 194 IsResolvedField::encode(false) | 195 HoleCheckModeField::encode(HoleCheckMode::kElided); 196 BindTo(var); 197 } 198 199 VariableProxy::VariableProxy(const VariableProxy* copy_from) 200 : Expression(copy_from->position(), kVariableProxy), 201 next_unresolved_(nullptr) { 202 bit_field_ = copy_from->bit_field_; 203 DCHECK(!copy_from->is_resolved()); 204 raw_name_ = copy_from->raw_name_; 205 } 206 207 void VariableProxy::BindTo(Variable* var) { 208 DCHECK((is_this() && var->is_this()) || raw_name() == var->raw_name()); 209 set_var(var); 210 set_is_resolved(); 211 var->set_is_used(); 212 if (is_assigned()) var->set_maybe_assigned(); 213 } 214 215 Assignment::Assignment(NodeType node_type, Token::Value op, Expression* target, 216 Expression* value, int pos) 217 : Expression(pos, node_type), target_(target), value_(value) { 218 bit_field_ |= TokenField::encode(op); 219 } 220 221 void FunctionLiteral::set_inferred_name(Handle<String> inferred_name) { 222 DCHECK(!inferred_name.is_null()); 223 inferred_name_ = inferred_name; 224 DCHECK(raw_inferred_name_ == nullptr || raw_inferred_name_->IsEmpty()); 225 raw_inferred_name_ = nullptr; 226 scope()->set_has_inferred_function_name(true); 227 } 228 229 void FunctionLiteral::set_raw_inferred_name( 230 const AstConsString* raw_inferred_name) { 231 DCHECK_NOT_NULL(raw_inferred_name); 232 raw_inferred_name_ = raw_inferred_name; 233 DCHECK(inferred_name_.is_null()); 234 inferred_name_ = Handle<String>(); 235 scope()->set_has_inferred_function_name(true); 236 } 237 238 bool FunctionLiteral::ShouldEagerCompile() const { 239 return scope()->ShouldEagerCompile(); 240 } 241 242 void FunctionLiteral::SetShouldEagerCompile() { 243 scope()->set_should_eager_compile(); 244 } 245 246 bool FunctionLiteral::AllowsLazyCompilation() { 247 return scope()->AllowsLazyCompilation(); 248 } 249 250 Handle<String> FunctionLiteral::name(Isolate* isolate) const { 251 return raw_name_ ? raw_name_->string() : isolate->factory()->empty_string(); 252 } 253 254 int FunctionLiteral::start_position() const { 255 return scope()->start_position(); 256 } 257 258 259 int FunctionLiteral::end_position() const { 260 return scope()->end_position(); 261 } 262 263 264 LanguageMode FunctionLiteral::language_mode() const { 265 return scope()->language_mode(); 266 } 267 268 FunctionKind FunctionLiteral::kind() const { return scope()->function_kind(); } 269 270 bool FunctionLiteral::NeedsHomeObject(Expression* expr) { 271 if (expr == nullptr || !expr->IsFunctionLiteral()) return false; 272 DCHECK_NOT_NULL(expr->AsFunctionLiteral()->scope()); 273 return expr->AsFunctionLiteral()->scope()->NeedsHomeObject(); 274 } 275 276 std::unique_ptr<char[]> FunctionLiteral::GetDebugName() const { 277 const AstConsString* cons_string; 278 if (raw_name_ != nullptr && !raw_name_->IsEmpty()) { 279 cons_string = raw_name_; 280 } else if (raw_inferred_name_ != nullptr && !raw_inferred_name_->IsEmpty()) { 281 cons_string = raw_inferred_name_; 282 } else if (!inferred_name_.is_null()) { 283 AllowHandleDereference allow_deref; 284 return inferred_name_->ToCString(); 285 } else { 286 char* empty_str = new char[1]; 287 empty_str[0] = 0; 288 return std::unique_ptr<char[]>(empty_str); 289 } 290 291 // TODO(rmcilroy): Deal with two-character strings. 292 std::vector<char> result_vec; 293 std::forward_list<const AstRawString*> strings = cons_string->ToRawStrings(); 294 for (const AstRawString* string : strings) { 295 if (!string->is_one_byte()) break; 296 for (int i = 0; i < string->length(); i++) { 297 result_vec.push_back(string->raw_data()[i]); 298 } 299 } 300 std::unique_ptr<char[]> result(new char[result_vec.size() + 1]); 301 memcpy(result.get(), result_vec.data(), result_vec.size()); 302 result[result_vec.size()] = '\0'; 303 return result; 304 } 305 306 ObjectLiteralProperty::ObjectLiteralProperty(Expression* key, Expression* value, 307 Kind kind, bool is_computed_name) 308 : LiteralProperty(key, value, is_computed_name), 309 kind_(kind), 310 emit_store_(true) {} 311 312 ObjectLiteralProperty::ObjectLiteralProperty(AstValueFactory* ast_value_factory, 313 Expression* key, Expression* value, 314 bool is_computed_name) 315 : LiteralProperty(key, value, is_computed_name), emit_store_(true) { 316 if (!is_computed_name && key->AsLiteral()->IsString() && 317 key->AsLiteral()->AsRawString() == ast_value_factory->proto_string()) { 318 kind_ = PROTOTYPE; 319 } else if (value_->AsMaterializedLiteral() != nullptr) { 320 kind_ = MATERIALIZED_LITERAL; 321 } else if (value_->IsLiteral()) { 322 kind_ = CONSTANT; 323 } else { 324 kind_ = COMPUTED; 325 } 326 } 327 328 bool LiteralProperty::NeedsSetFunctionName() const { 329 return is_computed_name_ && (value_->IsAnonymousFunctionDefinition() || 330 value_->IsConciseMethodDefinition() || 331 value_->IsAccessorFunctionDefinition()); 332 } 333 334 ClassLiteralProperty::ClassLiteralProperty(Expression* key, Expression* value, 335 Kind kind, bool is_static, 336 bool is_computed_name) 337 : LiteralProperty(key, value, is_computed_name), 338 kind_(kind), 339 is_static_(is_static), 340 private_or_computed_name_var_(nullptr) {} 341 342 bool ObjectLiteral::Property::IsCompileTimeValue() const { 343 return kind_ == CONSTANT || 344 (kind_ == MATERIALIZED_LITERAL && value_->IsCompileTimeValue()); 345 } 346 347 348 void ObjectLiteral::Property::set_emit_store(bool emit_store) { 349 emit_store_ = emit_store; 350 } 351 352 bool ObjectLiteral::Property::emit_store() const { return emit_store_; } 353 354 void ObjectLiteral::CalculateEmitStore(Zone* zone) { 355 const auto GETTER = ObjectLiteral::Property::GETTER; 356 const auto SETTER = ObjectLiteral::Property::SETTER; 357 358 ZoneAllocationPolicy allocator(zone); 359 360 CustomMatcherZoneHashMap table( 361 Literal::Match, ZoneHashMap::kDefaultHashMapCapacity, allocator); 362 for (int i = properties()->length() - 1; i >= 0; i--) { 363 ObjectLiteral::Property* property = properties()->at(i); 364 if (property->is_computed_name()) continue; 365 if (property->IsPrototype()) continue; 366 Literal* literal = property->key()->AsLiteral(); 367 DCHECK(!literal->IsNullLiteral()); 368 369 uint32_t hash = literal->Hash(); 370 ZoneHashMap::Entry* entry = table.LookupOrInsert(literal, hash, allocator); 371 if (entry->value == nullptr) { 372 entry->value = property; 373 } else { 374 // We already have a later definition of this property, so we don't need 375 // to emit a store for the current one. 376 // 377 // There are two subtleties here. 378 // 379 // (1) Emitting a store might actually be incorrect. For example, in {get 380 // foo() {}, foo: 42}, the getter store would override the data property 381 // (which, being a non-computed compile-time valued property, is already 382 // part of the initial literal object. 383 // 384 // (2) If the later definition is an accessor (say, a getter), and the 385 // current definition is a complementary accessor (here, a setter), then 386 // we still must emit a store for the current definition. 387 388 auto later_kind = 389 static_cast<ObjectLiteral::Property*>(entry->value)->kind(); 390 bool complementary_accessors = 391 (property->kind() == GETTER && later_kind == SETTER) || 392 (property->kind() == SETTER && later_kind == GETTER); 393 if (!complementary_accessors) { 394 property->set_emit_store(false); 395 if (later_kind == GETTER || later_kind == SETTER) { 396 entry->value = property; 397 } 398 } 399 } 400 } 401 } 402 403 void ObjectLiteral::InitFlagsForPendingNullPrototype(int i) { 404 // We still check for __proto__:null after computed property names. 405 for (; i < properties()->length(); i++) { 406 if (properties()->at(i)->IsNullPrototype()) { 407 set_has_null_protoype(true); 408 break; 409 } 410 } 411 } 412 413 int ObjectLiteral::InitDepthAndFlags() { 414 if (is_initialized()) return depth(); 415 bool is_simple = true; 416 bool has_seen_prototype = false; 417 bool needs_initial_allocation_site = false; 418 int depth_acc = 1; 419 uint32_t nof_properties = 0; 420 uint32_t elements = 0; 421 uint32_t max_element_index = 0; 422 for (int i = 0; i < properties()->length(); i++) { 423 ObjectLiteral::Property* property = properties()->at(i); 424 if (property->IsPrototype()) { 425 has_seen_prototype = true; 426 // __proto__:null has no side-effects and is set directly on the 427 // boilerplate. 428 if (property->IsNullPrototype()) { 429 set_has_null_protoype(true); 430 continue; 431 } 432 DCHECK(!has_null_prototype()); 433 is_simple = false; 434 continue; 435 } 436 if (nof_properties == boilerplate_properties_) { 437 DCHECK(property->is_computed_name()); 438 is_simple = false; 439 if (!has_seen_prototype) InitFlagsForPendingNullPrototype(i); 440 break; 441 } 442 DCHECK(!property->is_computed_name()); 443 444 MaterializedLiteral* literal = property->value()->AsMaterializedLiteral(); 445 if (literal != nullptr) { 446 int subliteral_depth = literal->InitDepthAndFlags() + 1; 447 if (subliteral_depth > depth_acc) depth_acc = subliteral_depth; 448 needs_initial_allocation_site |= literal->NeedsInitialAllocationSite(); 449 } 450 451 Literal* key = property->key()->AsLiteral(); 452 Expression* value = property->value(); 453 454 bool is_compile_time_value = value->IsCompileTimeValue(); 455 is_simple = is_simple && is_compile_time_value; 456 457 // Keep track of the number of elements in the object literal and 458 // the largest element index. If the largest element index is 459 // much larger than the number of elements, creating an object 460 // literal with fast elements will be a waste of space. 461 uint32_t element_index = 0; 462 if (key->AsArrayIndex(&element_index)) { 463 max_element_index = Max(element_index, max_element_index); 464 elements++; 465 } else { 466 DCHECK(key->IsPropertyName()); 467 } 468 469 nof_properties++; 470 } 471 472 set_depth(depth_acc); 473 set_is_simple(is_simple); 474 set_needs_initial_allocation_site(needs_initial_allocation_site); 475 set_has_elements(elements > 0); 476 set_fast_elements((max_element_index <= 32) || 477 ((2 * elements) >= max_element_index)); 478 return depth_acc; 479 } 480 481 void ObjectLiteral::BuildBoilerplateDescription(Isolate* isolate) { 482 if (!boilerplate_description_.is_null()) return; 483 484 int index_keys = 0; 485 bool has_seen_proto = false; 486 for (int i = 0; i < properties()->length(); i++) { 487 ObjectLiteral::Property* property = properties()->at(i); 488 if (property->IsPrototype()) { 489 has_seen_proto = true; 490 continue; 491 } 492 if (property->is_computed_name()) { 493 continue; 494 } 495 496 Literal* key = property->key()->AsLiteral(); 497 498 if (!key->IsPropertyName()) { 499 index_keys++; 500 } 501 } 502 503 Handle<ObjectBoilerplateDescription> boilerplate_description = 504 isolate->factory()->NewObjectBoilerplateDescription( 505 boilerplate_properties_, properties()->length(), index_keys, 506 has_seen_proto); 507 508 int position = 0; 509 for (int i = 0; i < properties()->length(); i++) { 510 ObjectLiteral::Property* property = properties()->at(i); 511 if (property->IsPrototype()) continue; 512 513 if (static_cast<uint32_t>(position) == boilerplate_properties_) { 514 DCHECK(property->is_computed_name()); 515 break; 516 } 517 DCHECK(!property->is_computed_name()); 518 519 MaterializedLiteral* m_literal = property->value()->AsMaterializedLiteral(); 520 if (m_literal != nullptr) { 521 m_literal->BuildConstants(isolate); 522 } 523 524 // Add CONSTANT and COMPUTED properties to boilerplate. Use undefined 525 // value for COMPUTED properties, the real value is filled in at 526 // runtime. The enumeration order is maintained. 527 Literal* key_literal = property->key()->AsLiteral(); 528 uint32_t element_index = 0; 529 Handle<Object> key = 530 key_literal->AsArrayIndex(&element_index) 531 ? isolate->factory()->NewNumberFromUint(element_index) 532 : Handle<Object>::cast(key_literal->AsRawPropertyName()->string()); 533 534 Handle<Object> value = GetBoilerplateValue(property->value(), isolate); 535 536 // Add name, value pair to the fixed array. 537 boilerplate_description->set_key_value(position++, *key, *value); 538 } 539 540 boilerplate_description->set_flags(EncodeLiteralType()); 541 542 boilerplate_description_ = boilerplate_description; 543 } 544 545 bool ObjectLiteral::IsFastCloningSupported() const { 546 // The CreateShallowObjectLiteratal builtin doesn't copy elements, and object 547 // literals don't support copy-on-write (COW) elements for now. 548 // TODO(mvstanton): make object literals support COW elements. 549 return fast_elements() && is_shallow() && 550 properties_count() <= 551 ConstructorBuiltins::kMaximumClonedShallowObjectProperties; 552 } 553 554 bool ArrayLiteral::is_empty() const { 555 DCHECK(is_initialized()); 556 return values()->is_empty() && (boilerplate_description().is_null() || 557 boilerplate_description()->is_empty()); 558 } 559 560 int ArrayLiteral::InitDepthAndFlags() { 561 if (is_initialized()) return depth(); 562 563 int constants_length = 564 first_spread_index_ >= 0 ? first_spread_index_ : values()->length(); 565 566 // Fill in the literals. 567 bool is_simple = first_spread_index_ < 0; 568 int depth_acc = 1; 569 int array_index = 0; 570 for (; array_index < constants_length; array_index++) { 571 Expression* element = values()->at(array_index); 572 MaterializedLiteral* literal = element->AsMaterializedLiteral(); 573 if (literal != nullptr) { 574 int subliteral_depth = literal->InitDepthAndFlags() + 1; 575 if (subliteral_depth > depth_acc) depth_acc = subliteral_depth; 576 } 577 578 if (!element->IsCompileTimeValue()) { 579 is_simple = false; 580 } 581 } 582 583 set_depth(depth_acc); 584 set_is_simple(is_simple); 585 // Array literals always need an initial allocation site to properly track 586 // elements transitions. 587 set_needs_initial_allocation_site(true); 588 return depth_acc; 589 } 590 591 void ArrayLiteral::BuildBoilerplateDescription(Isolate* isolate) { 592 if (!boilerplate_description_.is_null()) return; 593 594 int constants_length = 595 first_spread_index_ >= 0 ? first_spread_index_ : values()->length(); 596 ElementsKind kind = FIRST_FAST_ELEMENTS_KIND; 597 Handle<FixedArray> fixed_array = 598 isolate->factory()->NewFixedArrayWithHoles(constants_length); 599 600 // Fill in the literals. 601 bool is_holey = false; 602 int array_index = 0; 603 for (; array_index < constants_length; array_index++) { 604 Expression* element = values()->at(array_index); 605 DCHECK(!element->IsSpread()); 606 MaterializedLiteral* m_literal = element->AsMaterializedLiteral(); 607 if (m_literal != nullptr) { 608 m_literal->BuildConstants(isolate); 609 } 610 611 // New handle scope here, needs to be after BuildContants(). 612 HandleScope scope(isolate); 613 Handle<Object> boilerplate_value = GetBoilerplateValue(element, isolate); 614 if (boilerplate_value->IsTheHole(isolate)) { 615 is_holey = true; 616 continue; 617 } 618 619 if (boilerplate_value->IsUninitialized(isolate)) { 620 boilerplate_value = handle(Smi::kZero, isolate); 621 } 622 623 kind = GetMoreGeneralElementsKind(kind, 624 boilerplate_value->OptimalElementsKind()); 625 fixed_array->set(array_index, *boilerplate_value); 626 } 627 628 if (is_holey) kind = GetHoleyElementsKind(kind); 629 630 // Simple and shallow arrays can be lazily copied, we transform the 631 // elements array to a copy-on-write array. 632 if (is_simple() && depth() == 1 && array_index > 0 && 633 IsSmiOrObjectElementsKind(kind)) { 634 fixed_array->set_map(ReadOnlyRoots(isolate).fixed_cow_array_map()); 635 } 636 637 Handle<FixedArrayBase> elements = fixed_array; 638 if (IsDoubleElementsKind(kind)) { 639 ElementsAccessor* accessor = ElementsAccessor::ForKind(kind); 640 elements = isolate->factory()->NewFixedDoubleArray(constants_length); 641 // We are copying from non-fast-double to fast-double. 642 ElementsKind from_kind = TERMINAL_FAST_ELEMENTS_KIND; 643 accessor->CopyElements(isolate, fixed_array, from_kind, elements, 644 constants_length); 645 } 646 647 boilerplate_description_ = 648 isolate->factory()->NewArrayBoilerplateDescription(kind, elements); 649 } 650 651 bool ArrayLiteral::IsFastCloningSupported() const { 652 return depth() <= 1 && 653 values()->length() <= 654 ConstructorBuiltins::kMaximumClonedShallowArrayElements; 655 } 656 657 bool MaterializedLiteral::IsSimple() const { 658 if (IsArrayLiteral()) return AsArrayLiteral()->is_simple(); 659 if (IsObjectLiteral()) return AsObjectLiteral()->is_simple(); 660 DCHECK(IsRegExpLiteral()); 661 return false; 662 } 663 664 Handle<Object> MaterializedLiteral::GetBoilerplateValue(Expression* expression, 665 Isolate* isolate) { 666 if (expression->IsLiteral()) { 667 return expression->AsLiteral()->BuildValue(isolate); 668 } 669 if (expression->IsCompileTimeValue()) { 670 if (expression->IsObjectLiteral()) { 671 ObjectLiteral* object_literal = expression->AsObjectLiteral(); 672 DCHECK(object_literal->is_simple()); 673 return object_literal->boilerplate_description(); 674 } else { 675 DCHECK(expression->IsArrayLiteral()); 676 ArrayLiteral* array_literal = expression->AsArrayLiteral(); 677 DCHECK(array_literal->is_simple()); 678 return array_literal->boilerplate_description(); 679 } 680 } 681 return isolate->factory()->uninitialized_value(); 682 } 683 684 int MaterializedLiteral::InitDepthAndFlags() { 685 if (IsArrayLiteral()) return AsArrayLiteral()->InitDepthAndFlags(); 686 if (IsObjectLiteral()) return AsObjectLiteral()->InitDepthAndFlags(); 687 DCHECK(IsRegExpLiteral()); 688 return 1; 689 } 690 691 bool MaterializedLiteral::NeedsInitialAllocationSite() { 692 if (IsArrayLiteral()) { 693 return AsArrayLiteral()->needs_initial_allocation_site(); 694 } 695 if (IsObjectLiteral()) { 696 return AsObjectLiteral()->needs_initial_allocation_site(); 697 } 698 DCHECK(IsRegExpLiteral()); 699 return false; 700 } 701 702 void MaterializedLiteral::BuildConstants(Isolate* isolate) { 703 if (IsArrayLiteral()) { 704 AsArrayLiteral()->BuildBoilerplateDescription(isolate); 705 return; 706 } 707 if (IsObjectLiteral()) { 708 AsObjectLiteral()->BuildBoilerplateDescription(isolate); 709 return; 710 } 711 DCHECK(IsRegExpLiteral()); 712 } 713 714 Handle<TemplateObjectDescription> GetTemplateObject::GetOrBuildDescription( 715 Isolate* isolate) { 716 Handle<FixedArray> raw_strings = 717 isolate->factory()->NewFixedArray(this->raw_strings()->length(), TENURED); 718 bool raw_and_cooked_match = true; 719 for (int i = 0; i < raw_strings->length(); ++i) { 720 if (this->cooked_strings()->at(i) == nullptr || 721 *this->raw_strings()->at(i)->string() != 722 *this->cooked_strings()->at(i)->string()) { 723 raw_and_cooked_match = false; 724 } 725 raw_strings->set(i, *this->raw_strings()->at(i)->string()); 726 } 727 Handle<FixedArray> cooked_strings = raw_strings; 728 if (!raw_and_cooked_match) { 729 cooked_strings = isolate->factory()->NewFixedArray( 730 this->cooked_strings()->length(), TENURED); 731 for (int i = 0; i < cooked_strings->length(); ++i) { 732 if (this->cooked_strings()->at(i) != nullptr) { 733 cooked_strings->set(i, *this->cooked_strings()->at(i)->string()); 734 } else { 735 cooked_strings->set(i, ReadOnlyRoots(isolate).undefined_value()); 736 } 737 } 738 } 739 return isolate->factory()->NewTemplateObjectDescription(raw_strings, 740 cooked_strings); 741 } 742 743 static bool IsCommutativeOperationWithSmiLiteral(Token::Value op) { 744 // Add is not commutative due to potential for string addition. 745 return op == Token::MUL || op == Token::BIT_AND || op == Token::BIT_OR || 746 op == Token::BIT_XOR; 747 } 748 749 // Check for the pattern: x + 1. 750 static bool MatchSmiLiteralOperation(Expression* left, Expression* right, 751 Expression** expr, Smi** literal) { 752 if (right->IsSmiLiteral()) { 753 *expr = left; 754 *literal = right->AsLiteral()->AsSmiLiteral(); 755 return true; 756 } 757 return false; 758 } 759 760 bool BinaryOperation::IsSmiLiteralOperation(Expression** subexpr, 761 Smi** literal) { 762 return MatchSmiLiteralOperation(left_, right_, subexpr, literal) || 763 (IsCommutativeOperationWithSmiLiteral(op()) && 764 MatchSmiLiteralOperation(right_, left_, subexpr, literal)); 765 } 766 767 static bool IsTypeof(Expression* expr) { 768 UnaryOperation* maybe_unary = expr->AsUnaryOperation(); 769 return maybe_unary != nullptr && maybe_unary->op() == Token::TYPEOF; 770 } 771 772 // Check for the pattern: typeof <expression> equals <string literal>. 773 static bool MatchLiteralCompareTypeof(Expression* left, Token::Value op, 774 Expression* right, Expression** expr, 775 Literal** literal) { 776 if (IsTypeof(left) && right->IsStringLiteral() && Token::IsEqualityOp(op)) { 777 *expr = left->AsUnaryOperation()->expression(); 778 *literal = right->AsLiteral(); 779 return true; 780 } 781 return false; 782 } 783 784 bool CompareOperation::IsLiteralCompareTypeof(Expression** expr, 785 Literal** literal) { 786 return MatchLiteralCompareTypeof(left_, op(), right_, expr, literal) || 787 MatchLiteralCompareTypeof(right_, op(), left_, expr, literal); 788 } 789 790 791 static bool IsVoidOfLiteral(Expression* expr) { 792 UnaryOperation* maybe_unary = expr->AsUnaryOperation(); 793 return maybe_unary != nullptr && maybe_unary->op() == Token::VOID && 794 maybe_unary->expression()->IsLiteral(); 795 } 796 797 798 // Check for the pattern: void <literal> equals <expression> or 799 // undefined equals <expression> 800 static bool MatchLiteralCompareUndefined(Expression* left, 801 Token::Value op, 802 Expression* right, 803 Expression** expr) { 804 if (IsVoidOfLiteral(left) && Token::IsEqualityOp(op)) { 805 *expr = right; 806 return true; 807 } 808 if (left->IsUndefinedLiteral() && Token::IsEqualityOp(op)) { 809 *expr = right; 810 return true; 811 } 812 return false; 813 } 814 815 bool CompareOperation::IsLiteralCompareUndefined(Expression** expr) { 816 return MatchLiteralCompareUndefined(left_, op(), right_, expr) || 817 MatchLiteralCompareUndefined(right_, op(), left_, expr); 818 } 819 820 // Check for the pattern: null equals <expression> 821 static bool MatchLiteralCompareNull(Expression* left, 822 Token::Value op, 823 Expression* right, 824 Expression** expr) { 825 if (left->IsNullLiteral() && Token::IsEqualityOp(op)) { 826 *expr = right; 827 return true; 828 } 829 return false; 830 } 831 832 bool CompareOperation::IsLiteralCompareNull(Expression** expr) { 833 return MatchLiteralCompareNull(left_, op(), right_, expr) || 834 MatchLiteralCompareNull(right_, op(), left_, expr); 835 } 836 837 Call::CallType Call::GetCallType() const { 838 VariableProxy* proxy = expression()->AsVariableProxy(); 839 if (proxy != nullptr) { 840 if (proxy->var()->IsUnallocated()) { 841 return GLOBAL_CALL; 842 } else if (proxy->var()->IsLookupSlot()) { 843 // Calls going through 'with' always use VariableMode::kDynamic rather 844 // than VariableMode::kDynamicLocal or VariableMode::kDynamicGlobal. 845 return proxy->var()->mode() == VariableMode::kDynamic ? WITH_CALL 846 : OTHER_CALL; 847 } 848 } 849 850 if (expression()->IsSuperCallReference()) return SUPER_CALL; 851 852 Property* property = expression()->AsProperty(); 853 if (property != nullptr) { 854 bool is_super = property->IsSuperAccess(); 855 if (property->key()->IsPropertyName()) { 856 return is_super ? NAMED_SUPER_PROPERTY_CALL : NAMED_PROPERTY_CALL; 857 } else { 858 return is_super ? KEYED_SUPER_PROPERTY_CALL : KEYED_PROPERTY_CALL; 859 } 860 } 861 862 if (expression()->IsResolvedProperty()) { 863 return RESOLVED_PROPERTY_CALL; 864 } 865 866 return OTHER_CALL; 867 } 868 869 CaseClause::CaseClause(Expression* label, ZonePtrList<Statement>* statements) 870 : label_(label), statements_(statements) {} 871 872 bool Literal::IsPropertyName() const { 873 if (type() != kString) return false; 874 uint32_t index; 875 return !string_->AsArrayIndex(&index); 876 } 877 878 bool Literal::ToUint32(uint32_t* value) const { 879 switch (type()) { 880 case kString: 881 return string_->AsArrayIndex(value); 882 case kSmi: 883 if (smi_ < 0) return false; 884 *value = static_cast<uint32_t>(smi_); 885 return true; 886 case kHeapNumber: 887 return DoubleToUint32IfEqualToSelf(AsNumber(), value); 888 default: 889 return false; 890 } 891 } 892 893 bool Literal::AsArrayIndex(uint32_t* value) const { 894 return ToUint32(value) && *value != kMaxUInt32; 895 } 896 897 Handle<Object> Literal::BuildValue(Isolate* isolate) const { 898 switch (type()) { 899 case kSmi: 900 return handle(Smi::FromInt(smi_), isolate); 901 case kHeapNumber: 902 return isolate->factory()->NewNumber(number_, TENURED); 903 case kString: 904 return string_->string(); 905 case kSymbol: 906 return isolate->factory()->home_object_symbol(); 907 case kBoolean: 908 return isolate->factory()->ToBoolean(boolean_); 909 case kNull: 910 return isolate->factory()->null_value(); 911 case kUndefined: 912 return isolate->factory()->undefined_value(); 913 case kTheHole: 914 return isolate->factory()->the_hole_value(); 915 case kBigInt: 916 // This should never fail: the parser will never create a BigInt 917 // literal that cannot be allocated. 918 return BigIntLiteral(isolate, bigint_.c_str()).ToHandleChecked(); 919 } 920 UNREACHABLE(); 921 } 922 923 bool Literal::ToBooleanIsTrue() const { 924 switch (type()) { 925 case kSmi: 926 return smi_ != 0; 927 case kHeapNumber: 928 return DoubleToBoolean(number_); 929 case kString: 930 return !string_->IsEmpty(); 931 case kNull: 932 case kUndefined: 933 return false; 934 case kBoolean: 935 return boolean_; 936 case kBigInt: { 937 const char* bigint_str = bigint_.c_str(); 938 size_t length = strlen(bigint_str); 939 DCHECK_GT(length, 0); 940 if (length == 1 && bigint_str[0] == '0') return false; 941 // Skip over any radix prefix; BigInts with length > 1 only 942 // begin with zero if they include a radix. 943 for (size_t i = (bigint_str[0] == '0') ? 2 : 0; i < length; ++i) { 944 if (bigint_str[i] != '0') return true; 945 } 946 return false; 947 } 948 case kSymbol: 949 return true; 950 case kTheHole: 951 UNREACHABLE(); 952 } 953 UNREACHABLE(); 954 } 955 956 uint32_t Literal::Hash() { 957 return IsString() ? AsRawString()->Hash() 958 : ComputeLongHash(double_to_uint64(AsNumber())); 959 } 960 961 962 // static 963 bool Literal::Match(void* a, void* b) { 964 Literal* x = static_cast<Literal*>(a); 965 Literal* y = static_cast<Literal*>(b); 966 return (x->IsString() && y->IsString() && 967 x->AsRawString() == y->AsRawString()) || 968 (x->IsNumber() && y->IsNumber() && x->AsNumber() == y->AsNumber()); 969 } 970 971 Literal* AstNodeFactory::NewNumberLiteral(double number, int pos) { 972 int int_value; 973 if (DoubleToSmiInteger(number, &int_value)) { 974 return NewSmiLiteral(int_value, pos); 975 } 976 return new (zone_) Literal(number, pos); 977 } 978 979 const char* CallRuntime::debug_name() { 980 #ifdef DEBUG 981 return is_jsruntime() ? NameForNativeContextIntrinsicIndex(context_index_) 982 : function_->name; 983 #else 984 return is_jsruntime() ? "(context function)" : function_->name; 985 #endif // DEBUG 986 } 987 988 #define RETURN_LABELS(NodeType) \ 989 case k##NodeType: \ 990 return static_cast<const NodeType*>(this)->labels(); 991 992 ZonePtrList<const AstRawString>* BreakableStatement::labels() const { 993 switch (node_type()) { 994 BREAKABLE_NODE_LIST(RETURN_LABELS) 995 ITERATION_NODE_LIST(RETURN_LABELS) 996 default: 997 UNREACHABLE(); 998 } 999 } 1000 1001 #undef RETURN_LABELS 1002 1003 } // namespace internal 1004 } // namespace v8 1005