Home | History | Annotate | Download | only in ast
      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