--- old/src/jdk/nashorn/internal/runtime/ScriptObject.java 2014-08-11 20:02:13.958583667 +0530 +++ new/src/jdk/nashorn/internal/runtime/ScriptObject.java 2014-08-11 20:02:13.758582677 +0530 @@ -1324,7 +1324,19 @@ * @param all True if to include non-enumerable keys. * @return Array of keys. */ - public String[] getOwnKeys(final boolean all) { + public final String[] getOwnKeys(final boolean all) { + return getOwnKeys(all, null); + } + + /** + * return an array of own property keys associated with the object. + * + * @param all True if to include non-enumerable keys. + * @param nonEnumerable set of non-enumerable properties seen already.Used + to filter out shadowed, but enumerable properties from proto children. + * @return Array of keys. + */ + protected String[] getOwnKeys(final boolean all, final Set nonEnumerable) { final List keys = new ArrayList<>(); final PropertyMap selfMap = this.getMap(); @@ -1338,8 +1350,21 @@ } for (final Property property : selfMap.getProperties()) { - if (all || property.isEnumerable()) { - keys.add(property.getKey()); + final boolean enumerable = property.isEnumerable(); + final String key = property.getKey(); + if (all) { + keys.add(key); + } else if (enumerable) { + // either we don't have non-enumerable filter set or filter set + // does not contain the current property. + if (nonEnumerable == null || !nonEnumerable.contains(key)) { + keys.add(key); + } + } else { + // store this non-enumerable property for later proto walk + if (nonEnumerable != null) { + nonEnumerable.add(key); + } } } @@ -2398,8 +2423,9 @@ @Override protected void init() { final Set keys = new LinkedHashSet<>(); + final Set nonEnumerable = new HashSet<>(); for (ScriptObject self = object; self != null; self = self.getProto()) { - keys.addAll(Arrays.asList(self.getOwnKeys(false))); + keys.addAll(Arrays.asList(self.getOwnKeys(false, nonEnumerable))); } this.values = keys.toArray(new String[keys.size()]); } @@ -2413,8 +2439,9 @@ @Override protected void init() { final ArrayList valueList = new ArrayList<>(); + final Set nonEnumerable = new HashSet<>(); for (ScriptObject self = object; self != null; self = self.getProto()) { - for (final String key : self.getOwnKeys(false)) { + for (final String key : self.getOwnKeys(false, nonEnumerable)) { valueList.add(self.get(key)); } }