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 "src/ast/scopes.h" 9 #include "src/builtins.h" 10 #include "src/code-stubs.h" 11 #include "src/contexts.h" 12 #include "src/conversions.h" 13 #include "src/hashmap.h" 14 #include "src/parsing/parser.h" 15 #include "src/property.h" 16 #include "src/property-details.h" 17 #include "src/string-stream.h" 18 #include "src/type-info.h" 19 20 namespace v8 { 21 namespace internal { 22 23 // ---------------------------------------------------------------------------- 24 // All the Accept member functions for each syntax tree node type. 25 26 #define DECL_ACCEPT(type) \ 27 void type::Accept(AstVisitor* v) { v->Visit##type(this); } 28 AST_NODE_LIST(DECL_ACCEPT) 29 #undef DECL_ACCEPT 30 31 32 // ---------------------------------------------------------------------------- 33 // Implementation of other node functionality. 34 35 36 bool Expression::IsSmiLiteral() const { 37 return IsLiteral() && AsLiteral()->value()->IsSmi(); 38 } 39 40 41 bool Expression::IsStringLiteral() const { 42 return IsLiteral() && AsLiteral()->value()->IsString(); 43 } 44 45 46 bool Expression::IsNullLiteral() const { 47 return IsLiteral() && AsLiteral()->value()->IsNull(); 48 } 49 50 51 bool Expression::IsUndefinedLiteral(Isolate* isolate) const { 52 const VariableProxy* var_proxy = AsVariableProxy(); 53 if (var_proxy == NULL) return false; 54 Variable* var = var_proxy->var(); 55 // The global identifier "undefined" is immutable. Everything 56 // else could be reassigned. 57 return var != NULL && var->IsUnallocatedOrGlobalSlot() && 58 var_proxy->raw_name()->IsOneByteEqualTo("undefined"); 59 } 60 61 62 bool Expression::IsValidReferenceExpressionOrThis() const { 63 return IsValidReferenceExpression() || 64 (IsVariableProxy() && AsVariableProxy()->is_this()); 65 } 66 67 68 VariableProxy::VariableProxy(Zone* zone, Variable* var, int start_position, 69 int end_position) 70 : Expression(zone, start_position), 71 bit_field_(IsThisField::encode(var->is_this()) | 72 IsAssignedField::encode(false) | 73 IsResolvedField::encode(false)), 74 raw_name_(var->raw_name()), 75 end_position_(end_position) { 76 BindTo(var); 77 } 78 79 80 VariableProxy::VariableProxy(Zone* zone, const AstRawString* name, 81 Variable::Kind variable_kind, int start_position, 82 int end_position) 83 : Expression(zone, start_position), 84 bit_field_(IsThisField::encode(variable_kind == Variable::THIS) | 85 IsAssignedField::encode(false) | 86 IsResolvedField::encode(false)), 87 raw_name_(name), 88 end_position_(end_position) {} 89 90 91 void VariableProxy::BindTo(Variable* var) { 92 DCHECK((is_this() && var->is_this()) || raw_name() == var->raw_name()); 93 set_var(var); 94 set_is_resolved(); 95 var->set_is_used(); 96 } 97 98 99 void VariableProxy::AssignFeedbackVectorSlots(Isolate* isolate, 100 FeedbackVectorSpec* spec, 101 FeedbackVectorSlotCache* cache) { 102 if (UsesVariableFeedbackSlot()) { 103 // VariableProxies that point to the same Variable within a function can 104 // make their loads from the same IC slot. 105 if (var()->IsUnallocated()) { 106 ZoneHashMap::Entry* entry = cache->Get(var()); 107 if (entry != NULL) { 108 variable_feedback_slot_ = FeedbackVectorSlot( 109 static_cast<int>(reinterpret_cast<intptr_t>(entry->value))); 110 return; 111 } 112 } 113 variable_feedback_slot_ = spec->AddLoadICSlot(); 114 if (var()->IsUnallocated()) { 115 cache->Put(var(), variable_feedback_slot_); 116 } 117 } 118 } 119 120 121 static void AssignVectorSlots(Expression* expr, FeedbackVectorSpec* spec, 122 FeedbackVectorSlot* out_slot) { 123 Property* property = expr->AsProperty(); 124 LhsKind assign_type = Property::GetAssignType(property); 125 if ((assign_type == VARIABLE && 126 expr->AsVariableProxy()->var()->IsUnallocated()) || 127 assign_type == NAMED_PROPERTY || assign_type == KEYED_PROPERTY) { 128 // TODO(ishell): consider using ICSlotCache for variables here. 129 FeedbackVectorSlotKind kind = assign_type == KEYED_PROPERTY 130 ? FeedbackVectorSlotKind::KEYED_STORE_IC 131 : FeedbackVectorSlotKind::STORE_IC; 132 *out_slot = spec->AddSlot(kind); 133 } 134 } 135 136 137 void ForEachStatement::AssignFeedbackVectorSlots( 138 Isolate* isolate, FeedbackVectorSpec* spec, 139 FeedbackVectorSlotCache* cache) { 140 // TODO(adamk): for-of statements do not make use of this feedback slot. 141 // The each_slot_ should be specific to ForInStatement, and this work moved 142 // there. 143 if (IsForOfStatement()) return; 144 AssignVectorSlots(each(), spec, &each_slot_); 145 } 146 147 148 Assignment::Assignment(Zone* zone, Token::Value op, Expression* target, 149 Expression* value, int pos) 150 : Expression(zone, pos), 151 bit_field_( 152 IsUninitializedField::encode(false) | KeyTypeField::encode(ELEMENT) | 153 StoreModeField::encode(STANDARD_STORE) | TokenField::encode(op)), 154 target_(target), 155 value_(value), 156 binary_operation_(NULL) {} 157 158 159 void Assignment::AssignFeedbackVectorSlots(Isolate* isolate, 160 FeedbackVectorSpec* spec, 161 FeedbackVectorSlotCache* cache) { 162 AssignVectorSlots(target(), spec, &slot_); 163 } 164 165 166 void CountOperation::AssignFeedbackVectorSlots(Isolate* isolate, 167 FeedbackVectorSpec* spec, 168 FeedbackVectorSlotCache* cache) { 169 AssignVectorSlots(expression(), spec, &slot_); 170 } 171 172 173 Token::Value Assignment::binary_op() const { 174 switch (op()) { 175 case Token::ASSIGN_BIT_OR: return Token::BIT_OR; 176 case Token::ASSIGN_BIT_XOR: return Token::BIT_XOR; 177 case Token::ASSIGN_BIT_AND: return Token::BIT_AND; 178 case Token::ASSIGN_SHL: return Token::SHL; 179 case Token::ASSIGN_SAR: return Token::SAR; 180 case Token::ASSIGN_SHR: return Token::SHR; 181 case Token::ASSIGN_ADD: return Token::ADD; 182 case Token::ASSIGN_SUB: return Token::SUB; 183 case Token::ASSIGN_MUL: return Token::MUL; 184 case Token::ASSIGN_DIV: return Token::DIV; 185 case Token::ASSIGN_MOD: return Token::MOD; 186 default: UNREACHABLE(); 187 } 188 return Token::ILLEGAL; 189 } 190 191 192 bool FunctionLiteral::AllowsLazyCompilation() { 193 return scope()->AllowsLazyCompilation(); 194 } 195 196 197 bool FunctionLiteral::AllowsLazyCompilationWithoutContext() { 198 return scope()->AllowsLazyCompilationWithoutContext(); 199 } 200 201 202 int FunctionLiteral::start_position() const { 203 return scope()->start_position(); 204 } 205 206 207 int FunctionLiteral::end_position() const { 208 return scope()->end_position(); 209 } 210 211 212 LanguageMode FunctionLiteral::language_mode() const { 213 return scope()->language_mode(); 214 } 215 216 217 bool FunctionLiteral::NeedsHomeObject(Expression* expr) { 218 if (expr == nullptr || !expr->IsFunctionLiteral()) return false; 219 DCHECK_NOT_NULL(expr->AsFunctionLiteral()->scope()); 220 return expr->AsFunctionLiteral()->scope()->NeedsHomeObject(); 221 } 222 223 224 ObjectLiteralProperty::ObjectLiteralProperty(Expression* key, Expression* value, 225 Kind kind, bool is_static, 226 bool is_computed_name) 227 : key_(key), 228 value_(value), 229 kind_(kind), 230 emit_store_(true), 231 is_static_(is_static), 232 is_computed_name_(is_computed_name) {} 233 234 235 ObjectLiteralProperty::ObjectLiteralProperty(AstValueFactory* ast_value_factory, 236 Expression* key, Expression* value, 237 bool is_static, 238 bool is_computed_name) 239 : key_(key), 240 value_(value), 241 emit_store_(true), 242 is_static_(is_static), 243 is_computed_name_(is_computed_name) { 244 if (!is_computed_name && 245 key->AsLiteral()->raw_value()->EqualsString( 246 ast_value_factory->proto_string())) { 247 kind_ = PROTOTYPE; 248 } else if (value_->AsMaterializedLiteral() != NULL) { 249 kind_ = MATERIALIZED_LITERAL; 250 } else if (value_->IsLiteral()) { 251 kind_ = CONSTANT; 252 } else { 253 kind_ = COMPUTED; 254 } 255 } 256 257 258 void ClassLiteral::AssignFeedbackVectorSlots(Isolate* isolate, 259 FeedbackVectorSpec* spec, 260 FeedbackVectorSlotCache* cache) { 261 // This logic that computes the number of slots needed for vector store 262 // ICs must mirror FullCodeGenerator::VisitClassLiteral. 263 if (NeedsProxySlot()) { 264 slot_ = spec->AddStoreICSlot(); 265 } 266 267 for (int i = 0; i < properties()->length(); i++) { 268 ObjectLiteral::Property* property = properties()->at(i); 269 Expression* value = property->value(); 270 if (FunctionLiteral::NeedsHomeObject(value)) { 271 property->SetSlot(spec->AddStoreICSlot()); 272 } 273 } 274 } 275 276 277 bool ObjectLiteral::Property::IsCompileTimeValue() { 278 return kind_ == CONSTANT || 279 (kind_ == MATERIALIZED_LITERAL && 280 CompileTimeValue::IsCompileTimeValue(value_)); 281 } 282 283 284 void ObjectLiteral::Property::set_emit_store(bool emit_store) { 285 emit_store_ = emit_store; 286 } 287 288 289 bool ObjectLiteral::Property::emit_store() { 290 return emit_store_; 291 } 292 293 294 void ObjectLiteral::AssignFeedbackVectorSlots(Isolate* isolate, 295 FeedbackVectorSpec* spec, 296 FeedbackVectorSlotCache* cache) { 297 // This logic that computes the number of slots needed for vector store 298 // ics must mirror FullCodeGenerator::VisitObjectLiteral. 299 int property_index = 0; 300 for (; property_index < properties()->length(); property_index++) { 301 ObjectLiteral::Property* property = properties()->at(property_index); 302 if (property->is_computed_name()) break; 303 if (property->IsCompileTimeValue()) continue; 304 305 Literal* key = property->key()->AsLiteral(); 306 Expression* value = property->value(); 307 switch (property->kind()) { 308 case ObjectLiteral::Property::CONSTANT: 309 UNREACHABLE(); 310 case ObjectLiteral::Property::MATERIALIZED_LITERAL: 311 // Fall through. 312 case ObjectLiteral::Property::COMPUTED: 313 // It is safe to use [[Put]] here because the boilerplate already 314 // contains computed properties with an uninitialized value. 315 if (key->value()->IsInternalizedString()) { 316 if (property->emit_store()) { 317 property->SetSlot(spec->AddStoreICSlot()); 318 if (FunctionLiteral::NeedsHomeObject(value)) { 319 property->SetSlot(spec->AddStoreICSlot(), 1); 320 } 321 } 322 break; 323 } 324 if (property->emit_store() && FunctionLiteral::NeedsHomeObject(value)) { 325 property->SetSlot(spec->AddStoreICSlot()); 326 } 327 break; 328 case ObjectLiteral::Property::PROTOTYPE: 329 break; 330 case ObjectLiteral::Property::GETTER: 331 if (property->emit_store() && FunctionLiteral::NeedsHomeObject(value)) { 332 property->SetSlot(spec->AddStoreICSlot()); 333 } 334 break; 335 case ObjectLiteral::Property::SETTER: 336 if (property->emit_store() && FunctionLiteral::NeedsHomeObject(value)) { 337 property->SetSlot(spec->AddStoreICSlot()); 338 } 339 break; 340 } 341 } 342 343 for (; property_index < properties()->length(); property_index++) { 344 ObjectLiteral::Property* property = properties()->at(property_index); 345 346 Expression* value = property->value(); 347 if (property->kind() != ObjectLiteral::Property::PROTOTYPE) { 348 if (FunctionLiteral::NeedsHomeObject(value)) { 349 property->SetSlot(spec->AddStoreICSlot()); 350 } 351 } 352 } 353 } 354 355 356 void ObjectLiteral::CalculateEmitStore(Zone* zone) { 357 const auto GETTER = ObjectLiteral::Property::GETTER; 358 const auto SETTER = ObjectLiteral::Property::SETTER; 359 360 ZoneAllocationPolicy allocator(zone); 361 362 ZoneHashMap table(Literal::Match, ZoneHashMap::kDefaultHashMapCapacity, 363 allocator); 364 for (int i = properties()->length() - 1; i >= 0; i--) { 365 ObjectLiteral::Property* property = properties()->at(i); 366 if (property->is_computed_name()) continue; 367 if (property->kind() == ObjectLiteral::Property::PROTOTYPE) continue; 368 Literal* literal = property->key()->AsLiteral(); 369 DCHECK(!literal->value()->IsNull()); 370 371 // If there is an existing entry do not emit a store unless the previous 372 // entry was also an accessor. 373 uint32_t hash = literal->Hash(); 374 ZoneHashMap::Entry* entry = table.LookupOrInsert(literal, hash, allocator); 375 if (entry->value != NULL) { 376 auto previous_kind = 377 static_cast<ObjectLiteral::Property*>(entry->value)->kind(); 378 if (!((property->kind() == GETTER && previous_kind == SETTER) || 379 (property->kind() == SETTER && previous_kind == GETTER))) { 380 property->set_emit_store(false); 381 } 382 } 383 entry->value = property; 384 } 385 } 386 387 388 bool ObjectLiteral::IsBoilerplateProperty(ObjectLiteral::Property* property) { 389 return property != NULL && 390 property->kind() != ObjectLiteral::Property::PROTOTYPE; 391 } 392 393 394 void ObjectLiteral::BuildConstantProperties(Isolate* isolate) { 395 if (!constant_properties_.is_null()) return; 396 397 // Allocate a fixed array to hold all the constant properties. 398 Handle<FixedArray> constant_properties = isolate->factory()->NewFixedArray( 399 boilerplate_properties_ * 2, TENURED); 400 401 int position = 0; 402 // Accumulate the value in local variables and store it at the end. 403 bool is_simple = true; 404 int depth_acc = 1; 405 uint32_t max_element_index = 0; 406 uint32_t elements = 0; 407 for (int i = 0; i < properties()->length(); i++) { 408 ObjectLiteral::Property* property = properties()->at(i); 409 if (!IsBoilerplateProperty(property)) { 410 is_simple = false; 411 continue; 412 } 413 414 if (position == boilerplate_properties_ * 2) { 415 DCHECK(property->is_computed_name()); 416 is_simple = false; 417 break; 418 } 419 DCHECK(!property->is_computed_name()); 420 421 MaterializedLiteral* m_literal = property->value()->AsMaterializedLiteral(); 422 if (m_literal != NULL) { 423 m_literal->BuildConstants(isolate); 424 if (m_literal->depth() >= depth_acc) depth_acc = m_literal->depth() + 1; 425 } 426 427 // Add CONSTANT and COMPUTED properties to boilerplate. Use undefined 428 // value for COMPUTED properties, the real value is filled in at 429 // runtime. The enumeration order is maintained. 430 Handle<Object> key = property->key()->AsLiteral()->value(); 431 Handle<Object> value = GetBoilerplateValue(property->value(), isolate); 432 433 // Ensure objects that may, at any point in time, contain fields with double 434 // representation are always treated as nested objects. This is true for 435 // computed fields (value is undefined), and smi and double literals 436 // (value->IsNumber()). 437 // TODO(verwaest): Remove once we can store them inline. 438 if (FLAG_track_double_fields && 439 (value->IsNumber() || value->IsUninitialized())) { 440 may_store_doubles_ = true; 441 } 442 443 is_simple = is_simple && !value->IsUninitialized(); 444 445 // Keep track of the number of elements in the object literal and 446 // the largest element index. If the largest element index is 447 // much larger than the number of elements, creating an object 448 // literal with fast elements will be a waste of space. 449 uint32_t element_index = 0; 450 if (key->IsString() 451 && Handle<String>::cast(key)->AsArrayIndex(&element_index) 452 && element_index > max_element_index) { 453 max_element_index = element_index; 454 elements++; 455 } else if (key->IsSmi()) { 456 int key_value = Smi::cast(*key)->value(); 457 if (key_value > 0 458 && static_cast<uint32_t>(key_value) > max_element_index) { 459 max_element_index = key_value; 460 } 461 elements++; 462 } 463 464 // Add name, value pair to the fixed array. 465 constant_properties->set(position++, *key); 466 constant_properties->set(position++, *value); 467 } 468 469 constant_properties_ = constant_properties; 470 fast_elements_ = 471 (max_element_index <= 32) || ((2 * elements) >= max_element_index); 472 has_elements_ = elements > 0; 473 set_is_simple(is_simple); 474 set_depth(depth_acc); 475 } 476 477 478 void ArrayLiteral::BuildConstantElements(Isolate* isolate) { 479 if (!constant_elements_.is_null()) return; 480 481 int constants_length = 482 first_spread_index_ >= 0 ? first_spread_index_ : values()->length(); 483 484 // Allocate a fixed array to hold all the object literals. 485 Handle<JSArray> array = isolate->factory()->NewJSArray( 486 FAST_HOLEY_SMI_ELEMENTS, constants_length, constants_length, 487 Strength::WEAK, INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE); 488 489 // Fill in the literals. 490 bool is_simple = (first_spread_index_ < 0); 491 int depth_acc = 1; 492 bool is_holey = false; 493 int array_index = 0; 494 for (; array_index < constants_length; array_index++) { 495 Expression* element = values()->at(array_index); 496 DCHECK(!element->IsSpread()); 497 MaterializedLiteral* m_literal = element->AsMaterializedLiteral(); 498 if (m_literal != NULL) { 499 m_literal->BuildConstants(isolate); 500 if (m_literal->depth() + 1 > depth_acc) { 501 depth_acc = m_literal->depth() + 1; 502 } 503 } 504 505 // New handle scope here, needs to be after BuildContants(). 506 HandleScope scope(isolate); 507 Handle<Object> boilerplate_value = GetBoilerplateValue(element, isolate); 508 if (boilerplate_value->IsTheHole()) { 509 is_holey = true; 510 continue; 511 } 512 513 if (boilerplate_value->IsUninitialized()) { 514 boilerplate_value = handle(Smi::FromInt(0), isolate); 515 is_simple = false; 516 } 517 518 JSObject::AddDataElement(array, array_index, boilerplate_value, NONE) 519 .Assert(); 520 } 521 522 JSObject::ValidateElements(array); 523 Handle<FixedArrayBase> element_values(array->elements()); 524 525 // Simple and shallow arrays can be lazily copied, we transform the 526 // elements array to a copy-on-write array. 527 if (is_simple && depth_acc == 1 && array_index > 0 && 528 array->HasFastSmiOrObjectElements()) { 529 element_values->set_map(isolate->heap()->fixed_cow_array_map()); 530 } 531 532 // Remember both the literal's constant values as well as the ElementsKind 533 // in a 2-element FixedArray. 534 Handle<FixedArray> literals = isolate->factory()->NewFixedArray(2, TENURED); 535 536 ElementsKind kind = array->GetElementsKind(); 537 kind = is_holey ? GetHoleyElementsKind(kind) : GetPackedElementsKind(kind); 538 539 literals->set(0, Smi::FromInt(kind)); 540 literals->set(1, *element_values); 541 542 constant_elements_ = literals; 543 set_is_simple(is_simple); 544 set_depth(depth_acc); 545 } 546 547 548 void ArrayLiteral::AssignFeedbackVectorSlots(Isolate* isolate, 549 FeedbackVectorSpec* spec, 550 FeedbackVectorSlotCache* cache) { 551 // This logic that computes the number of slots needed for vector store 552 // ics must mirror FullCodeGenerator::VisitArrayLiteral. 553 int array_index = 0; 554 for (; array_index < values()->length(); array_index++) { 555 Expression* subexpr = values()->at(array_index); 556 if (subexpr->IsSpread()) break; 557 if (CompileTimeValue::IsCompileTimeValue(subexpr)) continue; 558 559 // We'll reuse the same literal slot for all of the non-constant 560 // subexpressions that use a keyed store IC. 561 literal_slot_ = spec->AddKeyedStoreICSlot(); 562 return; 563 } 564 } 565 566 567 Handle<Object> MaterializedLiteral::GetBoilerplateValue(Expression* expression, 568 Isolate* isolate) { 569 if (expression->IsLiteral()) { 570 return expression->AsLiteral()->value(); 571 } 572 if (CompileTimeValue::IsCompileTimeValue(expression)) { 573 return CompileTimeValue::GetValue(isolate, expression); 574 } 575 return isolate->factory()->uninitialized_value(); 576 } 577 578 579 void MaterializedLiteral::BuildConstants(Isolate* isolate) { 580 if (IsArrayLiteral()) { 581 return AsArrayLiteral()->BuildConstantElements(isolate); 582 } 583 if (IsObjectLiteral()) { 584 return AsObjectLiteral()->BuildConstantProperties(isolate); 585 } 586 DCHECK(IsRegExpLiteral()); 587 DCHECK(depth() >= 1); // Depth should be initialized. 588 } 589 590 591 void UnaryOperation::RecordToBooleanTypeFeedback(TypeFeedbackOracle* oracle) { 592 // TODO(olivf) If this Operation is used in a test context, then the 593 // expression has a ToBoolean stub and we want to collect the type 594 // information. However the GraphBuilder expects it to be on the instruction 595 // corresponding to the TestContext, therefore we have to store it here and 596 // not on the operand. 597 set_to_boolean_types(oracle->ToBooleanTypes(expression()->test_id())); 598 } 599 600 601 void BinaryOperation::RecordToBooleanTypeFeedback(TypeFeedbackOracle* oracle) { 602 // TODO(olivf) If this Operation is used in a test context, then the right 603 // hand side has a ToBoolean stub and we want to collect the type information. 604 // However the GraphBuilder expects it to be on the instruction corresponding 605 // to the TestContext, therefore we have to store it here and not on the 606 // right hand operand. 607 set_to_boolean_types(oracle->ToBooleanTypes(right()->test_id())); 608 } 609 610 611 static bool IsTypeof(Expression* expr) { 612 UnaryOperation* maybe_unary = expr->AsUnaryOperation(); 613 return maybe_unary != NULL && maybe_unary->op() == Token::TYPEOF; 614 } 615 616 617 // Check for the pattern: typeof <expression> equals <string literal>. 618 static bool MatchLiteralCompareTypeof(Expression* left, 619 Token::Value op, 620 Expression* right, 621 Expression** expr, 622 Handle<String>* check) { 623 if (IsTypeof(left) && right->IsStringLiteral() && Token::IsEqualityOp(op)) { 624 *expr = left->AsUnaryOperation()->expression(); 625 *check = Handle<String>::cast(right->AsLiteral()->value()); 626 return true; 627 } 628 return false; 629 } 630 631 632 bool CompareOperation::IsLiteralCompareTypeof(Expression** expr, 633 Handle<String>* check) { 634 return MatchLiteralCompareTypeof(left_, op_, right_, expr, check) || 635 MatchLiteralCompareTypeof(right_, op_, left_, expr, check); 636 } 637 638 639 static bool IsVoidOfLiteral(Expression* expr) { 640 UnaryOperation* maybe_unary = expr->AsUnaryOperation(); 641 return maybe_unary != NULL && 642 maybe_unary->op() == Token::VOID && 643 maybe_unary->expression()->IsLiteral(); 644 } 645 646 647 // Check for the pattern: void <literal> equals <expression> or 648 // undefined equals <expression> 649 static bool MatchLiteralCompareUndefined(Expression* left, 650 Token::Value op, 651 Expression* right, 652 Expression** expr, 653 Isolate* isolate) { 654 if (IsVoidOfLiteral(left) && Token::IsEqualityOp(op)) { 655 *expr = right; 656 return true; 657 } 658 if (left->IsUndefinedLiteral(isolate) && Token::IsEqualityOp(op)) { 659 *expr = right; 660 return true; 661 } 662 return false; 663 } 664 665 666 bool CompareOperation::IsLiteralCompareUndefined( 667 Expression** expr, Isolate* isolate) { 668 return MatchLiteralCompareUndefined(left_, op_, right_, expr, isolate) || 669 MatchLiteralCompareUndefined(right_, op_, left_, expr, isolate); 670 } 671 672 673 // Check for the pattern: null equals <expression> 674 static bool MatchLiteralCompareNull(Expression* left, 675 Token::Value op, 676 Expression* right, 677 Expression** expr) { 678 if (left->IsNullLiteral() && Token::IsEqualityOp(op)) { 679 *expr = right; 680 return true; 681 } 682 return false; 683 } 684 685 686 bool CompareOperation::IsLiteralCompareNull(Expression** expr) { 687 return MatchLiteralCompareNull(left_, op_, right_, expr) || 688 MatchLiteralCompareNull(right_, op_, left_, expr); 689 } 690 691 692 // ---------------------------------------------------------------------------- 693 // Inlining support 694 695 bool Declaration::IsInlineable() const { 696 return proxy()->var()->IsStackAllocated(); 697 } 698 699 bool FunctionDeclaration::IsInlineable() const { 700 return false; 701 } 702 703 704 // ---------------------------------------------------------------------------- 705 // Recording of type feedback 706 707 // TODO(rossberg): all RecordTypeFeedback functions should disappear 708 // once we use the common type field in the AST consistently. 709 710 void Expression::RecordToBooleanTypeFeedback(TypeFeedbackOracle* oracle) { 711 set_to_boolean_types(oracle->ToBooleanTypes(test_id())); 712 } 713 714 715 bool Call::IsUsingCallFeedbackICSlot(Isolate* isolate) const { 716 CallType call_type = GetCallType(isolate); 717 if (call_type == POSSIBLY_EVAL_CALL) { 718 return false; 719 } 720 return true; 721 } 722 723 724 bool Call::IsUsingCallFeedbackSlot(Isolate* isolate) const { 725 // SuperConstructorCall uses a CallConstructStub, which wants 726 // a Slot, in addition to any IC slots requested elsewhere. 727 return GetCallType(isolate) == SUPER_CALL; 728 } 729 730 731 void Call::AssignFeedbackVectorSlots(Isolate* isolate, FeedbackVectorSpec* spec, 732 FeedbackVectorSlotCache* cache) { 733 if (IsUsingCallFeedbackICSlot(isolate)) { 734 ic_slot_ = spec->AddCallICSlot(); 735 } 736 if (IsUsingCallFeedbackSlot(isolate)) { 737 stub_slot_ = spec->AddGeneralSlot(); 738 } 739 } 740 741 742 Call::CallType Call::GetCallType(Isolate* isolate) const { 743 VariableProxy* proxy = expression()->AsVariableProxy(); 744 if (proxy != NULL) { 745 if (proxy->var()->is_possibly_eval(isolate)) { 746 return POSSIBLY_EVAL_CALL; 747 } else if (proxy->var()->IsUnallocatedOrGlobalSlot()) { 748 return GLOBAL_CALL; 749 } else if (proxy->var()->IsLookupSlot()) { 750 return LOOKUP_SLOT_CALL; 751 } 752 } 753 754 if (expression()->IsSuperCallReference()) return SUPER_CALL; 755 756 Property* property = expression()->AsProperty(); 757 if (property != nullptr) { 758 bool is_super = property->IsSuperAccess(); 759 if (property->key()->IsPropertyName()) { 760 return is_super ? NAMED_SUPER_PROPERTY_CALL : NAMED_PROPERTY_CALL; 761 } else { 762 return is_super ? KEYED_SUPER_PROPERTY_CALL : KEYED_PROPERTY_CALL; 763 } 764 } 765 766 return OTHER_CALL; 767 } 768 769 770 // ---------------------------------------------------------------------------- 771 // Implementation of AstVisitor 772 773 void AstVisitor::VisitDeclarations(ZoneList<Declaration*>* declarations) { 774 for (int i = 0; i < declarations->length(); i++) { 775 Visit(declarations->at(i)); 776 } 777 } 778 779 780 void AstVisitor::VisitStatements(ZoneList<Statement*>* statements) { 781 for (int i = 0; i < statements->length(); i++) { 782 Statement* stmt = statements->at(i); 783 Visit(stmt); 784 if (stmt->IsJump()) break; 785 } 786 } 787 788 789 void AstVisitor::VisitExpressions(ZoneList<Expression*>* expressions) { 790 for (int i = 0; i < expressions->length(); i++) { 791 // The variable statement visiting code may pass NULL expressions 792 // to this code. Maybe this should be handled by introducing an 793 // undefined expression or literal? Revisit this code if this 794 // changes 795 Expression* expression = expressions->at(i); 796 if (expression != NULL) Visit(expression); 797 } 798 } 799 800 801 CaseClause::CaseClause(Zone* zone, Expression* label, 802 ZoneList<Statement*>* statements, int pos) 803 : Expression(zone, pos), 804 label_(label), 805 statements_(statements), 806 compare_type_(Type::None(zone)) {} 807 808 809 uint32_t Literal::Hash() { 810 return raw_value()->IsString() 811 ? raw_value()->AsString()->hash() 812 : ComputeLongHash(double_to_uint64(raw_value()->AsNumber())); 813 } 814 815 816 // static 817 bool Literal::Match(void* literal1, void* literal2) { 818 const AstValue* x = static_cast<Literal*>(literal1)->raw_value(); 819 const AstValue* y = static_cast<Literal*>(literal2)->raw_value(); 820 return (x->IsString() && y->IsString() && x->AsString() == y->AsString()) || 821 (x->IsNumber() && y->IsNumber() && x->AsNumber() == y->AsNumber()); 822 } 823 824 825 } // namespace internal 826 } // namespace v8 827