Home | History | Annotate | Download | only in src
      1 // Copyright 2014 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/v8.h"
      6 
      7 #include "src/bootstrapper.h"
      8 #include "src/lookup.h"
      9 
     10 namespace v8 {
     11 namespace internal {
     12 
     13 
     14 void LookupIterator::Next() {
     15   has_property_ = false;
     16   do {
     17     state_ = LookupInHolder();
     18   } while (!IsFound() && NextHolder());
     19 }
     20 
     21 
     22 Handle<JSReceiver> LookupIterator::GetRoot() const {
     23   Handle<Object> receiver = GetReceiver();
     24   if (receiver->IsJSReceiver()) return Handle<JSReceiver>::cast(receiver);
     25   Context* native_context = isolate_->context()->native_context();
     26   JSFunction* function;
     27   if (receiver->IsNumber()) {
     28     function = native_context->number_function();
     29   } else if (receiver->IsString()) {
     30     function = native_context->string_function();
     31   } else if (receiver->IsSymbol()) {
     32     function = native_context->symbol_function();
     33   } else if (receiver->IsBoolean()) {
     34     function = native_context->boolean_function();
     35   } else {
     36     UNREACHABLE();
     37     function = NULL;
     38   }
     39   return handle(JSReceiver::cast(function->instance_prototype()));
     40 }
     41 
     42 
     43 Handle<Map> LookupIterator::GetReceiverMap() const {
     44   Handle<Object> receiver = GetReceiver();
     45   if (receiver->IsNumber()) return isolate_->factory()->heap_number_map();
     46   return handle(Handle<HeapObject>::cast(receiver)->map());
     47 }
     48 
     49 
     50 bool LookupIterator::NextHolder() {
     51   if (holder_map_->prototype()->IsNull()) return false;
     52 
     53   Handle<JSReceiver> next(JSReceiver::cast(holder_map_->prototype()));
     54 
     55   if (!check_derived() &&
     56       !(check_hidden() &&
     57          // TODO(verwaest): Check if this is actually necessary currently. If it
     58          // is, this should be handled by setting is_hidden_prototype on the
     59          // global object behind the proxy.
     60         (holder_map_->IsJSGlobalProxyMap() ||
     61          next->map()->is_hidden_prototype()))) {
     62     return false;
     63   }
     64 
     65   holder_map_ = handle(next->map());
     66   maybe_holder_ = next;
     67   return true;
     68 }
     69 
     70 
     71 LookupIterator::State LookupIterator::LookupInHolder() {
     72   switch (state_) {
     73     case NOT_FOUND:
     74       if (holder_map_->IsJSProxyMap()) {
     75         return JSPROXY;
     76       }
     77       if (check_access_check() && holder_map_->is_access_check_needed()) {
     78         return ACCESS_CHECK;
     79       }
     80       // Fall through.
     81     case ACCESS_CHECK:
     82       if (check_interceptor() && holder_map_->has_named_interceptor()) {
     83         return INTERCEPTOR;
     84       }
     85       // Fall through.
     86     case INTERCEPTOR:
     87       if (holder_map_->is_dictionary_map()) {
     88         property_encoding_ = DICTIONARY;
     89       } else {
     90         DescriptorArray* descriptors = holder_map_->instance_descriptors();
     91         number_ = descriptors->SearchWithCache(*name_, *holder_map_);
     92         if (number_ == DescriptorArray::kNotFound) return NOT_FOUND;
     93         property_encoding_ = DESCRIPTOR;
     94       }
     95       return PROPERTY;
     96     case PROPERTY:
     97       return NOT_FOUND;
     98     case JSPROXY:
     99       UNREACHABLE();
    100   }
    101   UNREACHABLE();
    102   return state_;
    103 }
    104 
    105 
    106 bool LookupIterator::IsBootstrapping() const {
    107   return isolate_->bootstrapper()->IsActive();
    108 }
    109 
    110 
    111 bool LookupIterator::HasAccess(v8::AccessType access_type) const {
    112   ASSERT_EQ(ACCESS_CHECK, state_);
    113   ASSERT(is_guaranteed_to_have_holder());
    114   return isolate_->MayNamedAccess(GetHolder(), name_, access_type);
    115 }
    116 
    117 
    118 bool LookupIterator::HasProperty() {
    119   ASSERT_EQ(PROPERTY, state_);
    120   ASSERT(is_guaranteed_to_have_holder());
    121 
    122   if (property_encoding_ == DICTIONARY) {
    123     Handle<JSObject> holder = GetHolder();
    124     number_ = holder->property_dictionary()->FindEntry(name_);
    125     if (number_ == NameDictionary::kNotFound) return false;
    126 
    127     property_details_ = GetHolder()->property_dictionary()->DetailsAt(number_);
    128     // Holes in dictionary cells are absent values unless marked as read-only.
    129     if (holder->IsGlobalObject() &&
    130         (property_details_.IsDeleted() ||
    131          (!property_details_.IsReadOnly() && FetchValue()->IsTheHole()))) {
    132       return false;
    133     }
    134   } else {
    135     property_details_ = holder_map_->instance_descriptors()->GetDetails(
    136         number_);
    137   }
    138 
    139   switch (property_details_.type()) {
    140     case v8::internal::FIELD:
    141     case v8::internal::NORMAL:
    142     case v8::internal::CONSTANT:
    143       property_kind_ = DATA;
    144       break;
    145     case v8::internal::CALLBACKS:
    146       property_kind_ = ACCESSOR;
    147       break;
    148     case v8::internal::HANDLER:
    149     case v8::internal::NONEXISTENT:
    150     case v8::internal::INTERCEPTOR:
    151       UNREACHABLE();
    152   }
    153 
    154   has_property_ = true;
    155   return true;
    156 }
    157 
    158 
    159 Handle<Object> LookupIterator::FetchValue() const {
    160   Object* result = NULL;
    161   switch (property_encoding_) {
    162     case DICTIONARY:
    163       result = GetHolder()->property_dictionary()->ValueAt(number_);
    164       if (GetHolder()->IsGlobalObject()) {
    165         result = PropertyCell::cast(result)->value();
    166       }
    167       break;
    168     case DESCRIPTOR:
    169       if (property_details_.type() == v8::internal::FIELD) {
    170         FieldIndex field_index = FieldIndex::ForDescriptor(
    171             *holder_map_, number_);
    172         return JSObject::FastPropertyAt(
    173             GetHolder(), property_details_.representation(), field_index);
    174       }
    175       result = holder_map_->instance_descriptors()->GetValue(number_);
    176   }
    177   return handle(result, isolate_);
    178 }
    179 
    180 
    181 Handle<Object> LookupIterator::GetAccessors() const {
    182   ASSERT(has_property_);
    183   ASSERT_EQ(ACCESSOR, property_kind_);
    184   return FetchValue();
    185 }
    186 
    187 
    188 Handle<Object> LookupIterator::GetDataValue() const {
    189   ASSERT(has_property_);
    190   ASSERT_EQ(DATA, property_kind_);
    191   Handle<Object> value = FetchValue();
    192   if (value->IsTheHole()) {
    193     ASSERT(property_details_.IsReadOnly());
    194     return factory()->undefined_value();
    195   }
    196   return value;
    197 }
    198 
    199 
    200 } }  // namespace v8::internal
    201