# Private names.
macro NEW_PRIVATE(name) = (%CreatePrivateSymbol(name));
+macro IS_PRIVATE(sym) = (%SymbolIsPrivate(sym));
macro HAS_PRIVATE(obj, sym) = (sym in obj);
macro GET_PRIVATE(obj, sym) = (obj[sym]);
macro SET_PRIVATE(obj, sym, val) = (obj[sym] = val);
# Matches Messages::kNoLineNumberInfo from v8.h
const kNoLineNumberInfo = 0;
+
+# Matches PropertyAttributes from property-details.h
+const PROPERTY_ATTRIBUTES_NONE = 0;
+const PROPERTY_ATTRIBUTES_STRING = 8;
+const PROPERTY_ATTRIBUTES_SYMBOLIC = 16;
+const PROPERTY_ATTRIBUTES_PRIVATE_SYMBOL = 32;
// Find all the named properties.
if (kind & PropertyKind.Named) {
- // Get the local property names.
- propertyNames = %GetLocalPropertyNames(this.value_, true);
+ // Get all the local property names.
+ propertyNames =
+ %GetLocalPropertyNames(this.value_, PROPERTY_ATTRIBUTES_NONE);
total += propertyNames.length;
// Get names for named interceptor properties if any.
}
+static bool FilterKey(Object* key, PropertyAttributes filter) {
+ if ((filter & SYMBOLIC) && key->IsSymbol()) {
+ return true;
+ }
+
+ if ((filter & PRIVATE_SYMBOL) &&
+ key->IsSymbol() && Symbol::cast(key)->is_private()) {
+ return true;
+ }
+
+ if ((filter & STRING) && !key->IsSymbol()) {
+ return true;
+ }
+
+ return false;
+}
+
+
int Map::NumberOfDescribedProperties(DescriptorFlag which,
PropertyAttributes filter) {
int result = 0;
: NumberOfOwnDescriptors();
for (int i = 0; i < limit; i++) {
if ((descs->GetDetails(i).attributes() & filter) == 0 &&
- ((filter & SYMBOLIC) == 0 || !descs->GetKey(i)->IsSymbol())) {
+ !FilterKey(descs->GetKey(i), filter)) {
result++;
}
}
DescriptorArray* descs = map()->instance_descriptors();
for (int i = 0; i < real_size; i++) {
if ((descs->GetDetails(i).attributes() & filter) == 0 &&
- ((filter & SYMBOLIC) == 0 || !descs->GetKey(i)->IsSymbol())) {
+ !FilterKey(descs->GetKey(i), filter)) {
storage->set(index++, descs->GetKey(i));
}
}
for (int i = 0; i < capacity; i++) {
Object* k = HashTable<Shape, Key>::KeyAt(i);
if (HashTable<Shape, Key>::IsKey(k) &&
- ((filter & SYMBOLIC) == 0 || !k->IsSymbol())) {
+ !FilterKey(k, filter)) {
PropertyDetails details = DetailsAt(i);
if (details.IsDeleted()) continue;
PropertyAttributes attr = details.attributes();
SEALED = DONT_DELETE,
FROZEN = SEALED | READ_ONLY,
- SYMBOLIC = 8, // Used to filter symbol names
- DONT_SHOW = DONT_ENUM | SYMBOLIC,
- ABSENT = 16 // Used in runtime to indicate a property is absent.
+ STRING = 8, // Used to filter symbols and string names
+ SYMBOLIC = 16,
+ PRIVATE_SYMBOL = 32,
+
+ DONT_SHOW = DONT_ENUM | SYMBOLIC | PRIVATE_SYMBOL,
+ ABSENT = 64 // Used in runtime to indicate a property is absent.
// ABSENT can never be stored in or returned from a descriptor's attributes
// bitfield. It is only used as a return value meaning the attributes of
// a non-existent property.
// Return the names of the local named properties.
// args[0]: object
+// args[1]: PropertyAttributes as int
RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalPropertyNames) {
HandleScope scope(isolate);
ASSERT(args.length() == 2);
return isolate->heap()->undefined_value();
}
CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
- CONVERT_BOOLEAN_ARG_CHECKED(include_symbols, 1);
- PropertyAttributes filter = include_symbols ? NONE : SYMBOLIC;
+ 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.
return %_ValueOf(this);
}
+
+// ES6 19.1.2.8
+function ObjectGetOwnPropertySymbols(obj) {
+ if (!IS_SPEC_OBJECT(obj)) {
+ throw MakeTypeError("called_on_non_object",
+ ["Object.getOwnPropertySymbols"]);
+ }
+
+ // TODO(arv): Proxies use a shared trap for String and Symbol keys.
+
+ return ObjectGetOwnPropertyKeys(obj, true);
+}
+
+
//-------------------------------------------------------------------
function SetUpSymbol() {
}
SetUpSymbol();
+
+
+function ExtendObject() {
+ %CheckIsBootstrapping();
+
+ InstallFunctions($Object, DONT_ENUM, $Array(
+ "getOwnPropertySymbols", ObjectGetOwnPropertySymbols
+ ));
+}
+
+ExtendObject();
}
-// ES5 section 15.2.3.4.
-function ObjectGetOwnPropertyNames(obj) {
- if (!IS_SPEC_OBJECT(obj)) {
- throw MakeTypeError("called_on_non_object", ["Object.getOwnPropertyNames"]);
- }
- // Special handling for proxies.
- if (%IsJSProxy(obj)) {
- var handler = %GetHandler(obj);
- var names = CallTrap0(handler, "getOwnPropertyNames", UNDEFINED);
- return ToNameArray(names, "getOwnPropertyNames", false);
- }
-
+function ObjectGetOwnPropertyKeys(obj, symbolsOnly) {
var nameArrays = new InternalArray();
+ var filter = symbolsOnly ?
+ PROPERTY_ATTRIBUTES_STRING | PROPERTY_ATTRIBUTES_PRIVATE_SYMBOL :
+ PROPERTY_ATTRIBUTES_SYMBOLIC;
// Find all the indexed properties.
- // Get the local element names.
- var localElementNames = %GetLocalElementNames(obj);
- for (var i = 0; i < localElementNames.length; ++i) {
- localElementNames[i] = %_NumberToString(localElementNames[i]);
- }
- nameArrays.push(localElementNames);
-
- // Get names for indexed interceptor properties.
- var interceptorInfo = %GetInterceptorInfo(obj);
- if ((interceptorInfo & 1) != 0) {
- var indexedInterceptorNames = %GetIndexedInterceptorElementNames(obj);
- if (!IS_UNDEFINED(indexedInterceptorNames)) {
- nameArrays.push(indexedInterceptorNames);
+ // Only get the local element names if we want to include string keys.
+ if (!symbolsOnly) {
+ var localElementNames = %GetLocalElementNames(obj);
+ for (var i = 0; i < localElementNames.length; ++i) {
+ localElementNames[i] = %_NumberToString(localElementNames[i]);
+ }
+ nameArrays.push(localElementNames);
+
+ // Get names for indexed interceptor properties.
+ var interceptorInfo = %GetInterceptorInfo(obj);
+ if ((interceptorInfo & 1) != 0) {
+ var indexedInterceptorNames = %GetIndexedInterceptorElementNames(obj);
+ if (!IS_UNDEFINED(indexedInterceptorNames)) {
+ nameArrays.push(indexedInterceptorNames);
+ }
}
}
// Find all the named properties.
// Get the local property names.
- nameArrays.push(%GetLocalPropertyNames(obj, false));
+ nameArrays.push(%GetLocalPropertyNames(obj, filter));
// Get names for named interceptor properties if any.
if ((interceptorInfo & 2) != 0) {
- var namedInterceptorNames = %GetNamedInterceptorPropertyNames(obj);
+ var namedInterceptorNames =
+ %GetNamedInterceptorPropertyNames(obj);
if (!IS_UNDEFINED(namedInterceptorNames)) {
nameArrays.push(namedInterceptorNames);
}
// Property names are expected to be unique strings,
// but interceptors can interfere with that assumption.
if (interceptorInfo != 0) {
- var propertySet = { __proto__: null };
+ var seenKeys = { __proto__: null };
var j = 0;
for (var i = 0; i < propertyNames.length; ++i) {
- if (IS_SYMBOL(propertyNames[i])) continue;
- var name = ToString(propertyNames[i]);
- // We need to check for the exact property value since for intrinsic
- // properties like toString if(propertySet["toString"]) will always
- // succeed.
- if (propertySet[name] === true) {
- continue;
+ var name = propertyNames[i];
+ if (symbolsOnly) {
+ if (!IS_SYMBOL(name) || IS_PRIVATE(name)) continue;
+ } else {
+ if (IS_SYMBOL(name)) continue;
+ name = ToString(name);
}
- propertySet[name] = true;
+ if (seenKeys[name]) continue;
+ seenKeys[name] = true;
propertyNames[j++] = name;
}
propertyNames.length = j;
}
+// ES5 section 15.2.3.4.
+function ObjectGetOwnPropertyNames(obj) {
+ if (!IS_SPEC_OBJECT(obj)) {
+ throw MakeTypeError("called_on_non_object", ["Object.getOwnPropertyNames"]);
+ }
+ // Special handling for proxies.
+ if (%IsJSProxy(obj)) {
+ var handler = %GetHandler(obj);
+ var names = CallTrap0(handler, "getOwnPropertyNames", UNDEFINED);
+ return ToNameArray(names, "getOwnPropertyNames", false);
+ }
+
+ return ObjectGetOwnPropertyKeys(obj, false);
+}
+
+
// ES5 section 15.2.3.5.
function ObjectCreate(proto, properties) {
if (!IS_SPEC_OBJECT(proto) && proto !== null) {
"getPrototypeOf", ObjectGetPrototypeOf,
"getOwnPropertyDescriptor", ObjectGetOwnPropertyDescriptor,
"getOwnPropertyNames", ObjectGetOwnPropertyNames,
+ // getOwnPropertySymbols is added in symbol.js.
"is", ObjectIs,
"isExtensible", ObjectIsExtensible,
"isFrozen", ObjectIsFrozen,
"isSealed", ObjectIsSealed,
"preventExtensions", ObjectPreventExtension,
"seal", ObjectSeal
+ // deliverChangeRecords, getNotifier, observe and unobserve are added
+ // in object-observe.js.
));
}
// Call the runtime version of GetLocalPropertyNames() on the natively
// created object through JavaScript.
context->Global()->Set(v8_str("obj"), o4);
- CompileRun("var names = %GetLocalPropertyNames(obj, true);");
+ // PROPERTY_ATTRIBUTES_NONE = 0
+ CompileRun("var names = %GetLocalPropertyNames(obj, 0);");
ExpectInt32("names.length", 1006);
ExpectTrue("names.indexOf(\"baz\") >= 0");
// the natively created object through JavaScript.
context->Global()->Set(v8_str("obj"), o2);
context->Global()->Set(v8_str("sym"), sym);
- CompileRun("var names = %GetLocalPropertyNames(obj, true);");
+ // PROPERTY_ATTRIBUTES_NONE = 0
+ CompileRun("var names = %GetLocalPropertyNames(obj, 0);");
ExpectInt32("names.length", 7);
ExpectTrue("names.indexOf(\"foo\") >= 0");
CheckCorrectThrow("%HasElement(other, 1)");
CheckCorrectThrow("%IsPropertyEnumerable(other, 'x')");
CheckCorrectThrow("%GetPropertyNames(other)");
- CheckCorrectThrow("%GetLocalPropertyNames(other, true)");
+ // PROPERTY_ATTRIBUTES_NONE = 0
+ CheckCorrectThrow("%GetLocalPropertyNames(other, 0)");
CheckCorrectThrow("%DefineOrRedefineAccessorProperty("
"other, 'x', null, null, 1)");
}
-function TestKeyHas() {
+function TestKeyHas(obj) {
for (var i in symbols) {
assertTrue(symbols[i] in obj)
assertTrue(Object.hasOwnProperty.call(obj, symbols[i]))
}
+function TestGetOwnPropertySymbols(obj) {
+ var syms = Object.getOwnPropertySymbols(obj)
+ assertEquals(syms.length, symbols.length)
+ for (var i in syms) {
+ assertEquals("symbol", typeof syms[i])
+ }
+}
+
+
function TestKeyDescriptor(obj) {
for (var i in symbols) {
var desc = Object.getOwnPropertyDescriptor(obj, symbols[i]);
TestKeyHas(obj)
TestKeyEnum(obj)
TestKeyNames(obj)
+ TestGetOwnPropertySymbols(obj)
TestKeyDescriptor(obj)
TestKeyDelete(obj)
}
}
}
TestCachedKeyAfterScavenge();
+
+
+function TestGetOwnPropertySymbolsWithProto() {
+ // We need to be have fast properties to have insertion order for property
+ // keys. The current limit is currently 30 properties.
+ var syms = symbols.slice(0, 30);
+ var proto = {}
+ var object = Object.create(proto)
+ for (var i = 0; i < syms.length; i++) {
+ // Even on object, odd on proto.
+ if (i % 2) {
+ proto[syms[i]] = i
+ } else {
+ object[syms[i]] = i
+ }
+ }
+
+ assertTrue(%HasFastProperties(object));
+
+ var objectOwnSymbols = Object.getOwnPropertySymbols(object)
+ assertEquals(objectOwnSymbols.length, syms.length / 2)
+
+ for (var i = 0; i < objectOwnSymbols.length; i++) {
+ assertEquals(objectOwnSymbols[i], syms[i * 2])
+ }
+}
+TestGetOwnPropertySymbolsWithProto()
+
+
+function TestGetOwnPropertySymbolsWithPrivateSymbols() {
+ var privateSymbol = %CreatePrivateSymbol("private")
+ var publicSymbol = Symbol()
+ var publicSymbol2 = Symbol()
+ var obj = {}
+ obj[publicSymbol] = 1
+ obj[privateSymbol] = 2
+ obj[publicSymbol2] = 3
+ var syms = Object.getOwnPropertySymbols(obj)
+ assertEquals(syms, [publicSymbol, publicSymbol2])
+}
+TestGetOwnPropertySymbolsWithPrivateSymbols()