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
Next()14 void LookupIterator::Next() {
15 has_property_ = false;
16 do {
17 state_ = LookupInHolder();
18 } while (!IsFound() && NextHolder());
19 }
20
21
GetRoot() const22 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
GetReceiverMap() const43 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
NextHolder()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
LookupInHolder()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
IsBootstrapping() const106 bool LookupIterator::IsBootstrapping() const {
107 return isolate_->bootstrapper()->IsActive();
108 }
109
110
HasAccess(v8::AccessType access_type) const111 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
HasProperty()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
FetchValue() const159 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
GetAccessors() const181 Handle<Object> LookupIterator::GetAccessors() const {
182 ASSERT(has_property_);
183 ASSERT_EQ(ACCESSOR, property_kind_);
184 return FetchValue();
185 }
186
187
GetDataValue() const188 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