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 9 #include "src/ast/compile-time-value.h" 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.h" 18 #include "src/double.h" 19 #include "src/elements.h" 20 #include "src/objects-inl.h" 21 #include "src/objects/literal-objects.h" 22 #include "src/property-details.h" 23 #include "src/property.h" 24 #include "src/string-stream.h" 25 #include "src/type-info.h" 26 27 namespace v8 { 28 namespace internal { 29 30 // ---------------------------------------------------------------------------- 31 // Implementation of other node functionality. 32 33 #ifdef DEBUG 34 35 static const char* NameForNativeContextIntrinsicIndex(uint32_t idx) { 36 switch (idx) { 37 #define NATIVE_CONTEXT_FIELDS_IDX(NAME, Type, name) \ 38 case Context::NAME: \ 39 return #name; 40 41 NATIVE_CONTEXT_FIELDS(NATIVE_CONTEXT_FIELDS_IDX) 42 #undef NATIVE_CONTEXT_FIELDS_IDX 43 44 default: 45 break; 46 } 47 48 return "UnknownIntrinsicIndex"; 49 } 50 51 void AstNode::Print() { Print(Isolate::Current()); } 52 53 void AstNode::Print(Isolate* isolate) { 54 AstPrinter::PrintOut(isolate, this); 55 } 56 57 58 #endif // DEBUG 59 60 #define RETURN_NODE(Node) \ 61 case k##Node: \ 62 return static_cast<Node*>(this); 63 64 IterationStatement* AstNode::AsIterationStatement() { 65 switch (node_type()) { 66 ITERATION_NODE_LIST(RETURN_NODE); 67 default: 68 return nullptr; 69 } 70 } 71 72 BreakableStatement* AstNode::AsBreakableStatement() { 73 switch (node_type()) { 74 BREAKABLE_NODE_LIST(RETURN_NODE); 75 ITERATION_NODE_LIST(RETURN_NODE); 76 default: 77 return nullptr; 78 } 79 } 80 81 MaterializedLiteral* AstNode::AsMaterializedLiteral() { 82 switch (node_type()) { 83 LITERAL_NODE_LIST(RETURN_NODE); 84 default: 85 return nullptr; 86 } 87 } 88 89 #undef RETURN_NODE 90 91 bool Expression::IsSmiLiteral() const { 92 return IsLiteral() && AsLiteral()->raw_value()->IsSmi(); 93 } 94 95 bool Expression::IsNumberLiteral() const { 96 return IsLiteral() && AsLiteral()->raw_value()->IsNumber(); 97 } 98 99 bool Expression::IsStringLiteral() const { 100 return IsLiteral() && AsLiteral()->raw_value()->IsString(); 101 } 102 103 bool Expression::IsPropertyName() const { 104 return IsLiteral() && AsLiteral()->IsPropertyName(); 105 } 106 107 bool Expression::IsNullLiteral() const { 108 if (!IsLiteral()) return false; 109 return AsLiteral()->raw_value()->IsNull(); 110 } 111 112 bool Expression::IsUndefinedLiteral() const { 113 if (IsLiteral() && AsLiteral()->raw_value()->IsUndefined()) return true; 114 115 const VariableProxy* var_proxy = AsVariableProxy(); 116 if (var_proxy == nullptr) return false; 117 Variable* var = var_proxy->var(); 118 // The global identifier "undefined" is immutable. Everything 119 // else could be reassigned. 120 return var != NULL && var->IsUnallocated() && 121 var_proxy->raw_name()->IsOneByteEqualTo("undefined"); 122 } 123 124 bool Expression::ToBooleanIsTrue() const { 125 return IsLiteral() && AsLiteral()->ToBooleanIsTrue(); 126 } 127 128 bool Expression::ToBooleanIsFalse() const { 129 return IsLiteral() && AsLiteral()->ToBooleanIsFalse(); 130 } 131 132 bool Expression::IsValidReferenceExpression() const { 133 // We don't want expressions wrapped inside RewritableExpression to be 134 // considered as valid reference expressions, as they will be rewritten 135 // to something (most probably involving a do expression). 136 if (IsRewritableExpression()) return false; 137 return IsProperty() || 138 (IsVariableProxy() && AsVariableProxy()->IsValidReferenceExpression()); 139 } 140 141 bool Expression::IsValidReferenceExpressionOrThis() const { 142 return IsValidReferenceExpression() || 143 (IsVariableProxy() && AsVariableProxy()->is_this()); 144 } 145 146 bool Expression::IsAnonymousFunctionDefinition() const { 147 return (IsFunctionLiteral() && 148 AsFunctionLiteral()->IsAnonymousFunctionDefinition()) || 149 (IsDoExpression() && 150 AsDoExpression()->IsAnonymousFunctionDefinition()); 151 } 152 153 void Expression::MarkTail() { 154 if (IsConditional()) { 155 AsConditional()->MarkTail(); 156 } else if (IsCall()) { 157 AsCall()->MarkTail(); 158 } else if (IsBinaryOperation()) { 159 AsBinaryOperation()->MarkTail(); 160 } 161 } 162 163 bool DoExpression::IsAnonymousFunctionDefinition() const { 164 // This is specifically to allow DoExpressions to represent ClassLiterals. 165 return represented_function_ != nullptr && 166 represented_function_->raw_name()->length() == 0; 167 } 168 169 bool Statement::IsJump() const { 170 switch (node_type()) { 171 #define JUMP_NODE_LIST(V) \ 172 V(Block) \ 173 V(ExpressionStatement) \ 174 V(ContinueStatement) \ 175 V(BreakStatement) \ 176 V(ReturnStatement) \ 177 V(IfStatement) 178 #define GENERATE_CASE(Node) \ 179 case k##Node: \ 180 return static_cast<const Node*>(this)->IsJump(); 181 JUMP_NODE_LIST(GENERATE_CASE) 182 #undef GENERATE_CASE 183 #undef JUMP_NODE_LIST 184 default: 185 return false; 186 } 187 } 188 189 VariableProxy::VariableProxy(Variable* var, int start_position) 190 : Expression(start_position, kVariableProxy), 191 raw_name_(var->raw_name()), 192 next_unresolved_(nullptr) { 193 bit_field_ |= IsThisField::encode(var->is_this()) | 194 IsAssignedField::encode(false) | 195 IsResolvedField::encode(false) | 196 HoleCheckModeField::encode(HoleCheckMode::kElided); 197 BindTo(var); 198 } 199 200 VariableProxy::VariableProxy(const AstRawString* name, 201 VariableKind variable_kind, int start_position) 202 : Expression(start_position, kVariableProxy), 203 raw_name_(name), 204 next_unresolved_(nullptr) { 205 bit_field_ |= IsThisField::encode(variable_kind == THIS_VARIABLE) | 206 IsAssignedField::encode(false) | 207 IsResolvedField::encode(false) | 208 HoleCheckModeField::encode(HoleCheckMode::kElided); 209 } 210 211 VariableProxy::VariableProxy(const VariableProxy* copy_from) 212 : Expression(copy_from->position(), kVariableProxy), 213 next_unresolved_(nullptr) { 214 bit_field_ = copy_from->bit_field_; 215 DCHECK(!copy_from->is_resolved()); 216 raw_name_ = copy_from->raw_name_; 217 } 218 219 void VariableProxy::BindTo(Variable* var) { 220 DCHECK((is_this() && var->is_this()) || raw_name() == var->raw_name()); 221 set_var(var); 222 set_is_resolved(); 223 var->set_is_used(); 224 if (is_assigned()) var->set_maybe_assigned(); 225 } 226 227 void VariableProxy::AssignFeedbackSlots(FeedbackVectorSpec* spec, 228 TypeofMode typeof_mode, 229 FeedbackSlotCache* cache) { 230 if (UsesVariableFeedbackSlot()) { 231 // VariableProxies that point to the same Variable within a function can 232 // make their loads from the same IC slot. 233 if (var()->IsUnallocated() || var()->mode() == DYNAMIC_GLOBAL) { 234 FeedbackSlot slot = cache->Get(typeof_mode, var()); 235 if (!slot.IsInvalid()) { 236 variable_feedback_slot_ = slot; 237 return; 238 } 239 variable_feedback_slot_ = spec->AddLoadGlobalICSlot(typeof_mode); 240 cache->Put(typeof_mode, var(), variable_feedback_slot_); 241 } else { 242 variable_feedback_slot_ = spec->AddLoadICSlot(); 243 } 244 } 245 } 246 247 static void AssignVectorSlots(Expression* expr, FeedbackVectorSpec* spec, 248 LanguageMode language_mode, 249 FeedbackSlot* out_slot) { 250 Property* property = expr->AsProperty(); 251 LhsKind assign_type = Property::GetAssignType(property); 252 if ((assign_type == VARIABLE && 253 expr->AsVariableProxy()->var()->IsUnallocated()) || 254 assign_type == NAMED_PROPERTY || assign_type == KEYED_PROPERTY) { 255 // TODO(ishell): consider using ICSlotCache for variables here. 256 if (assign_type == KEYED_PROPERTY) { 257 *out_slot = spec->AddKeyedStoreICSlot(language_mode); 258 259 } else { 260 *out_slot = spec->AddStoreICSlot(language_mode); 261 } 262 } 263 } 264 265 void ForInStatement::AssignFeedbackSlots(FeedbackVectorSpec* spec, 266 LanguageMode language_mode, 267 FeedbackSlotCache* cache) { 268 AssignVectorSlots(each(), spec, language_mode, &each_slot_); 269 for_in_feedback_slot_ = spec->AddGeneralSlot(); 270 } 271 272 Assignment::Assignment(Token::Value op, Expression* target, Expression* value, 273 int pos) 274 : Expression(pos, kAssignment), 275 target_(target), 276 value_(value), 277 binary_operation_(NULL) { 278 bit_field_ |= IsUninitializedField::encode(false) | 279 KeyTypeField::encode(ELEMENT) | 280 StoreModeField::encode(STANDARD_STORE) | TokenField::encode(op); 281 } 282 283 void Assignment::AssignFeedbackSlots(FeedbackVectorSpec* spec, 284 LanguageMode language_mode, 285 FeedbackSlotCache* cache) { 286 AssignVectorSlots(target(), spec, language_mode, &slot_); 287 } 288 289 void CountOperation::AssignFeedbackSlots(FeedbackVectorSpec* spec, 290 LanguageMode language_mode, 291 FeedbackSlotCache* cache) { 292 AssignVectorSlots(expression(), spec, language_mode, &slot_); 293 // Assign a slot to collect feedback about binary operations. Used only in 294 // ignition. Fullcodegen uses AstId to record type feedback. 295 binary_operation_slot_ = spec->AddInterpreterBinaryOpICSlot(); 296 } 297 298 299 Token::Value Assignment::binary_op() const { 300 switch (op()) { 301 case Token::ASSIGN_BIT_OR: return Token::BIT_OR; 302 case Token::ASSIGN_BIT_XOR: return Token::BIT_XOR; 303 case Token::ASSIGN_BIT_AND: return Token::BIT_AND; 304 case Token::ASSIGN_SHL: return Token::SHL; 305 case Token::ASSIGN_SAR: return Token::SAR; 306 case Token::ASSIGN_SHR: return Token::SHR; 307 case Token::ASSIGN_ADD: return Token::ADD; 308 case Token::ASSIGN_SUB: return Token::SUB; 309 case Token::ASSIGN_MUL: return Token::MUL; 310 case Token::ASSIGN_DIV: return Token::DIV; 311 case Token::ASSIGN_MOD: return Token::MOD; 312 default: UNREACHABLE(); 313 } 314 return Token::ILLEGAL; 315 } 316 317 bool FunctionLiteral::ShouldEagerCompile() const { 318 return scope()->ShouldEagerCompile(); 319 } 320 321 void FunctionLiteral::SetShouldEagerCompile() { 322 scope()->set_should_eager_compile(); 323 } 324 325 bool FunctionLiteral::AllowsLazyCompilation() { 326 return scope()->AllowsLazyCompilation(); 327 } 328 329 330 int FunctionLiteral::start_position() const { 331 return scope()->start_position(); 332 } 333 334 335 int FunctionLiteral::end_position() const { 336 return scope()->end_position(); 337 } 338 339 340 LanguageMode FunctionLiteral::language_mode() const { 341 return scope()->language_mode(); 342 } 343 344 FunctionKind FunctionLiteral::kind() const { return scope()->function_kind(); } 345 346 bool FunctionLiteral::NeedsHomeObject(Expression* expr) { 347 if (expr == nullptr || !expr->IsFunctionLiteral()) return false; 348 DCHECK_NOT_NULL(expr->AsFunctionLiteral()->scope()); 349 return expr->AsFunctionLiteral()->scope()->NeedsHomeObject(); 350 } 351 352 ObjectLiteralProperty::ObjectLiteralProperty(Expression* key, Expression* value, 353 Kind kind, bool is_computed_name) 354 : LiteralProperty(key, value, is_computed_name), 355 kind_(kind), 356 emit_store_(true) {} 357 358 ObjectLiteralProperty::ObjectLiteralProperty(AstValueFactory* ast_value_factory, 359 Expression* key, Expression* value, 360 bool is_computed_name) 361 : LiteralProperty(key, value, is_computed_name), emit_store_(true) { 362 if (!is_computed_name && 363 key->AsLiteral()->raw_value()->EqualsString( 364 ast_value_factory->proto_string())) { 365 kind_ = PROTOTYPE; 366 } else if (value_->AsMaterializedLiteral() != NULL) { 367 kind_ = MATERIALIZED_LITERAL; 368 } else if (value_->IsLiteral()) { 369 kind_ = CONSTANT; 370 } else { 371 kind_ = COMPUTED; 372 } 373 } 374 375 FeedbackSlot LiteralProperty::GetStoreDataPropertySlot() const { 376 int offset = FunctionLiteral::NeedsHomeObject(value_) ? 1 : 0; 377 return GetSlot(offset); 378 } 379 380 void LiteralProperty::SetStoreDataPropertySlot(FeedbackSlot slot) { 381 int offset = FunctionLiteral::NeedsHomeObject(value_) ? 1 : 0; 382 return SetSlot(slot, offset); 383 } 384 385 bool LiteralProperty::NeedsSetFunctionName() const { 386 return is_computed_name_ && 387 (value_->IsAnonymousFunctionDefinition() || 388 (value_->IsFunctionLiteral() && 389 IsConciseMethod(value_->AsFunctionLiteral()->kind()))); 390 } 391 392 ClassLiteralProperty::ClassLiteralProperty(Expression* key, Expression* value, 393 Kind kind, bool is_static, 394 bool is_computed_name) 395 : LiteralProperty(key, value, is_computed_name), 396 kind_(kind), 397 is_static_(is_static) {} 398 399 void ClassLiteral::AssignFeedbackSlots(FeedbackVectorSpec* spec, 400 LanguageMode language_mode, 401 FeedbackSlotCache* cache) { 402 // This logic that computes the number of slots needed for vector store 403 // ICs must mirror BytecodeGenerator::VisitClassLiteral. 404 if (FunctionLiteral::NeedsHomeObject(constructor())) { 405 home_object_slot_ = spec->AddStoreICSlot(language_mode); 406 } 407 408 if (NeedsProxySlot()) { 409 proxy_slot_ = spec->AddStoreICSlot(language_mode); 410 } 411 412 for (int i = 0; i < properties()->length(); i++) { 413 ClassLiteral::Property* property = properties()->at(i); 414 Expression* value = property->value(); 415 if (FunctionLiteral::NeedsHomeObject(value)) { 416 property->SetSlot(spec->AddStoreICSlot(language_mode)); 417 } 418 property->SetStoreDataPropertySlot( 419 spec->AddStoreDataPropertyInLiteralICSlot()); 420 } 421 } 422 423 bool ObjectLiteral::Property::IsCompileTimeValue() const { 424 return kind_ == CONSTANT || 425 (kind_ == MATERIALIZED_LITERAL && 426 CompileTimeValue::IsCompileTimeValue(value_)); 427 } 428 429 430 void ObjectLiteral::Property::set_emit_store(bool emit_store) { 431 emit_store_ = emit_store; 432 } 433 434 bool ObjectLiteral::Property::emit_store() const { return emit_store_; } 435 436 void ObjectLiteral::AssignFeedbackSlots(FeedbackVectorSpec* spec, 437 LanguageMode language_mode, 438 FeedbackSlotCache* cache) { 439 MaterializedLiteral::AssignFeedbackSlots(spec, language_mode, cache); 440 441 // This logic that computes the number of slots needed for vector store 442 // ics must mirror FullCodeGenerator::VisitObjectLiteral. 443 int property_index = 0; 444 for (; property_index < properties()->length(); property_index++) { 445 ObjectLiteral::Property* property = properties()->at(property_index); 446 if (property->is_computed_name()) break; 447 if (property->IsCompileTimeValue()) continue; 448 449 Literal* key = property->key()->AsLiteral(); 450 Expression* value = property->value(); 451 switch (property->kind()) { 452 case ObjectLiteral::Property::SPREAD: 453 case ObjectLiteral::Property::CONSTANT: 454 UNREACHABLE(); 455 case ObjectLiteral::Property::MATERIALIZED_LITERAL: 456 // Fall through. 457 case ObjectLiteral::Property::COMPUTED: 458 // It is safe to use [[Put]] here because the boilerplate already 459 // contains computed properties with an uninitialized value. 460 if (key->IsStringLiteral()) { 461 if (property->emit_store()) { 462 property->SetSlot(spec->AddStoreOwnICSlot()); 463 if (FunctionLiteral::NeedsHomeObject(value)) { 464 property->SetSlot(spec->AddStoreICSlot(language_mode), 1); 465 } 466 } 467 break; 468 } 469 if (property->emit_store() && FunctionLiteral::NeedsHomeObject(value)) { 470 property->SetSlot(spec->AddStoreICSlot(language_mode)); 471 } 472 break; 473 case ObjectLiteral::Property::PROTOTYPE: 474 break; 475 case ObjectLiteral::Property::GETTER: 476 if (property->emit_store() && FunctionLiteral::NeedsHomeObject(value)) { 477 property->SetSlot(spec->AddStoreICSlot(language_mode)); 478 } 479 break; 480 case ObjectLiteral::Property::SETTER: 481 if (property->emit_store() && FunctionLiteral::NeedsHomeObject(value)) { 482 property->SetSlot(spec->AddStoreICSlot(language_mode)); 483 } 484 break; 485 } 486 } 487 488 for (; property_index < properties()->length(); property_index++) { 489 ObjectLiteral::Property* property = properties()->at(property_index); 490 491 Expression* value = property->value(); 492 if (property->kind() != ObjectLiteral::Property::PROTOTYPE) { 493 if (FunctionLiteral::NeedsHomeObject(value)) { 494 property->SetSlot(spec->AddStoreICSlot(language_mode)); 495 } 496 } 497 property->SetStoreDataPropertySlot( 498 spec->AddStoreDataPropertyInLiteralICSlot()); 499 } 500 } 501 502 503 void ObjectLiteral::CalculateEmitStore(Zone* zone) { 504 const auto GETTER = ObjectLiteral::Property::GETTER; 505 const auto SETTER = ObjectLiteral::Property::SETTER; 506 507 ZoneAllocationPolicy allocator(zone); 508 509 CustomMatcherZoneHashMap table( 510 Literal::Match, ZoneHashMap::kDefaultHashMapCapacity, allocator); 511 for (int i = properties()->length() - 1; i >= 0; i--) { 512 ObjectLiteral::Property* property = properties()->at(i); 513 if (property->is_computed_name()) continue; 514 if (property->kind() == ObjectLiteral::Property::PROTOTYPE) continue; 515 Literal* literal = property->key()->AsLiteral(); 516 DCHECK(!literal->IsNullLiteral()); 517 518 // If there is an existing entry do not emit a store unless the previous 519 // entry was also an accessor. 520 uint32_t hash = literal->Hash(); 521 ZoneHashMap::Entry* entry = table.LookupOrInsert(literal, hash, allocator); 522 if (entry->value != NULL) { 523 auto previous_kind = 524 static_cast<ObjectLiteral::Property*>(entry->value)->kind(); 525 if (!((property->kind() == GETTER && previous_kind == SETTER) || 526 (property->kind() == SETTER && previous_kind == GETTER))) { 527 property->set_emit_store(false); 528 } 529 } 530 entry->value = property; 531 } 532 } 533 534 535 bool ObjectLiteral::IsBoilerplateProperty(ObjectLiteral::Property* property) { 536 return property != NULL && 537 property->kind() != ObjectLiteral::Property::PROTOTYPE; 538 } 539 540 void ObjectLiteral::InitDepthAndFlags() { 541 if (depth_ > 0) return; 542 543 int position = 0; 544 // Accumulate the value in local variables and store it at the end. 545 bool is_simple = true; 546 int depth_acc = 1; 547 uint32_t max_element_index = 0; 548 uint32_t elements = 0; 549 for (int i = 0; i < properties()->length(); i++) { 550 ObjectLiteral::Property* property = properties()->at(i); 551 if (!IsBoilerplateProperty(property)) { 552 is_simple = false; 553 continue; 554 } 555 556 if (static_cast<uint32_t>(position) == boilerplate_properties_ * 2) { 557 DCHECK(property->is_computed_name()); 558 is_simple = false; 559 break; 560 } 561 DCHECK(!property->is_computed_name()); 562 563 MaterializedLiteral* m_literal = property->value()->AsMaterializedLiteral(); 564 if (m_literal != NULL) { 565 m_literal->InitDepthAndFlags(); 566 if (m_literal->depth() >= depth_acc) depth_acc = m_literal->depth() + 1; 567 } 568 569 const AstValue* key = property->key()->AsLiteral()->raw_value(); 570 Expression* value = property->value(); 571 572 bool is_compile_time_value = CompileTimeValue::IsCompileTimeValue(value); 573 574 // Ensure objects that may, at any point in time, contain fields with double 575 // representation are always treated as nested objects. This is true for 576 // computed fields, and smi and double literals. 577 // TODO(verwaest): Remove once we can store them inline. 578 if (FLAG_track_double_fields && 579 (value->IsNumberLiteral() || !is_compile_time_value)) { 580 bit_field_ = MayStoreDoublesField::update(bit_field_, true); 581 } 582 583 is_simple = is_simple && is_compile_time_value; 584 585 // Keep track of the number of elements in the object literal and 586 // the largest element index. If the largest element index is 587 // much larger than the number of elements, creating an object 588 // literal with fast elements will be a waste of space. 589 uint32_t element_index = 0; 590 if (key->IsString() && key->AsString()->AsArrayIndex(&element_index)) { 591 max_element_index = Max(element_index, max_element_index); 592 elements++; 593 } else if (key->ToUint32(&element_index) && element_index != kMaxUInt32) { 594 max_element_index = Max(element_index, max_element_index); 595 elements++; 596 } 597 598 // Increment the position for the key and the value. 599 position += 2; 600 } 601 602 bit_field_ = FastElementsField::update( 603 bit_field_, 604 (max_element_index <= 32) || ((2 * elements) >= max_element_index)); 605 bit_field_ = HasElementsField::update(bit_field_, elements > 0); 606 607 set_is_simple(is_simple); 608 set_depth(depth_acc); 609 } 610 611 void ObjectLiteral::BuildConstantProperties(Isolate* isolate) { 612 if (!constant_properties_.is_null()) return; 613 614 int index_keys = 0; 615 bool has_seen_proto = false; 616 for (int i = 0; i < properties()->length(); i++) { 617 ObjectLiteral::Property* property = properties()->at(i); 618 if (!IsBoilerplateProperty(property)) { 619 has_seen_proto = true; 620 continue; 621 } 622 if (property->is_computed_name()) { 623 continue; 624 } 625 626 Handle<Object> key = property->key()->AsLiteral()->value(); 627 628 uint32_t element_index = 0; 629 if (key->ToArrayIndex(&element_index) || 630 (key->IsString() && String::cast(*key)->AsArrayIndex(&element_index))) { 631 index_keys++; 632 } 633 } 634 635 Handle<BoilerplateDescription> constant_properties = 636 isolate->factory()->NewBoilerplateDescription(boilerplate_properties_, 637 properties()->length(), 638 index_keys, has_seen_proto); 639 640 int position = 0; 641 for (int i = 0; i < properties()->length(); i++) { 642 ObjectLiteral::Property* property = properties()->at(i); 643 if (!IsBoilerplateProperty(property)) { 644 continue; 645 } 646 647 if (static_cast<uint32_t>(position) == boilerplate_properties_ * 2) { 648 DCHECK(property->is_computed_name()); 649 break; 650 } 651 DCHECK(!property->is_computed_name()); 652 653 MaterializedLiteral* m_literal = property->value()->AsMaterializedLiteral(); 654 if (m_literal != NULL) { 655 m_literal->BuildConstants(isolate); 656 } 657 658 // Add CONSTANT and COMPUTED properties to boilerplate. Use undefined 659 // value for COMPUTED properties, the real value is filled in at 660 // runtime. The enumeration order is maintained. 661 Handle<Object> key = property->key()->AsLiteral()->value(); 662 Handle<Object> value = GetBoilerplateValue(property->value(), isolate); 663 664 uint32_t element_index = 0; 665 if (key->IsString() && String::cast(*key)->AsArrayIndex(&element_index)) { 666 key = isolate->factory()->NewNumberFromUint(element_index); 667 } else if (key->IsNumber() && !key->ToArrayIndex(&element_index)) { 668 key = isolate->factory()->NumberToString(key); 669 } 670 671 // Add name, value pair to the fixed array. 672 constant_properties->set(position++, *key); 673 constant_properties->set(position++, *value); 674 } 675 676 constant_properties_ = constant_properties; 677 } 678 679 bool ObjectLiteral::IsFastCloningSupported() const { 680 // The FastCloneShallowObject builtin doesn't copy elements, and object 681 // literals don't support copy-on-write (COW) elements for now. 682 // TODO(mvstanton): make object literals support COW elements. 683 return fast_elements() && has_shallow_properties() && 684 properties_count() <= ConstructorBuiltinsAssembler:: 685 kMaximumClonedShallowObjectProperties; 686 } 687 688 ElementsKind ArrayLiteral::constant_elements_kind() const { 689 return static_cast<ElementsKind>(constant_elements()->elements_kind()); 690 } 691 692 void ArrayLiteral::InitDepthAndFlags() { 693 DCHECK_LT(first_spread_index_, 0); 694 695 if (depth_ > 0) return; 696 697 int constants_length = values()->length(); 698 699 // Fill in the literals. 700 bool is_simple = true; 701 int depth_acc = 1; 702 int array_index = 0; 703 for (; array_index < constants_length; array_index++) { 704 Expression* element = values()->at(array_index); 705 DCHECK(!element->IsSpread()); 706 MaterializedLiteral* m_literal = element->AsMaterializedLiteral(); 707 if (m_literal != NULL) { 708 m_literal->InitDepthAndFlags(); 709 if (m_literal->depth() + 1 > depth_acc) { 710 depth_acc = m_literal->depth() + 1; 711 } 712 } 713 714 if (!CompileTimeValue::IsCompileTimeValue(element)) { 715 is_simple = false; 716 } 717 } 718 719 set_is_simple(is_simple); 720 set_depth(depth_acc); 721 } 722 723 void ArrayLiteral::BuildConstantElements(Isolate* isolate) { 724 DCHECK_LT(first_spread_index_, 0); 725 726 if (!constant_elements_.is_null()) return; 727 728 int constants_length = values()->length(); 729 ElementsKind kind = FIRST_FAST_ELEMENTS_KIND; 730 Handle<FixedArray> fixed_array = 731 isolate->factory()->NewFixedArrayWithHoles(constants_length); 732 733 // Fill in the literals. 734 bool is_holey = false; 735 int array_index = 0; 736 for (; array_index < constants_length; array_index++) { 737 Expression* element = values()->at(array_index); 738 DCHECK(!element->IsSpread()); 739 MaterializedLiteral* m_literal = element->AsMaterializedLiteral(); 740 if (m_literal != NULL) { 741 m_literal->BuildConstants(isolate); 742 } 743 744 // New handle scope here, needs to be after BuildContants(). 745 HandleScope scope(isolate); 746 Handle<Object> boilerplate_value = GetBoilerplateValue(element, isolate); 747 if (boilerplate_value->IsTheHole(isolate)) { 748 is_holey = true; 749 continue; 750 } 751 752 if (boilerplate_value->IsUninitialized(isolate)) { 753 boilerplate_value = handle(Smi::kZero, isolate); 754 } 755 756 kind = GetMoreGeneralElementsKind(kind, 757 boilerplate_value->OptimalElementsKind()); 758 fixed_array->set(array_index, *boilerplate_value); 759 } 760 761 if (is_holey) kind = GetHoleyElementsKind(kind); 762 763 // Simple and shallow arrays can be lazily copied, we transform the 764 // elements array to a copy-on-write array. 765 if (is_simple() && depth() == 1 && array_index > 0 && 766 IsFastSmiOrObjectElementsKind(kind)) { 767 fixed_array->set_map(isolate->heap()->fixed_cow_array_map()); 768 } 769 770 Handle<FixedArrayBase> elements = fixed_array; 771 if (IsFastDoubleElementsKind(kind)) { 772 ElementsAccessor* accessor = ElementsAccessor::ForKind(kind); 773 elements = isolate->factory()->NewFixedDoubleArray(constants_length); 774 // We are copying from non-fast-double to fast-double. 775 ElementsKind from_kind = TERMINAL_FAST_ELEMENTS_KIND; 776 accessor->CopyElements(fixed_array, from_kind, elements, constants_length); 777 } 778 779 // Remember both the literal's constant values as well as the ElementsKind. 780 Handle<ConstantElementsPair> literals = 781 isolate->factory()->NewConstantElementsPair(kind, elements); 782 783 constant_elements_ = literals; 784 } 785 786 bool ArrayLiteral::IsFastCloningSupported() const { 787 return depth() <= 1 && 788 values()->length() <= 789 ConstructorBuiltinsAssembler::kMaximumClonedShallowArrayElements; 790 } 791 792 void ArrayLiteral::RewindSpreads() { 793 values_->Rewind(first_spread_index_); 794 first_spread_index_ = -1; 795 } 796 797 void ArrayLiteral::AssignFeedbackSlots(FeedbackVectorSpec* spec, 798 LanguageMode language_mode, 799 FeedbackSlotCache* cache) { 800 MaterializedLiteral::AssignFeedbackSlots(spec, language_mode, cache); 801 802 // This logic that computes the number of slots needed for vector store 803 // ics must mirror FullCodeGenerator::VisitArrayLiteral. 804 for (int array_index = 0; array_index < values()->length(); array_index++) { 805 Expression* subexpr = values()->at(array_index); 806 DCHECK(!subexpr->IsSpread()); 807 if (CompileTimeValue::IsCompileTimeValue(subexpr)) continue; 808 809 // We'll reuse the same literal slot for all of the non-constant 810 // subexpressions that use a keyed store IC. 811 literal_slot_ = spec->AddKeyedStoreICSlot(language_mode); 812 return; 813 } 814 } 815 816 817 Handle<Object> MaterializedLiteral::GetBoilerplateValue(Expression* expression, 818 Isolate* isolate) { 819 if (expression->IsLiteral()) { 820 return expression->AsLiteral()->value(); 821 } 822 if (CompileTimeValue::IsCompileTimeValue(expression)) { 823 return CompileTimeValue::GetValue(isolate, expression); 824 } 825 return isolate->factory()->uninitialized_value(); 826 } 827 828 void MaterializedLiteral::InitDepthAndFlags() { 829 if (IsArrayLiteral()) { 830 return AsArrayLiteral()->InitDepthAndFlags(); 831 } 832 if (IsObjectLiteral()) { 833 return AsObjectLiteral()->InitDepthAndFlags(); 834 } 835 DCHECK(IsRegExpLiteral()); 836 DCHECK_LE(1, depth()); // Depth should be initialized. 837 } 838 839 void MaterializedLiteral::BuildConstants(Isolate* isolate) { 840 if (IsArrayLiteral()) { 841 return AsArrayLiteral()->BuildConstantElements(isolate); 842 } 843 if (IsObjectLiteral()) { 844 return AsObjectLiteral()->BuildConstantProperties(isolate); 845 } 846 DCHECK(IsRegExpLiteral()); 847 } 848 849 850 void UnaryOperation::RecordToBooleanTypeFeedback(TypeFeedbackOracle* oracle) { 851 // TODO(olivf) If this Operation is used in a test context, then the 852 // expression has a ToBoolean stub and we want to collect the type 853 // information. However the GraphBuilder expects it to be on the instruction 854 // corresponding to the TestContext, therefore we have to store it here and 855 // not on the operand. 856 set_to_boolean_types(oracle->ToBooleanTypes(expression()->test_id())); 857 } 858 859 860 void BinaryOperation::RecordToBooleanTypeFeedback(TypeFeedbackOracle* oracle) { 861 // TODO(olivf) If this Operation is used in a test context, then the right 862 // hand side has a ToBoolean stub and we want to collect the type information. 863 // However the GraphBuilder expects it to be on the instruction corresponding 864 // to the TestContext, therefore we have to store it here and not on the 865 // right hand operand. 866 set_to_boolean_types(oracle->ToBooleanTypes(right()->test_id())); 867 } 868 869 void BinaryOperation::AssignFeedbackSlots(FeedbackVectorSpec* spec, 870 LanguageMode language_mode, 871 FeedbackSlotCache* cache) { 872 // Feedback vector slot is only used by interpreter for binary operations. 873 // Full-codegen uses AstId to record type feedback. 874 switch (op()) { 875 // Comma, logical_or and logical_and do not collect type feedback. 876 case Token::COMMA: 877 case Token::AND: 878 case Token::OR: 879 return; 880 default: 881 feedback_slot_ = spec->AddInterpreterBinaryOpICSlot(); 882 return; 883 } 884 } 885 886 static bool IsTypeof(Expression* expr) { 887 UnaryOperation* maybe_unary = expr->AsUnaryOperation(); 888 return maybe_unary != NULL && maybe_unary->op() == Token::TYPEOF; 889 } 890 891 void CompareOperation::AssignFeedbackSlots(FeedbackVectorSpec* spec, 892 LanguageMode language_mode, 893 FeedbackSlotCache* cache_) { 894 // Feedback vector slot is only used by interpreter for binary operations. 895 // Full-codegen uses AstId to record type feedback. 896 switch (op()) { 897 // instanceof and in do not collect type feedback. 898 case Token::INSTANCEOF: 899 case Token::IN: 900 return; 901 default: 902 feedback_slot_ = spec->AddInterpreterCompareICSlot(); 903 } 904 } 905 906 // Check for the pattern: typeof <expression> equals <string literal>. 907 static bool MatchLiteralCompareTypeof(Expression* left, 908 Token::Value op, 909 Expression* right, 910 Expression** expr, 911 Handle<String>* check) { 912 if (IsTypeof(left) && right->IsStringLiteral() && Token::IsEqualityOp(op)) { 913 *expr = left->AsUnaryOperation()->expression(); 914 *check = Handle<String>::cast(right->AsLiteral()->value()); 915 return true; 916 } 917 return false; 918 } 919 920 921 bool CompareOperation::IsLiteralCompareTypeof(Expression** expr, 922 Handle<String>* check) { 923 return MatchLiteralCompareTypeof(left_, op(), right_, expr, check) || 924 MatchLiteralCompareTypeof(right_, op(), left_, expr, check); 925 } 926 927 928 static bool IsVoidOfLiteral(Expression* expr) { 929 UnaryOperation* maybe_unary = expr->AsUnaryOperation(); 930 return maybe_unary != NULL && 931 maybe_unary->op() == Token::VOID && 932 maybe_unary->expression()->IsLiteral(); 933 } 934 935 936 // Check for the pattern: void <literal> equals <expression> or 937 // undefined equals <expression> 938 static bool MatchLiteralCompareUndefined(Expression* left, 939 Token::Value op, 940 Expression* right, 941 Expression** expr) { 942 if (IsVoidOfLiteral(left) && Token::IsEqualityOp(op)) { 943 *expr = right; 944 return true; 945 } 946 if (left->IsUndefinedLiteral() && Token::IsEqualityOp(op)) { 947 *expr = right; 948 return true; 949 } 950 return false; 951 } 952 953 bool CompareOperation::IsLiteralCompareUndefined(Expression** expr) { 954 return MatchLiteralCompareUndefined(left_, op(), right_, expr) || 955 MatchLiteralCompareUndefined(right_, op(), left_, expr); 956 } 957 958 959 // Check for the pattern: null equals <expression> 960 static bool MatchLiteralCompareNull(Expression* left, 961 Token::Value op, 962 Expression* right, 963 Expression** expr) { 964 if (left->IsNullLiteral() && Token::IsEqualityOp(op)) { 965 *expr = right; 966 return true; 967 } 968 return false; 969 } 970 971 972 bool CompareOperation::IsLiteralCompareNull(Expression** expr) { 973 return MatchLiteralCompareNull(left_, op(), right_, expr) || 974 MatchLiteralCompareNull(right_, op(), left_, expr); 975 } 976 977 978 // ---------------------------------------------------------------------------- 979 // Recording of type feedback 980 981 // TODO(rossberg): all RecordTypeFeedback functions should disappear 982 // once we use the common type field in the AST consistently. 983 984 void Expression::RecordToBooleanTypeFeedback(TypeFeedbackOracle* oracle) { 985 if (IsUnaryOperation()) { 986 AsUnaryOperation()->RecordToBooleanTypeFeedback(oracle); 987 } else if (IsBinaryOperation()) { 988 AsBinaryOperation()->RecordToBooleanTypeFeedback(oracle); 989 } else { 990 set_to_boolean_types(oracle->ToBooleanTypes(test_id())); 991 } 992 } 993 994 SmallMapList* Expression::GetReceiverTypes() { 995 switch (node_type()) { 996 #define NODE_LIST(V) \ 997 PROPERTY_NODE_LIST(V) \ 998 V(Call) 999 #define GENERATE_CASE(Node) \ 1000 case k##Node: \ 1001 return static_cast<Node*>(this)->GetReceiverTypes(); 1002 NODE_LIST(GENERATE_CASE) 1003 #undef NODE_LIST 1004 #undef GENERATE_CASE 1005 default: 1006 UNREACHABLE(); 1007 return nullptr; 1008 } 1009 } 1010 1011 KeyedAccessStoreMode Expression::GetStoreMode() const { 1012 switch (node_type()) { 1013 #define GENERATE_CASE(Node) \ 1014 case k##Node: \ 1015 return static_cast<const Node*>(this)->GetStoreMode(); 1016 PROPERTY_NODE_LIST(GENERATE_CASE) 1017 #undef GENERATE_CASE 1018 default: 1019 UNREACHABLE(); 1020 return STANDARD_STORE; 1021 } 1022 } 1023 1024 IcCheckType Expression::GetKeyType() const { 1025 switch (node_type()) { 1026 #define GENERATE_CASE(Node) \ 1027 case k##Node: \ 1028 return static_cast<const Node*>(this)->GetKeyType(); 1029 PROPERTY_NODE_LIST(GENERATE_CASE) 1030 #undef GENERATE_CASE 1031 default: 1032 UNREACHABLE(); 1033 return PROPERTY; 1034 } 1035 } 1036 1037 bool Expression::IsMonomorphic() const { 1038 switch (node_type()) { 1039 #define GENERATE_CASE(Node) \ 1040 case k##Node: \ 1041 return static_cast<const Node*>(this)->IsMonomorphic(); 1042 PROPERTY_NODE_LIST(GENERATE_CASE) 1043 CALL_NODE_LIST(GENERATE_CASE) 1044 #undef GENERATE_CASE 1045 default: 1046 UNREACHABLE(); 1047 return false; 1048 } 1049 } 1050 1051 void Call::AssignFeedbackSlots(FeedbackVectorSpec* spec, 1052 LanguageMode language_mode, 1053 FeedbackSlotCache* cache) { 1054 ic_slot_ = spec->AddCallICSlot(); 1055 } 1056 1057 Call::CallType Call::GetCallType() const { 1058 VariableProxy* proxy = expression()->AsVariableProxy(); 1059 if (proxy != NULL) { 1060 if (proxy->var()->IsUnallocated()) { 1061 return GLOBAL_CALL; 1062 } else if (proxy->var()->IsLookupSlot()) { 1063 // Calls going through 'with' always use DYNAMIC rather than DYNAMIC_LOCAL 1064 // or DYNAMIC_GLOBAL. 1065 return proxy->var()->mode() == DYNAMIC ? WITH_CALL : OTHER_CALL; 1066 } 1067 } 1068 1069 if (expression()->IsSuperCallReference()) return SUPER_CALL; 1070 1071 Property* property = expression()->AsProperty(); 1072 if (property != nullptr) { 1073 bool is_super = property->IsSuperAccess(); 1074 if (property->key()->IsPropertyName()) { 1075 return is_super ? NAMED_SUPER_PROPERTY_CALL : NAMED_PROPERTY_CALL; 1076 } else { 1077 return is_super ? KEYED_SUPER_PROPERTY_CALL : KEYED_PROPERTY_CALL; 1078 } 1079 } 1080 1081 return OTHER_CALL; 1082 } 1083 1084 CaseClause::CaseClause(Expression* label, ZoneList<Statement*>* statements, 1085 int pos) 1086 : Expression(pos, kCaseClause), 1087 label_(label), 1088 statements_(statements), 1089 compare_type_(AstType::None()) {} 1090 1091 void CaseClause::AssignFeedbackSlots(FeedbackVectorSpec* spec, 1092 LanguageMode language_mode, 1093 FeedbackSlotCache* cache) { 1094 feedback_slot_ = spec->AddInterpreterCompareICSlot(); 1095 } 1096 1097 uint32_t Literal::Hash() { 1098 return raw_value()->IsString() 1099 ? raw_value()->AsString()->hash() 1100 : ComputeLongHash(double_to_uint64(raw_value()->AsNumber())); 1101 } 1102 1103 1104 // static 1105 bool Literal::Match(void* literal1, void* literal2) { 1106 const AstValue* x = static_cast<Literal*>(literal1)->raw_value(); 1107 const AstValue* y = static_cast<Literal*>(literal2)->raw_value(); 1108 return (x->IsString() && y->IsString() && x->AsString() == y->AsString()) || 1109 (x->IsNumber() && y->IsNumber() && x->AsNumber() == y->AsNumber()); 1110 } 1111 1112 const char* CallRuntime::debug_name() { 1113 #ifdef DEBUG 1114 return is_jsruntime() ? NameForNativeContextIntrinsicIndex(context_index_) 1115 : function_->name; 1116 #else 1117 return is_jsruntime() ? "(context function)" : function_->name; 1118 #endif // DEBUG 1119 } 1120 1121 } // namespace internal 1122 } // namespace v8 1123