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