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