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