}
+// Enumerator used as indices into the array returned from GetOwnProperty
+enum PropertyDescriptorIndices {
+ IS_ACCESSOR_INDEX,
+ VALUE_INDEX,
+ GETTER_INDEX,
+ SETTER_INDEX,
+ WRITABLE_INDEX,
+ ENUMERABLE_INDEX,
+ CONFIGURABLE_INDEX,
+ DESCRIPTOR_SIZE
+};
+
// Returns an array with the property description:
// if args[1] is not a property on args[0]
// returns undefined
static Object* Runtime_GetOwnProperty(Arguments args) {
ASSERT(args.length() == 2);
HandleScope scope;
- Handle<FixedArray> elms = Factory::NewFixedArray(5);
+ Handle<FixedArray> elms = Factory::NewFixedArray(DESCRIPTOR_SIZE);
Handle<JSArray> desc = Factory::NewJSArrayWithElements(elms);
LookupResult result;
CONVERT_CHECKED(JSObject, obj, args[0]);
CONVERT_CHECKED(String, name, args[1]);
+ // This could be an element.
+ uint32_t index;
+ if (name->AsArrayIndex(&index)) {
+ if (!obj->HasLocalElement(index)) {
+ return Heap::undefined_value();
+ }
+
+ // Special handling of string objects according to ECMAScript 5 15.5.5.2.
+ // Note that this might be a string object with elements other than the
+ // actual string value. This is covered by the subsequent cases.
+ if (obj->IsStringObjectWithCharacterAt(index)) {
+ JSValue* js_value = JSValue::cast(obj);
+ String* str = String::cast(js_value->value());
+ elms->set(IS_ACCESSOR_INDEX, Heap::false_value());
+ elms->set(VALUE_INDEX, str->SubString(index, index+1));
+ elms->set(WRITABLE_INDEX, Heap::false_value());
+ elms->set(ENUMERABLE_INDEX, Heap::false_value());
+ elms->set(CONFIGURABLE_INDEX, Heap::false_value());
+ return *desc;
+ }
+
+ // This can potentially be an element in the elements dictionary or
+ // a fast element.
+ if (obj->HasDictionaryElements()) {
+ NumberDictionary* dictionary = obj->element_dictionary();
+ int entry = dictionary->FindEntry(index);
+ PropertyDetails details = dictionary->DetailsAt(entry);
+ elms->set(IS_ACCESSOR_INDEX, Heap::false_value());
+ elms->set(VALUE_INDEX, dictionary->ValueAt(entry));
+ elms->set(WRITABLE_INDEX, Heap::ToBoolean(!details.IsDontDelete()));
+ elms->set(ENUMERABLE_INDEX, Heap::ToBoolean(!details.IsDontEnum()));
+ elms->set(CONFIGURABLE_INDEX, Heap::ToBoolean(!details.IsReadOnly()));
+ return *desc;
+ } else {
+ // Elements that are stored as array elements always has:
+ // writable: true, configurable: true, enumerable: true.
+ elms->set(IS_ACCESSOR_INDEX, Heap::false_value());
+ elms->set(VALUE_INDEX, obj->GetElement(index));
+ elms->set(WRITABLE_INDEX, Heap::true_value());
+ elms->set(ENUMERABLE_INDEX, Heap::true_value());
+ elms->set(CONFIGURABLE_INDEX, Heap::true_value());
+ return *desc;
+ }
+ }
+
// Use recursive implementation to also traverse hidden prototypes
GetOwnPropertyImplementation(obj, name, &result);
- if (!result.IsProperty())
+ if (!result.IsProperty()) {
return Heap::undefined_value();
-
+ }
if (result.type() == CALLBACKS) {
Object* structure = result.GetCallbackObject();
if (structure->IsProxy() || structure->IsAccessorInfo()) {
// an API defined callback.
Object* value = obj->GetPropertyWithCallback(
obj, structure, name, result.holder());
- elms->set(0, Heap::false_value());
- elms->set(1, value);
- elms->set(2, Heap::ToBoolean(!result.IsReadOnly()));
+ elms->set(IS_ACCESSOR_INDEX, Heap::false_value());
+ elms->set(VALUE_INDEX, value);
+ elms->set(WRITABLE_INDEX, Heap::ToBoolean(!result.IsReadOnly()));
} else if (structure->IsFixedArray()) {
// __defineGetter__/__defineSetter__ callback.
- elms->set(0, Heap::true_value());
- elms->set(1, FixedArray::cast(structure)->get(0));
- elms->set(2, FixedArray::cast(structure)->get(1));
+ elms->set(IS_ACCESSOR_INDEX, Heap::true_value());
+ elms->set(GETTER_INDEX, FixedArray::cast(structure)->get(0));
+ elms->set(SETTER_INDEX, FixedArray::cast(structure)->get(1));
} else {
return Heap::undefined_value();
}
} else {
- elms->set(0, Heap::false_value());
- elms->set(1, result.GetLazyValue());
- elms->set(2, Heap::ToBoolean(!result.IsReadOnly()));
+ elms->set(IS_ACCESSOR_INDEX, Heap::false_value());
+ elms->set(VALUE_INDEX, result.GetLazyValue());
+ elms->set(WRITABLE_INDEX, Heap::ToBoolean(!result.IsReadOnly()));
}
- elms->set(3, Heap::ToBoolean(!result.IsDontEnum()));
- elms->set(4, Heap::ToBoolean(!result.IsDontDelete()));
+ elms->set(ENUMERABLE_INDEX, Heap::ToBoolean(!result.IsDontEnum()));
+ elms->set(CONFIGURABLE_INDEX, Heap::ToBoolean(!result.IsDontDelete()));
return *desc;
}
function GetOwnProperty(obj, p) {
var desc = new PropertyDescriptor();
- // An array with:
- // obj is a data property [false, value, Writeable, Enumerable, Configurable]
- // obj is an accessor [true, Get, Set, Enumerable, Configurable]
+ // GetOwnProperty returns an array indexed by the constants
+ // defined in macros.py.
+ // If p is not a property on obj undefined is returned.
var props = %GetOwnProperty(ToObject(obj), ToString(p));
if (IS_UNDEFINED(props)) return void 0;
// This is an accessor
- if (props[0]) {
- desc.setGet(props[1]);
- desc.setSet(props[2]);
+ if (props[IS_ACCESSOR_INDEX]) {
+ desc.setGet(props[GETTER_INDEX]);
+ desc.setSet(props[SETTER_INDEX]);
} else {
- desc.setValue(props[1]);
- desc.setWritable(props[2]);
+ desc.setValue(props[VALUE_INDEX]);
+ desc.setWritable(props[WRITABLE_INDEX]);
}
- desc.setEnumerable(props[3]);
- desc.setConfigurable(props[4]);
+ desc.setEnumerable(props[ENUMERABLE_INDEX]);
+ desc.setConfigurable(props[CONFIGURABLE_INDEX]);
return desc;
}
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-function get(){return x}
-function set(x){this.x=x};
+// This file only tests very simple descriptors that always have
+// configurable, enumerable, and writable set to true.
+// A range of more elaborate tests are performed in
+// object-define-property.js
-var obj = {x:1};
+function get() { return x; }
+function set(x) { this.x = x; }
+
+var obj = {x: 1};
obj.__defineGetter__("accessor", get);
obj.__defineSetter__("accessor", set);
+var a = new Array();
+a[1] = 42;
+obj[1] = 42;
-
-var descIsData = Object.getOwnPropertyDescriptor(obj,'x');
+var descIsData = Object.getOwnPropertyDescriptor(obj, 'x');
assertTrue(descIsData.enumerable);
assertTrue(descIsData.writable);
assertTrue(descIsData.configurable);
var descIsNotAccessor = Object.getOwnPropertyDescriptor(obj, 'not-accessor');
assertTrue(descIsNotAccessor == undefined);
+
+var descArray = Object.getOwnPropertyDescriptor(a, '1');
+assertTrue(descArray.enumerable);
+assertTrue(descArray.configurable);
+assertTrue(descArray.writable);
+assertEquals(descArray.value, 42);
+
+var descObjectElement = Object.getOwnPropertyDescriptor(obj, '1');
+assertTrue(descObjectElement.enumerable);
+assertTrue(descObjectElement.configurable);
+assertTrue(descObjectElement.writable);
+assertEquals(descObjectElement.value, 42);
+
+// String objects.
+var a = new String('foobar');
+for (var i = 0; i < a.length; i++) {
+ var descStringObject = Object.getOwnPropertyDescriptor(a, i);
+ assertFalse(descStringObject.enumerable);
+ assertFalse(descStringObject.configurable);
+ assertFalse(descStringObject.writable);
+ assertEquals(descStringObject.value, a.substring(i, i+1));
+}
+
+// Support for additional attributes on string objects.
+a.x = 42;
+a[10] = 'foo';
+var descStringProperty = Object.getOwnPropertyDescriptor(a, 'x');
+assertTrue(descStringProperty.enumerable);
+assertTrue(descStringProperty.configurable);
+assertTrue(descStringProperty.writable);
+assertEquals(descStringProperty.value, 42);
+
+var descStringElement = Object.getOwnPropertyDescriptor(a, '10');
+assertTrue(descStringElement.enumerable);
+assertTrue(descStringElement.configurable);
+assertTrue(descStringElement.writable);
+assertEquals(descStringElement.value, 'foo');
+
+// Test that elements in the prototype chain is not returned.
+var proto = {};
+proto[10] = 42;
+
+var objWithProto = new Array();
+objWithProto.prototype = proto;
+objWithProto[0] = 'bar';
+var descWithProto = Object.getOwnPropertyDescriptor(objWithProto, '10');
+assertEquals(undefined, descWithProto);