}
-static bool FindAllCanReadHolder(LookupIterator* it) {
+// static
+bool JSObject::AllCanRead(LookupIterator* it) {
// Skip current iteration, it's in state ACCESS_CHECK or INTERCEPTOR, both of
// which have already been checked.
DCHECK(it->state() == LookupIterator::ACCESS_CHECK ||
MaybeHandle<Object> JSObject::GetPropertyWithFailedAccessCheck(
LookupIterator* it) {
Handle<JSObject> checked = it->GetHolder<JSObject>();
- while (FindAllCanReadHolder(it)) {
+ while (AllCanRead(it)) {
if (it->state() == LookupIterator::ACCESSOR) {
return GetPropertyWithAccessor(it, SLOPPY);
}
Maybe<PropertyAttributes> JSObject::GetPropertyAttributesWithFailedAccessCheck(
LookupIterator* it) {
Handle<JSObject> checked = it->GetHolder<JSObject>();
- while (FindAllCanReadHolder(it)) {
+ while (AllCanRead(it)) {
if (it->state() == LookupIterator::ACCESSOR) {
return Just(it->property_details().attributes());
}
}
-static bool FindAllCanWriteHolder(LookupIterator* it) {
+// static
+bool JSObject::AllCanWrite(LookupIterator* it) {
for (; it->IsFound(); it->Next()) {
if (it->state() == LookupIterator::ACCESSOR) {
Handle<Object> accessors = it->GetAccessors();
MaybeHandle<Object> JSObject::SetPropertyWithFailedAccessCheck(
LookupIterator* it, Handle<Object> value) {
Handle<JSObject> checked = it->GetHolder<JSObject>();
- if (FindAllCanWriteHolder(it)) {
+ if (AllCanWrite(it)) {
// The supplied language-mode is ignored by SetPropertyWithAccessor.
return SetPropertyWithAccessor(it, value, SLOPPY);
}
// Fill in the names of own properties into the supplied storage. The main
// purpose of this function is to provide reflection information for the object
// mirrors.
-void JSObject::GetOwnPropertyNames(
- FixedArray* storage, int index, PropertyAttributes filter) {
+int JSObject::GetOwnPropertyNames(FixedArray* storage, int index,
+ PropertyAttributes filter) {
DCHECK(storage->length() >= (NumberOfOwnProperties(filter) - index));
if (HasFastProperties()) {
+ int start_index = index;
int real_size = map()->NumberOfOwnDescriptors();
DescriptorArray* descs = map()->instance_descriptors();
for (int i = 0; i < real_size; i++) {
storage->set(index++, descs->GetKey(i));
}
}
+ return index - start_index;
} else if (IsGlobalObject()) {
- global_dictionary()->CopyKeysTo(storage, index, filter,
- GlobalDictionary::UNSORTED);
+ return global_dictionary()->CopyKeysTo(storage, index, filter,
+ GlobalDictionary::UNSORTED);
} else {
- property_dictionary()->CopyKeysTo(storage, index, filter,
- NameDictionary::UNSORTED);
+ return property_dictionary()->CopyKeysTo(storage, index, filter,
+ NameDictionary::UNSORTED);
}
}
case DICTIONARY_ELEMENTS: {
if (storage != NULL) {
- element_dictionary()->CopyKeysTo(storage, filter,
+ element_dictionary()->CopyKeysTo(storage, 0, filter,
SeededNumberDictionary::SORTED);
}
counter += element_dictionary()->NumberOfElementsFilterAttributes(filter);
SeededNumberDictionary* dictionary =
SeededNumberDictionary::cast(arguments);
if (storage != NULL) {
- dictionary->CopyKeysTo(storage, filter,
+ dictionary->CopyKeysTo(storage, 0, filter,
SeededNumberDictionary::UNSORTED);
}
counter += dictionary->NumberOfElementsFilterAttributes(filter);
}
-template <typename Derived, typename Shape, typename Key>
-void Dictionary<Derived, Shape, Key>::CopyKeysTo(
- FixedArray* storage, PropertyAttributes filter,
- typename Dictionary<Derived, Shape, Key>::SortMode sort_mode) {
- DCHECK(storage->length() >= NumberOfElementsFilterAttributes(filter));
- int capacity = this->Capacity();
- int index = 0;
- for (int i = 0; i < capacity; i++) {
- Object* k = this->KeyAt(i);
- if (this->IsKey(k) && !FilterKey(k, filter)) {
- if (this->IsDeleted(i)) continue;
- PropertyDetails details = this->DetailsAt(i);
- PropertyAttributes attr = details.attributes();
- if ((attr & filter) == 0) storage->set(index++, k);
- }
- }
- if (sort_mode == Dictionary::SORTED) {
- storage->SortPairs(storage, index);
- }
- DCHECK(storage->length() >= index);
-}
-
-
template <typename Dictionary>
struct EnumIndexComparator {
explicit EnumIndexComparator(Dictionary* dict) : dict(dict) {}
template <typename Derived, typename Shape, typename Key>
-void Dictionary<Derived, Shape, Key>::CopyKeysTo(
+int Dictionary<Derived, Shape, Key>::CopyKeysTo(
FixedArray* storage, int index, PropertyAttributes filter,
typename Dictionary<Derived, Shape, Key>::SortMode sort_mode) {
DCHECK(storage->length() >= NumberOfElementsFilterAttributes(filter));
+ int start_index = index;
int capacity = this->Capacity();
for (int i = 0; i < capacity; i++) {
Object* k = this->KeyAt(i);
storage->SortPairs(storage, index);
}
DCHECK(storage->length() >= index);
+ return index - start_index;
}
// with the specified attributes (ignoring interceptors).
int NumberOfOwnProperties(PropertyAttributes filter = NONE);
// Fill in details for properties into storage starting at the specified
- // index.
- void GetOwnPropertyNames(
- FixedArray* storage, int index, PropertyAttributes filter = NONE);
+ // index. Returns the number of properties added.
+ int GetOwnPropertyNames(FixedArray* storage, int index,
+ PropertyAttributes filter = NONE);
// Returns the number of properties on this object filtering out properties
// with the specified attributes (ignoring interceptors).
static void DeleteNormalizedProperty(Handle<JSObject> object,
Handle<Name> name, int entry);
+ static bool AllCanRead(LookupIterator* it);
+ static bool AllCanWrite(LookupIterator* it);
+
private:
friend class JSReceiver;
friend class Object;
enum SortMode { UNSORTED, SORTED };
- // Copies keys to preallocated fixed array.
- void CopyKeysTo(FixedArray* storage, PropertyAttributes filter,
- SortMode sort_mode);
-
// Fill in details for properties into storage.
- void CopyKeysTo(FixedArray* storage, int index, PropertyAttributes filter,
- SortMode sort_mode);
+ // Returns the number of properties added.
+ int CopyKeysTo(FixedArray* storage, int index, PropertyAttributes filter,
+ SortMode sort_mode);
// Copies enumerable keys to preallocated fixed array.
void CopyEnumKeysTo(FixedArray* storage);
}
-// Find the length of the prototype chain that is to be handled as one. If a
-// prototype object is hidden it is to be viewed as part of the the object it
-// is prototype for.
-static int OwnPrototypeChainLength(JSObject* obj) {
- int count = 1;
- for (PrototypeIterator iter(obj->GetIsolate(), obj);
- !iter.IsAtEnd(PrototypeIterator::END_AT_NON_HIDDEN); iter.Advance()) {
- count++;
- }
- return count;
-}
-
-
// Return the names of the own named properties.
// args[0]: object
// args[1]: PropertyAttributes as int
if (!args[0]->IsJSObject()) {
return isolate->heap()->undefined_value();
}
- CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
+ CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
CONVERT_SMI_ARG_CHECKED(filter_value, 1);
PropertyAttributes filter = static_cast<PropertyAttributes>(filter_value);
- // Skip the global proxy as it has no properties and always delegates to the
- // real global object.
- if (obj->IsJSGlobalProxy()) {
- // Only collect names if access is permitted.
- if (obj->IsAccessCheckNeeded() && !isolate->MayAccess(obj)) {
- isolate->ReportFailedAccessCheck(obj);
- RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
- return *isolate->factory()->NewJSArray(0);
- }
- PrototypeIterator iter(isolate, obj);
- obj = Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter));
- }
-
- // Find the number of objects making up this.
- int length = OwnPrototypeChainLength(*obj);
-
// Find the number of own properties for each of the objects.
- ScopedVector<int> own_property_count(length);
int total_property_count = 0;
- {
- PrototypeIterator iter(isolate, obj, PrototypeIterator::START_AT_RECEIVER);
- for (int i = 0; i < length; i++) {
- DCHECK(!iter.IsAtEnd());
- Handle<JSObject> jsproto =
- Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter));
- // Only collect names if access is permitted.
- if (jsproto->IsAccessCheckNeeded() && !isolate->MayAccess(jsproto)) {
- isolate->ReportFailedAccessCheck(jsproto);
- RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
- return *isolate->factory()->NewJSArray(0);
- }
- int n;
- n = jsproto->NumberOfOwnProperties(filter);
- own_property_count[i] = n;
- total_property_count += n;
- iter.Advance();
- }
+ for (PrototypeIterator iter(isolate, object,
+ PrototypeIterator::START_AT_RECEIVER);
+ !iter.IsAtEnd(PrototypeIterator::END_AT_NON_HIDDEN); iter.Advance()) {
+ Handle<JSObject> jsproto =
+ Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter));
+ total_property_count += jsproto->NumberOfOwnProperties(filter);
}
// Allocate an array with storage for all the property names.
// Get the property names.
int next_copy_index = 0;
int hidden_strings = 0;
- {
- PrototypeIterator iter(isolate, obj, PrototypeIterator::START_AT_RECEIVER);
- for (int i = 0; i < length; i++) {
- DCHECK(!iter.IsAtEnd());
- Handle<JSObject> jsproto =
- Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter));
- jsproto->GetOwnPropertyNames(*names, next_copy_index, filter);
- // Names from hidden prototypes may already have been added
- // for inherited function template instances. Count the duplicates
- // and stub them out; the final copy pass at the end ignores holes.
- for (int j = next_copy_index; j < next_copy_index + own_property_count[i];
- j++) {
- Object* name_from_hidden_proto = names->get(j);
- if (isolate->IsInternallyUsedPropertyName(name_from_hidden_proto)) {
- hidden_strings++;
- } else {
- for (int k = 0; k < next_copy_index; k++) {
- Object* name = names->get(k);
- if (name_from_hidden_proto == name) {
- names->set(j, isolate->heap()->hidden_string());
- hidden_strings++;
- break;
- }
+ Handle<Object> hidden_string = isolate->factory()->hidden_string();
+ for (PrototypeIterator iter(isolate, object,
+ PrototypeIterator::START_AT_RECEIVER);
+ !iter.IsAtEnd(PrototypeIterator::END_AT_NON_HIDDEN); iter.Advance()) {
+ Handle<JSObject> jsproto =
+ Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter));
+ int own = jsproto->GetOwnPropertyNames(*names, next_copy_index, filter);
+ // Names from hidden prototypes may already have been added
+ // for inherited function template instances. Count the duplicates
+ // and stub them out; the final copy pass at the end ignores holes.
+ for (int j = next_copy_index; j < next_copy_index + own; j++) {
+ Object* name_from_hidden_proto = names->get(j);
+ if (isolate->IsInternallyUsedPropertyName(name_from_hidden_proto)) {
+ hidden_strings++;
+ } else {
+ for (int k = 0; k < next_copy_index; k++) {
+ Object* name = names->get(k);
+ if (name_from_hidden_proto == name) {
+ names->set(j, *hidden_string);
+ hidden_strings++;
+ break;
}
}
}
- next_copy_index += own_property_count[i];
+ }
+ next_copy_index += own;
+ }
+
+ CHECK_EQ(total_property_count, next_copy_index);
- iter.Advance();
+ if (object->IsAccessCheckNeeded() && !isolate->MayAccess(object)) {
+ for (int i = 0; i < total_property_count; i++) {
+ Handle<Name> name(Name::cast(names->get(i)));
+ if (name.is_identical_to(hidden_string)) continue;
+ LookupIterator it(object, name, LookupIterator::HIDDEN_SKIP_INTERCEPTOR);
+ if (!JSObject::AllCanRead(&it)) {
+ names->set(i, *hidden_string);
+ hidden_strings++;
+ }
}
}
// Filter out name of hidden properties object and
// hidden prototype duplicates.
if (hidden_strings > 0) {
- Handle<FixedArray> old_names = names;
- names = isolate->factory()->NewFixedArray(names->length() - hidden_strings);
- int dest_pos = 0;
- for (int i = 0; i < total_property_count; i++) {
- Object* name = old_names->get(i);
- if (isolate->IsInternallyUsedPropertyName(name)) {
- hidden_strings--;
- continue;
+ if (hidden_strings == total_property_count) {
+ names = isolate->factory()->empty_fixed_array();
+ } else {
+ int i;
+ for (i = 0; i < total_property_count; i++) {
+ Object* name = names->get(i);
+ if (name == *hidden_string) break;
+ }
+ int dest_pos = i;
+ for (; i < total_property_count; i++) {
+ Object* name = names->get(i);
+ if (name == *hidden_string) continue;
+ names->set(dest_pos++, name);
}
- names->set(dest_pos++, name);
+
+ isolate->heap()->RightTrimFixedArray<Heap::CONCURRENT_TO_SWEEPER>(
+ *names, hidden_strings);
}
- DCHECK_EQ(0, hidden_strings);
}
return *isolate->factory()->NewJSArrayWithElements(names);
obj_template->Set(v8_str("x"), v8::Integer::New(isolate, 42));
obj_template->SetAccessCheckCallbacks(AccessAlwaysBlocked, NULL);
+ // Add an accessor accessible by cross-domain JS code.
+ obj_template->SetAccessor(
+ v8_str("accessible_prop"), EchoGetter, EchoSetter, v8::Handle<Value>(),
+ v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
+
// Create an environment
v8::Local<Context> context0 = Context::New(isolate, NULL, obj_template);
context0->Enter();
// global object should be blocked by access checks on the global
// proxy object. Accessing the object that requires access checks
// is blocked by the access checks on the object itself.
- value = CompileRun("Object.getOwnPropertyNames(other).length == 0");
- CHECK(value.IsEmpty());
+ value = CompileRun(
+ "var names = Object.getOwnPropertyNames(other);"
+ "names.length == 1 && names[0] == 'accessible_prop';");
+ CHECK(value->BooleanValue());
- value = CompileRun("Object.getOwnPropertyNames(object).length == 0");
- CHECK(value.IsEmpty());
+ value = CompileRun(
+ "var names = Object.getOwnPropertyNames(object);"
+ "names.length == 1 && names[0] == 'accessible_prop';");
+ CHECK(value->BooleanValue());
context1->Exit();
context0->Exit();
CheckCorrectThrow("%IsPropertyEnumerable(other, 'x')");
CheckCorrectThrow("%GetPropertyNames(other)");
// PROPERTY_ATTRIBUTES_NONE = 0
- CheckCorrectThrow("%GetOwnPropertyNames(other, 0)");
CheckCorrectThrow("%DefineAccessorPropertyUnchecked("
"other, 'x', null, null, 1)");