<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[197539] trunk/Source/JavaScriptCore</title>
</head>
<body>
<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; }
#msg dl a { font-weight: bold}
#msg dl a:link { color:#fc3; }
#msg dl a:active { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/197539">197539</a></dd>
<dt>Author</dt> <dd>sbarati@apple.com</dd>
<dt>Date</dt> <dd>2016-03-03 18:25:30 -0800 (Thu, 03 Mar 2016)</dd>
</dl>
<h3>Log Message</h3>
<pre>Add Proxy tests for exceptions that depend on an object being non-extensible and having configurable properties
https://bugs.webkit.org/show_bug.cgi?id=154745
Reviewed by Geoffrey Garen.
This patch is mostly an implementation of Proxy.[[OwnPropertyKeys]]
with respect to section 9.5.11 of the ECMAScript spec.
https://tc39.github.io/ecma262/#sec-proxy-object-internal-methods-and-internal-slots-ownpropertykeys
This patch also changes call sites of getOwnPropertyNames and
getPropertyNames to expect that an exception can be thrown.
* dfg/DFGOperations.cpp:
* inspector/JSInjectedScriptHost.cpp:
(Inspector::JSInjectedScriptHost::iteratorEntries):
* interpreter/Interpreter.cpp:
(JSC::Interpreter::execute):
* runtime/IntlObject.cpp:
(JSC::supportedLocales):
* runtime/JSCJSValue.h:
* runtime/JSCJSValueInlines.h:
(JSC::JSValue::get):
(JSC::JSValue::put):
* runtime/JSONObject.cpp:
(JSC::Stringifier::Holder::appendNextProperty):
(JSC::Walker::walk):
* runtime/JSObject.cpp:
(JSC::JSObject::getPropertyNames):
(JSC::JSObject::getGenericPropertyNames):
* runtime/JSObject.h:
(JSC::makeIdentifier):
(JSC::createListFromArrayLike):
* runtime/JSPropertyNameEnumerator.h:
(JSC::propertyNameEnumerator):
* runtime/JSPropertyNameIterator.cpp:
(JSC::JSPropertyNameIterator::create):
* runtime/MapConstructor.cpp:
(JSC::constructMap):
* runtime/ObjectConstructor.cpp:
(JSC::defineProperties):
(JSC::objectConstructorSeal):
(JSC::objectConstructorFreeze):
(JSC::objectConstructorIsSealed):
(JSC::objectConstructorIsFrozen):
(JSC::ownPropertyKeys):
* runtime/ProxyObject.cpp:
(JSC::ProxyObject::getOwnPropertySlotByIndex):
(JSC::ProxyObject::deleteProperty):
(JSC::ProxyObject::deletePropertyByIndex):
(JSC::ProxyObject::defineOwnProperty):
(JSC::ProxyObject::performGetOwnPropertyNames):
(JSC::ProxyObject::getOwnPropertyNames):
(JSC::ProxyObject::getOwnNonIndexPropertyNames):
(JSC::ProxyObject::getStructurePropertyNames):
(JSC::ProxyObject::getGenericPropertyNames):
(JSC::ProxyObject::visitChildren):
* runtime/ProxyObject.h:
(JSC::ProxyObject::create):
(JSC::ProxyObject::createStructure):
* runtime/Structure.cpp:
(JSC::Structure::Structure):
(JSC::Structure::add):
(JSC::Structure::getPropertyNamesFromStructure):
(JSC::Structure::checkConsistency):
(JSC::Structure::canCachePropertyNameEnumerator):
(JSC::Structure::canAccessPropertiesQuicklyForEnumeration):
(JSC::Structure::canAccessPropertiesQuickly): Deleted.
* runtime/Structure.h:
* runtime/WeakMapConstructor.cpp:
(JSC::constructWeakMap):
* tests/es6.yaml:
* tests/stress/proxy-own-keys.js: Added.
(assert):
(throw.new.Error.let.handler.ownKeys):
(throw.new.Error):
(assert.let.handler.get ownKeys):
(assert.let.handler.ownKeys):
(let.handler.ownKeys):
(i.catch):
(shallowEq):
(let.handler.getOwnPropertyDescriptor):
(i.set assert):
(set add):
(set assert):
(set if):</pre>
<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGOperationscpp">trunk/Source/JavaScriptCore/dfg/DFGOperations.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreinspectorJSInjectedScriptHostcpp">trunk/Source/JavaScriptCore/inspector/JSInjectedScriptHost.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreinterpreterInterpretercpp">trunk/Source/JavaScriptCore/interpreter/Interpreter.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeIntlObjectcpp">trunk/Source/JavaScriptCore/runtime/IntlObject.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeJSCJSValueh">trunk/Source/JavaScriptCore/runtime/JSCJSValue.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeJSCJSValueInlinesh">trunk/Source/JavaScriptCore/runtime/JSCJSValueInlines.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeJSONObjectcpp">trunk/Source/JavaScriptCore/runtime/JSONObject.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeJSObjectcpp">trunk/Source/JavaScriptCore/runtime/JSObject.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeJSObjecth">trunk/Source/JavaScriptCore/runtime/JSObject.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeJSPropertyNameEnumeratorh">trunk/Source/JavaScriptCore/runtime/JSPropertyNameEnumerator.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeJSPropertyNameIteratorcpp">trunk/Source/JavaScriptCore/runtime/JSPropertyNameIterator.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeMapConstructorcpp">trunk/Source/JavaScriptCore/runtime/MapConstructor.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeObjectConstructorcpp">trunk/Source/JavaScriptCore/runtime/ObjectConstructor.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeProxyObjectcpp">trunk/Source/JavaScriptCore/runtime/ProxyObject.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeProxyObjecth">trunk/Source/JavaScriptCore/runtime/ProxyObject.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeStructurecpp">trunk/Source/JavaScriptCore/runtime/Structure.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeStructureh">trunk/Source/JavaScriptCore/runtime/Structure.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeWeakMapConstructorcpp">trunk/Source/JavaScriptCore/runtime/WeakMapConstructor.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoretestses6yaml">trunk/Source/JavaScriptCore/tests/es6.yaml</a></li>
</ul>
<h3>Added Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoretestsstressproxyownkeysjs">trunk/Source/JavaScriptCore/tests/stress/proxy-own-keys.js</a></li>
</ul>
</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (197538 => 197539)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2016-03-04 01:58:34 UTC (rev 197538)
+++ trunk/Source/JavaScriptCore/ChangeLog        2016-03-04 02:25:30 UTC (rev 197539)
</span><span class="lines">@@ -1,3 +1,91 @@
</span><ins>+2016-03-03 Saam Barati <sbarati@apple.com>
+
+ Add Proxy tests for exceptions that depend on an object being non-extensible and having configurable properties
+ https://bugs.webkit.org/show_bug.cgi?id=154745
+
+ Reviewed by Geoffrey Garen.
+
+ This patch is mostly an implementation of Proxy.[[OwnPropertyKeys]]
+ with respect to section 9.5.11 of the ECMAScript spec.
+ https://tc39.github.io/ecma262/#sec-proxy-object-internal-methods-and-internal-slots-ownpropertykeys
+
+ This patch also changes call sites of getOwnPropertyNames and
+ getPropertyNames to expect that an exception can be thrown.
+
+ * dfg/DFGOperations.cpp:
+ * inspector/JSInjectedScriptHost.cpp:
+ (Inspector::JSInjectedScriptHost::iteratorEntries):
+ * interpreter/Interpreter.cpp:
+ (JSC::Interpreter::execute):
+ * runtime/IntlObject.cpp:
+ (JSC::supportedLocales):
+ * runtime/JSCJSValue.h:
+ * runtime/JSCJSValueInlines.h:
+ (JSC::JSValue::get):
+ (JSC::JSValue::put):
+ * runtime/JSONObject.cpp:
+ (JSC::Stringifier::Holder::appendNextProperty):
+ (JSC::Walker::walk):
+ * runtime/JSObject.cpp:
+ (JSC::JSObject::getPropertyNames):
+ (JSC::JSObject::getGenericPropertyNames):
+ * runtime/JSObject.h:
+ (JSC::makeIdentifier):
+ (JSC::createListFromArrayLike):
+ * runtime/JSPropertyNameEnumerator.h:
+ (JSC::propertyNameEnumerator):
+ * runtime/JSPropertyNameIterator.cpp:
+ (JSC::JSPropertyNameIterator::create):
+ * runtime/MapConstructor.cpp:
+ (JSC::constructMap):
+ * runtime/ObjectConstructor.cpp:
+ (JSC::defineProperties):
+ (JSC::objectConstructorSeal):
+ (JSC::objectConstructorFreeze):
+ (JSC::objectConstructorIsSealed):
+ (JSC::objectConstructorIsFrozen):
+ (JSC::ownPropertyKeys):
+ * runtime/ProxyObject.cpp:
+ (JSC::ProxyObject::getOwnPropertySlotByIndex):
+ (JSC::ProxyObject::deleteProperty):
+ (JSC::ProxyObject::deletePropertyByIndex):
+ (JSC::ProxyObject::defineOwnProperty):
+ (JSC::ProxyObject::performGetOwnPropertyNames):
+ (JSC::ProxyObject::getOwnPropertyNames):
+ (JSC::ProxyObject::getOwnNonIndexPropertyNames):
+ (JSC::ProxyObject::getStructurePropertyNames):
+ (JSC::ProxyObject::getGenericPropertyNames):
+ (JSC::ProxyObject::visitChildren):
+ * runtime/ProxyObject.h:
+ (JSC::ProxyObject::create):
+ (JSC::ProxyObject::createStructure):
+ * runtime/Structure.cpp:
+ (JSC::Structure::Structure):
+ (JSC::Structure::add):
+ (JSC::Structure::getPropertyNamesFromStructure):
+ (JSC::Structure::checkConsistency):
+ (JSC::Structure::canCachePropertyNameEnumerator):
+ (JSC::Structure::canAccessPropertiesQuicklyForEnumeration):
+ (JSC::Structure::canAccessPropertiesQuickly): Deleted.
+ * runtime/Structure.h:
+ * runtime/WeakMapConstructor.cpp:
+ (JSC::constructWeakMap):
+ * tests/es6.yaml:
+ * tests/stress/proxy-own-keys.js: Added.
+ (assert):
+ (throw.new.Error.let.handler.ownKeys):
+ (throw.new.Error):
+ (assert.let.handler.get ownKeys):
+ (assert.let.handler.ownKeys):
+ (let.handler.ownKeys):
+ (i.catch):
+ (shallowEq):
+ (let.handler.getOwnPropertyDescriptor):
+ (i.set assert):
+ (set add):
+ (set assert):
+ (set if):
+
</ins><span class="cx"> 2016-03-03 Keith Miller <keith_miller@apple.com>
</span><span class="cx">
</span><span class="cx"> Array prototype JS builtins should support Symbol.species
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGOperationscpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGOperations.cpp (197538 => 197539)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGOperations.cpp        2016-03-04 01:58:34 UTC (rev 197538)
+++ trunk/Source/JavaScriptCore/dfg/DFGOperations.cpp        2016-03-04 02:25:30 UTC (rev 197539)
</span><span class="lines">@@ -410,7 +410,7 @@
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> // Use this since we know that the value is out of bounds.
</span><del>- return JSValue::encode(JSValue(base).get(exec, index));
</del><ins>+ return JSValue::encode(JSValue(base).get(exec, static_cast<unsigned>(index)));
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> EncodedJSValue JIT_OPERATION operationGetByValArrayInt(ExecState* exec, JSArray* base, int32_t index)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreinspectorJSInjectedScriptHostcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/inspector/JSInjectedScriptHost.cpp (197538 => 197539)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/inspector/JSInjectedScriptHost.cpp        2016-03-04 01:58:34 UTC (rev 197538)
+++ trunk/Source/JavaScriptCore/inspector/JSInjectedScriptHost.cpp        2016-03-04 02:25:30 UTC (rev 197539)
</span><span class="lines">@@ -448,9 +448,11 @@
</span><span class="cx"> iterator = setIterator->clone(exec);
</span><span class="cx"> else if (JSStringIterator* stringIterator = jsDynamicCast<JSStringIterator*>(value))
</span><span class="cx"> iterator = stringIterator->clone(exec);
</span><del>- else if (JSPropertyNameIterator* propertyNameIterator = jsDynamicCast<JSPropertyNameIterator*>(value))
</del><ins>+ else if (JSPropertyNameIterator* propertyNameIterator = jsDynamicCast<JSPropertyNameIterator*>(value)) {
</ins><span class="cx"> iterator = propertyNameIterator->clone(exec);
</span><del>- else
</del><ins>+ if (UNLIKELY(exec->hadException()))
+ return JSValue();
+ } else
</ins><span class="cx"> return jsUndefined();
</span><span class="cx">
</span><span class="cx"> unsigned numberToFetch = 5;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreinterpreterInterpretercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/interpreter/Interpreter.cpp (197538 => 197539)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/interpreter/Interpreter.cpp        2016-03-04 01:58:34 UTC (rev 197538)
+++ trunk/Source/JavaScriptCore/interpreter/Interpreter.cpp        2016-03-04 02:25:30 UTC (rev 197539)
</span><span class="lines">@@ -891,7 +891,7 @@
</span><span class="cx"> continue;
</span><span class="cx"> }
</span><span class="cx"> case JSONPPathEntryTypeLookup: {
</span><del>- baseObject = baseObject.get(callFrame, JSONPPath[i].m_pathIndex);
</del><ins>+ baseObject = baseObject.get(callFrame, static_cast<unsigned>(JSONPPath[i].m_pathIndex));
</ins><span class="cx"> if (callFrame->hadException())
</span><span class="cx"> return jsUndefined();
</span><span class="cx"> continue;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeIntlObjectcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/IntlObject.cpp (197538 => 197539)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/IntlObject.cpp        2016-03-04 01:58:34 UTC (rev 197538)
+++ trunk/Source/JavaScriptCore/runtime/IntlObject.cpp        2016-03-04 02:25:30 UTC (rev 197539)
</span><span class="lines">@@ -944,6 +944,8 @@
</span><span class="cx"> // 7. Let keys be subset.[[OwnPropertyKeys]]().
</span><span class="cx"> PropertyNameArray keys(&state, PropertyNameMode::Strings);
</span><span class="cx"> supportedLocales->getOwnPropertyNames(supportedLocales, &state, keys, EnumerationMode());
</span><ins>+ if (state.hadException())
+ return jsUndefined();
</ins><span class="cx">
</span><span class="cx"> PropertyDescriptor desc;
</span><span class="cx"> desc.setConfigurable(false);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeJSCJSValueh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/JSCJSValue.h (197538 => 197539)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/JSCJSValue.h        2016-03-04 01:58:34 UTC (rev 197538)
+++ trunk/Source/JavaScriptCore/runtime/JSCJSValue.h        2016-03-04 02:25:30 UTC (rev 197539)
</span><span class="lines">@@ -275,6 +275,7 @@
</span><span class="cx"> JSValue get(ExecState*, PropertyName, PropertySlot&) const;
</span><span class="cx"> JSValue get(ExecState*, unsigned propertyName) const;
</span><span class="cx"> JSValue get(ExecState*, unsigned propertyName, PropertySlot&) const;
</span><ins>+ JSValue get(ExecState*, uint64_t propertyName) const;
</ins><span class="cx">
</span><span class="cx"> bool getPropertySlot(ExecState*, PropertyName, PropertySlot&) const;
</span><span class="cx">
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeJSCJSValueInlinesh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/JSCJSValueInlines.h (197538 => 197539)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/JSCJSValueInlines.h        2016-03-04 01:58:34 UTC (rev 197538)
+++ trunk/Source/JavaScriptCore/runtime/JSCJSValueInlines.h        2016-03-04 02:25:30 UTC (rev 197539)
</span><span class="lines">@@ -778,6 +778,13 @@
</span><span class="cx"> return jsUndefined();
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+ALWAYS_INLINE JSValue JSValue::get(ExecState* exec, uint64_t propertyName) const
+{
+ if (LIKELY(propertyName <= std::numeric_limits<unsigned>::max()))
+ return get(exec, static_cast<unsigned>(propertyName));
+ return get(exec, Identifier::from(exec, static_cast<double>(propertyName)));
+}
+
</ins><span class="cx"> inline void JSValue::put(ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot)
</span><span class="cx"> {
</span><span class="cx"> if (UNLIKELY(!isCell())) {
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeJSONObjectcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/JSONObject.cpp (197538 => 197539)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/JSONObject.cpp        2016-03-04 01:58:34 UTC (rev 197538)
+++ trunk/Source/JavaScriptCore/runtime/JSONObject.cpp        2016-03-04 02:25:30 UTC (rev 197539)
</span><span class="lines">@@ -439,6 +439,8 @@
</span><span class="cx"> else {
</span><span class="cx"> PropertyNameArray objectPropertyNames(exec, PropertyNameMode::Strings);
</span><span class="cx"> m_object->methodTable()->getOwnPropertyNames(m_object.get(), exec, objectPropertyNames, EnumerationMode());
</span><ins>+ if (UNLIKELY(exec->hadException()))
+ return false;
</ins><span class="cx"> m_propertyNames = objectPropertyNames.releaseData();
</span><span class="cx"> }
</span><span class="cx"> m_size = m_propertyNames->propertyNameVector().size();
</span><span class="lines">@@ -656,6 +658,8 @@
</span><span class="cx"> indexStack.append(0);
</span><span class="cx"> propertyStack.append(PropertyNameArray(m_exec, PropertyNameMode::Strings));
</span><span class="cx"> object->methodTable()->getOwnPropertyNames(object, m_exec, propertyStack.last(), EnumerationMode());
</span><ins>+ if (UNLIKELY(m_exec->hadException()))
+ return jsNull();
</ins><span class="cx"> }
</span><span class="cx"> objectStartVisitMember:
</span><span class="cx"> FALLTHROUGH;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeJSObjectcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/JSObject.cpp (197538 => 197539)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/JSObject.cpp        2016-03-04 01:58:34 UTC (rev 197538)
+++ trunk/Source/JavaScriptCore/runtime/JSObject.cpp        2016-03-04 02:25:30 UTC (rev 197539)
</span><span class="lines">@@ -1591,6 +1591,8 @@
</span><span class="cx"> void JSObject::getPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
</span><span class="cx"> {
</span><span class="cx"> object->methodTable(exec->vm())->getOwnPropertyNames(object, exec, propertyNames, mode);
</span><ins>+ if (UNLIKELY(exec->hadException()))
+ return;
</ins><span class="cx">
</span><span class="cx"> if (object->prototype().isNull())
</span><span class="cx"> return;
</span><span class="lines">@@ -1603,6 +1605,8 @@
</span><span class="cx"> break;
</span><span class="cx"> }
</span><span class="cx"> prototype->methodTable(vm)->getOwnPropertyNames(prototype, exec, propertyNames, mode);
</span><ins>+ if (UNLIKELY(exec->hadException()))
+ return;
</ins><span class="cx"> JSValue nextProto = prototype->prototype();
</span><span class="cx"> if (nextProto.isNull())
</span><span class="cx"> break;
</span><span class="lines">@@ -3025,6 +3029,8 @@
</span><span class="cx"> {
</span><span class="cx"> VM& vm = exec->vm();
</span><span class="cx"> object->methodTable(vm)->getOwnPropertyNames(object, exec, propertyNames, EnumerationMode(mode, JSObjectPropertiesMode::Exclude));
</span><ins>+ if (UNLIKELY(exec->hadException()))
+ return;
</ins><span class="cx">
</span><span class="cx"> if (object->prototype().isNull())
</span><span class="cx"> return;
</span><span class="lines">@@ -3036,6 +3042,8 @@
</span><span class="cx"> break;
</span><span class="cx"> }
</span><span class="cx"> prototype->methodTable(vm)->getOwnPropertyNames(prototype, exec, propertyNames, mode);
</span><ins>+ if (UNLIKELY(exec->hadException()))
+ return;
</ins><span class="cx"> JSValue nextProto = prototype->prototype();
</span><span class="cx"> if (nextProto.isNull())
</span><span class="cx"> break;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeJSObjecth"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/JSObject.h (197538 => 197539)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/JSObject.h        2016-03-04 01:58:34 UTC (rev 197538)
+++ trunk/Source/JavaScriptCore/runtime/JSObject.h        2016-03-04 02:25:30 UTC (rev 197539)
</span><span class="lines">@@ -41,6 +41,7 @@
</span><span class="cx"> #include "PropertyStorage.h"
</span><span class="cx"> #include "PutDirectIndexMode.h"
</span><span class="cx"> #include "PutPropertySlot.h"
</span><ins>+#include "RuntimeType.h"
</ins><span class="cx">
</span><span class="cx"> #include "Structure.h"
</span><span class="cx"> #include "VM.h"
</span><span class="lines">@@ -1533,6 +1534,37 @@
</span><span class="cx"> return name;
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+// Section 7.3.17 of the spec.
+template <typename AddFunction> // Add function should have a type like: (JSValue, RuntimeType) -> bool
+void createListFromArrayLike(ExecState* exec, JSValue arrayLikeValue, RuntimeTypeMask legalTypesFilter, const String& errorMessage, AddFunction addFunction)
+{
+ VM& vm = exec->vm();
+ Vector<JSValue> result;
+ JSValue lengthProperty = arrayLikeValue.get(exec, exec->vm().propertyNames->length);
+ if (vm.exception())
+ return;
+ double lengthAsDouble = lengthProperty.toLength(exec);
+ if (vm.exception())
+ return;
+ RELEASE_ASSERT(lengthAsDouble >= 0.0 && lengthAsDouble == std::trunc(lengthAsDouble));
+ uint64_t length = static_cast<uint64_t>(lengthAsDouble);
+ for (uint64_t index = 0; index < length; index++) {
+ JSValue next = arrayLikeValue.get(exec, index);
+ if (vm.exception())
+ return;
+
+ RuntimeType type = runtimeTypeForValue(next);
+ if (!(type & legalTypesFilter)) {
+ throwTypeError(exec, errorMessage);
+ return;
+ }
+
+ bool exitEarly = addFunction(next, type);
+ if (exitEarly)
+ return;
+ }
+}
+
</ins><span class="cx"> bool validateAndApplyPropertyDescriptor(ExecState*, JSObject*, PropertyName, bool isExtensible,
</span><span class="cx"> const PropertyDescriptor& descriptor, bool isCurrentDefined, const PropertyDescriptor& current, bool throwException);
</span><span class="cx">
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeJSPropertyNameEnumeratorh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/JSPropertyNameEnumerator.h (197538 => 197539)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/JSPropertyNameEnumerator.h        2016-03-04 01:58:34 UTC (rev 197538)
+++ trunk/Source/JavaScriptCore/runtime/JSPropertyNameEnumerator.h        2016-03-04 02:25:30 UTC (rev 197539)
</span><span class="lines">@@ -117,17 +117,21 @@
</span><span class="cx">
</span><span class="cx"> PropertyNameArray propertyNames(exec, PropertyNameMode::Strings);
</span><span class="cx">
</span><del>- if (structure->canAccessPropertiesQuickly() && indexedLength == base->getArrayLength()) {
</del><ins>+ if (structure->canAccessPropertiesQuicklyForEnumeration() && indexedLength == base->getArrayLength()) {
</ins><span class="cx"> base->methodTable(vm)->getStructurePropertyNames(base, exec, propertyNames, EnumerationMode());
</span><ins>+ ASSERT(!exec->hadException());
</ins><span class="cx">
</span><span class="cx"> numberStructureProperties = propertyNames.size();
</span><span class="cx">
</span><span class="cx"> base->methodTable(vm)->getGenericPropertyNames(base, exec, propertyNames, EnumerationMode());
</span><ins>+ ASSERT(!exec->hadException());
</ins><span class="cx"> } else {
</span><span class="cx"> // Generic property names vector contains all indexed property names.
</span><span class="cx"> // So disable indexed property enumeration phase by setting |indexedLength| to 0.
</span><span class="cx"> indexedLength = 0;
</span><span class="cx"> base->methodTable(vm)->getPropertyNames(base, exec, propertyNames, EnumerationMode());
</span><ins>+ if (UNLIKELY(exec->hadException()))
+ return nullptr;
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> ASSERT(propertyNames.size() < UINT32_MAX);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeJSPropertyNameIteratorcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/JSPropertyNameIterator.cpp (197538 => 197539)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/JSPropertyNameIterator.cpp        2016-03-04 01:58:34 UTC (rev 197538)
+++ trunk/Source/JavaScriptCore/runtime/JSPropertyNameIterator.cpp        2016-03-04 02:25:30 UTC (rev 197539)
</span><span class="lines">@@ -59,7 +59,10 @@
</span><span class="cx">
</span><span class="cx"> JSPropertyNameIterator* JSPropertyNameIterator::create(ExecState* exec, Structure* structure, JSObject* iteratedObject)
</span><span class="cx"> {
</span><del>- return JSPropertyNameIterator::create(exec, structure, iteratedObject, propertyNameEnumerator(exec, iteratedObject));
</del><ins>+ JSPropertyNameEnumerator* enumerator = propertyNameEnumerator(exec, iteratedObject);
+ if (UNLIKELY(exec->hadException()))
+ return nullptr;
+ return JSPropertyNameIterator::create(exec, structure, iteratedObject, enumerator);
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> JSPropertyNameIterator* JSPropertyNameIterator::create(ExecState* exec, Structure* structure, JSObject* iteratedObject, JSPropertyNameEnumerator* enumerator)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeMapConstructorcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/MapConstructor.cpp (197538 => 197539)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/MapConstructor.cpp        2016-03-04 01:58:34 UTC (rev 197538)
+++ trunk/Source/JavaScriptCore/runtime/MapConstructor.cpp        2016-03-04 02:25:30 UTC (rev 197539)
</span><span class="lines">@@ -108,13 +108,13 @@
</span><span class="cx"> return JSValue::encode(jsUndefined());
</span><span class="cx"> }
</span><span class="cx">
</span><del>- JSValue key = nextItem.get(exec, 0);
</del><ins>+ JSValue key = nextItem.get(exec, static_cast<unsigned>(0));
</ins><span class="cx"> if (exec->hadException()) {
</span><span class="cx"> iteratorClose(exec, iterator);
</span><span class="cx"> return JSValue::encode(jsUndefined());
</span><span class="cx"> }
</span><span class="cx">
</span><del>- JSValue value = nextItem.get(exec, 1);
</del><ins>+ JSValue value = nextItem.get(exec, static_cast<unsigned>(1));
</ins><span class="cx"> if (exec->hadException()) {
</span><span class="cx"> iteratorClose(exec, iterator);
</span><span class="cx"> return JSValue::encode(jsUndefined());
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeObjectConstructorcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/ObjectConstructor.cpp (197538 => 197539)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/ObjectConstructor.cpp        2016-03-04 01:58:34 UTC (rev 197538)
+++ trunk/Source/JavaScriptCore/runtime/ObjectConstructor.cpp        2016-03-04 02:25:30 UTC (rev 197539)
</span><span class="lines">@@ -408,6 +408,8 @@
</span><span class="cx"> {
</span><span class="cx"> PropertyNameArray propertyNames(exec, PropertyNameMode::StringsAndSymbols);
</span><span class="cx"> asObject(properties)->methodTable(exec->vm())->getOwnPropertyNames(asObject(properties), exec, propertyNames, EnumerationMode(DontEnumPropertiesMode::Exclude));
</span><ins>+ if (UNLIKELY(exec->hadException()))
+ return jsNull();
</ins><span class="cx"> size_t numProperties = propertyNames.size();
</span><span class="cx"> Vector<PropertyDescriptor> descriptors;
</span><span class="cx"> MarkedArgumentBuffer markBuffer;
</span><span class="lines">@@ -478,6 +480,8 @@
</span><span class="cx"> // 2. For each named own property name P of O,
</span><span class="cx"> PropertyNameArray properties(exec, PropertyNameMode::StringsAndSymbols);
</span><span class="cx"> object->methodTable(exec->vm())->getOwnPropertyNames(object, exec, properties, EnumerationMode(DontEnumPropertiesMode::Include));
</span><ins>+ if (UNLIKELY(exec->hadException()))
+ return JSValue::encode(obj);
</ins><span class="cx"> PropertyNameArray::const_iterator end = properties.end();
</span><span class="cx"> for (PropertyNameArray::const_iterator iter = properties.begin(); iter != end; ++iter) {
</span><span class="cx"> Identifier propertyName = *iter;
</span><span class="lines">@@ -514,6 +518,8 @@
</span><span class="cx"> // 2. For each named own property name P of O,
</span><span class="cx"> PropertyNameArray properties(exec, PropertyNameMode::StringsAndSymbols);
</span><span class="cx"> object->methodTable(exec->vm())->getOwnPropertyNames(object, exec, properties, EnumerationMode(DontEnumPropertiesMode::Include));
</span><ins>+ if (UNLIKELY(exec->hadException()))
+ return object;
</ins><span class="cx"> PropertyNameArray::const_iterator end = properties.end();
</span><span class="cx"> for (PropertyNameArray::const_iterator iter = properties.begin(); iter != end; ++iter) {
</span><span class="cx"> Identifier propertyName = *iter;
</span><span class="lines">@@ -580,6 +586,8 @@
</span><span class="cx"> // 2. For each named own property name P of O,
</span><span class="cx"> PropertyNameArray properties(exec, PropertyNameMode::StringsAndSymbols);
</span><span class="cx"> object->methodTable(exec->vm())->getOwnPropertyNames(object, exec, properties, EnumerationMode(DontEnumPropertiesMode::Include));
</span><ins>+ if (UNLIKELY(exec->hadException()))
+ return JSValue::encode(JSValue());
</ins><span class="cx"> PropertyNameArray::const_iterator end = properties.end();
</span><span class="cx"> for (PropertyNameArray::const_iterator iter = properties.begin(); iter != end; ++iter) {
</span><span class="cx"> Identifier propertyName = *iter;
</span><span class="lines">@@ -616,6 +624,8 @@
</span><span class="cx"> // 2. For each named own property name P of O,
</span><span class="cx"> PropertyNameArray properties(exec, PropertyNameMode::StringsAndSymbols);
</span><span class="cx"> object->methodTable(exec->vm())->getOwnPropertyNames(object, exec, properties, EnumerationMode(DontEnumPropertiesMode::Include));
</span><ins>+ if (UNLIKELY(exec->hadException()))
+ return JSValue::encode(JSValue());
</ins><span class="cx"> PropertyNameArray::const_iterator end = properties.end();
</span><span class="cx"> for (PropertyNameArray::const_iterator iter = properties.begin(); iter != end; ++iter) {
</span><span class="cx"> Identifier propertyName = *iter;
</span><span class="lines">@@ -661,6 +671,8 @@
</span><span class="cx"> {
</span><span class="cx"> PropertyNameArray properties(exec, propertyNameMode);
</span><span class="cx"> object->methodTable(exec->vm())->getOwnPropertyNames(object, exec, properties, EnumerationMode(dontEnumPropertiesMode));
</span><ins>+ if (exec->hadException())
+ return nullptr;
</ins><span class="cx">
</span><span class="cx"> JSArray* keys = constructEmptyArray(exec, 0);
</span><span class="cx">
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeProxyObjectcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/ProxyObject.cpp (197538 => 197539)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/ProxyObject.cpp        2016-03-04 01:58:34 UTC (rev 197538)
+++ trunk/Source/JavaScriptCore/runtime/ProxyObject.cpp        2016-03-04 02:25:30 UTC (rev 197539)
</span><span class="lines">@@ -341,8 +341,6 @@
</span><span class="cx"> {
</span><span class="cx"> ProxyObject* thisObject = jsCast<ProxyObject*>(object);
</span><span class="cx"> Identifier ident = Identifier::from(exec, propertyName);
</span><del>- if (exec->hadException())
- return false;
</del><span class="cx"> return thisObject->getOwnPropertySlotCommon(exec, ident.impl(), slot);
</span><span class="cx"> }
</span><span class="cx">
</span><span class="lines">@@ -587,7 +585,7 @@
</span><span class="cx"> {
</span><span class="cx"> ProxyObject* thisObject = jsCast<ProxyObject*>(cell);
</span><span class="cx"> auto performDefaultDelete = [&] () -> bool {
</span><del>- JSObject* target = jsCast<JSObject*>(thisObject->target());
</del><ins>+ JSObject* target = thisObject->target();
</ins><span class="cx"> return target->methodTable(exec->vm())->deleteProperty(target, exec, propertyName);
</span><span class="cx"> };
</span><span class="cx"> return thisObject->performDelete(exec, propertyName, performDefaultDelete);
</span><span class="lines">@@ -597,10 +595,8 @@
</span><span class="cx"> {
</span><span class="cx"> ProxyObject* thisObject = jsCast<ProxyObject*>(cell);
</span><span class="cx"> Identifier ident = Identifier::from(exec, propertyName);
</span><del>- if (exec->hadException())
- return false;
</del><span class="cx"> auto performDefaultDelete = [&] () -> bool {
</span><del>- JSObject* target = jsCast<JSObject*>(thisObject->target());
</del><ins>+ JSObject* target = thisObject->target();
</ins><span class="cx"> return target->methodTable(exec->vm())->deletePropertyByIndex(target, exec, propertyName);
</span><span class="cx"> };
</span><span class="cx"> return thisObject->performDelete(exec, ident.impl(), performDefaultDelete);
</span><span class="lines">@@ -801,6 +797,164 @@
</span><span class="cx"> return thisObject->performDefineOwnProperty(exec, propertyName, descriptor, shouldThrow);
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+void ProxyObject::performGetOwnPropertyNames(ExecState* exec, PropertyNameArray& trapResult, EnumerationMode enumerationMode)
+{
+ VM& vm = exec->vm();
+ JSValue handlerValue = this->handler();
+ if (handlerValue.isNull()) {
+ throwVMTypeError(exec, ASCIILiteral("Proxy 'handler' is null. It should be an Object."));
+ return;
+ }
+
+ JSObject* handler = jsCast<JSObject*>(handlerValue);
+ CallData callData;
+ CallType callType;
+ JSValue ownKeysMethod = handler->getMethod(exec, callData, callType, makeIdentifier(vm, "ownKeys"), ASCIILiteral("'ownKeys' property of a Proxy's handler should be callable."));
+ if (exec->hadException())
+ return;
+ JSObject* target = this->target();
+ if (ownKeysMethod.isUndefined()) {
+ target->methodTable(exec->vm())->getOwnPropertyNames(target, exec, trapResult, enumerationMode);
+ return;
+ }
+
+ MarkedArgumentBuffer arguments;
+ arguments.append(target);
+ JSValue arrayLikeObject = call(exec, ownKeysMethod, callType, callData, handler, arguments);
+ if (exec->hadException())
+ return;
+
+ PropertyNameMode propertyNameMode = trapResult.mode();
+ RuntimeTypeMask resultFilter = 0;
+ switch (propertyNameMode) {
+ case PropertyNameMode::Symbols:
+ resultFilter = TypeSymbol;
+ break;
+ case PropertyNameMode::Strings:
+ resultFilter = TypeString;
+ break;
+ case PropertyNameMode::StringsAndSymbols:
+ resultFilter = TypeSymbol | TypeString;
+ break;
+ }
+ ASSERT(resultFilter);
+ RuntimeTypeMask dontThrowAnExceptionTypeFilter = TypeString | TypeSymbol;
+ HashMap<UniquedStringImpl*, unsigned> uncheckedResultKeys;
+ unsigned totalSize = 0;
+
+ auto addPropName = [&] (JSValue value, RuntimeType type) -> bool {
+ static const bool doExitEarly = true;
+ static const bool dontExitEarly = false;
+
+ if (!(type & resultFilter))
+ return dontExitEarly;
+
+ Identifier ident = value.toPropertyKey(exec);
+ if (exec->hadException())
+ return doExitEarly;
+
+ ++uncheckedResultKeys.add(ident.impl(), 0).iterator->value;
+ ++totalSize;
+
+ trapResult.add(ident.impl());
+
+ return dontExitEarly;
+ };
+
+ createListFromArrayLike(exec, arrayLikeObject, dontThrowAnExceptionTypeFilter, ASCIILiteral("Proxy handler's 'ownKeys' method must return a array-like object containing only Strings and Symbols."), addPropName);
+ if (exec->hadException())
+ return;
+
+ bool targetIsExensible = target->isExtensible(exec);
+
+ PropertyNameArray targetKeys(&vm, propertyNameMode);
+ target->methodTable(vm)->getOwnPropertyNames(target, exec, targetKeys, enumerationMode);
+ if (exec->hadException())
+ return;
+ Vector<UniquedStringImpl*> targetConfigurableKeys;
+ Vector<UniquedStringImpl*> targetNonConfigurableKeys;
+ for (const Identifier& ident : targetKeys) {
+ PropertyDescriptor descriptor;
+ bool isPropertyDefined = target->getOwnPropertyDescriptor(exec, ident.impl(), descriptor);
+ if (exec->hadException())
+ return;
+ if (isPropertyDefined && !descriptor.configurable())
+ targetNonConfigurableKeys.append(ident.impl());
+ else
+ targetConfigurableKeys.append(ident.impl());
+ }
+
+ auto removeIfContainedInUncheckedResultKeys = [&] (UniquedStringImpl* impl) -> bool {
+ static const bool isContainedIn = true;
+ static const bool isNotContainedIn = false;
+
+ auto iter = uncheckedResultKeys.find(impl);
+ if (iter == uncheckedResultKeys.end())
+ return isNotContainedIn;
+
+ unsigned& count = iter->value;
+ if (count == 0)
+ return isNotContainedIn;
+
+ --count;
+ --totalSize;
+ return isContainedIn;
+ };
+
+ for (UniquedStringImpl* impl : targetNonConfigurableKeys) {
+ bool contains = removeIfContainedInUncheckedResultKeys(impl);
+ if (!contains) {
+ throwVMTypeError(exec, makeString("Proxy object's 'target' has the non-configurable property '", String(impl), "' that was not in the result from the 'ownKeys' trap."));
+ return;
+ }
+ }
+
+ if (targetIsExensible)
+ return;
+
+ for (UniquedStringImpl* impl : targetConfigurableKeys) {
+ bool contains = removeIfContainedInUncheckedResultKeys(impl);
+ if (!contains) {
+ throwVMTypeError(exec, makeString("Proxy object's non-extensible 'target' has configurable property '", String(impl), "' that was not in the result from the 'ownKeys' trap."));
+ return;
+ }
+ }
+
+#ifndef NDEBUG
+ unsigned sum = 0;
+ for (unsigned keyCount : uncheckedResultKeys.values())
+ sum += keyCount;
+ ASSERT(sum == totalSize);
+#endif
+
+ if (totalSize) {
+ throwVMTypeError(exec, ASCIILiteral("Proxy handler's 'ownKeys' method returned a key that was not present in its target or it returned duplicate keys."));
+ return;
+ }
+}
+
+void ProxyObject::getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNameArray, EnumerationMode enumerationMode)
+{
+ ProxyObject* thisObject = jsCast<ProxyObject*>(object);
+ thisObject->performGetOwnPropertyNames(exec, propertyNameArray, enumerationMode);
+}
+
+void ProxyObject::getOwnNonIndexPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode)
+{
+ RELEASE_ASSERT_NOT_REACHED();
+}
+
+void ProxyObject::getStructurePropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode)
+{
+ // We should always go down the getOwnPropertyNames path.
+ RELEASE_ASSERT_NOT_REACHED();
+}
+
+void ProxyObject::getGenericPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode)
+{
+ RELEASE_ASSERT_NOT_REACHED();
+}
+
</ins><span class="cx"> void ProxyObject::visitChildren(JSCell* cell, SlotVisitor& visitor)
</span><span class="cx"> {
</span><span class="cx"> ProxyObject* thisObject = jsCast<ProxyObject*>(cell);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeProxyObjecth"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/ProxyObject.h (197538 => 197539)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/ProxyObject.h        2016-03-04 01:58:34 UTC (rev 197538)
+++ trunk/Source/JavaScriptCore/runtime/ProxyObject.h        2016-03-04 02:25:30 UTC (rev 197539)
</span><span class="lines">@@ -28,6 +28,7 @@
</span><span class="cx">
</span><span class="cx"> #include "JSGlobalObject.h"
</span><span class="cx"> #include "JSObject.h"
</span><ins>+#include "RuntimeType.h"
</ins><span class="cx">
</span><span class="cx"> namespace JSC {
</span><span class="cx">
</span><span class="lines">@@ -35,7 +36,9 @@
</span><span class="cx"> public:
</span><span class="cx"> typedef JSNonFinalObject Base;
</span><span class="cx">
</span><del>- const static unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot | TypeOfShouldCallGetCallData | InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero;
</del><ins>+ // We lie an say we override getPropertyNames() because it prevents
+ // property name enumeration caching.
+ const static unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot | TypeOfShouldCallGetCallData | InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | OverridesGetPropertyNames;
</ins><span class="cx">
</span><span class="cx"> static ProxyObject* create(ExecState* exec, Structure* structure, JSValue target, JSValue handler)
</span><span class="cx"> {
</span><span class="lines">@@ -47,7 +50,11 @@
</span><span class="cx">
</span><span class="cx"> static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
</span><span class="cx"> {
</span><del>- return Structure::create(vm, globalObject, prototype, TypeInfo(ProxyObjectType, StructureFlags), info(), NonArray | MayHaveIndexedAccessors);
</del><ins>+ Structure* result = Structure::create(vm, globalObject, prototype, TypeInfo(ProxyObjectType, StructureFlags), info(), NonArray | MayHaveIndexedAccessors);
+ result->setIsQuickPropertyAccessAllowedForEnumeration(false);
+ RELEASE_ASSERT(!result->canAccessPropertiesQuicklyForEnumeration());
+ RELEASE_ASSERT(!result->canCachePropertyNameEnumerator());
+ return result;
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> DECLARE_EXPORT_INFO;
</span><span class="lines">@@ -72,6 +79,10 @@
</span><span class="cx"> static bool preventExtensions(JSObject*, ExecState*);
</span><span class="cx"> static bool isExtensible(JSObject*, ExecState*);
</span><span class="cx"> static bool defineOwnProperty(JSObject*, ExecState*, PropertyName, const PropertyDescriptor&, bool shouldThrow);
</span><ins>+ static void getOwnPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
+ static NO_RETURN_DUE_TO_CRASH void getOwnNonIndexPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
+ static NO_RETURN_DUE_TO_CRASH void getStructurePropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
+ static NO_RETURN_DUE_TO_CRASH void getGenericPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
</ins><span class="cx"> static void visitChildren(JSCell*, SlotVisitor&);
</span><span class="cx">
</span><span class="cx"> bool getOwnPropertySlotCommon(ExecState*, PropertyName, PropertySlot&);
</span><span class="lines">@@ -84,6 +95,7 @@
</span><span class="cx"> bool performPreventExtensions(ExecState*);
</span><span class="cx"> bool performIsExtensible(ExecState*);
</span><span class="cx"> bool performDefineOwnProperty(ExecState*, PropertyName, const PropertyDescriptor&, bool shouldThrow);
</span><ins>+ void performGetOwnPropertyNames(ExecState*, PropertyNameArray&, EnumerationMode);
</ins><span class="cx">
</span><span class="cx"> WriteBarrier<JSObject> m_target;
</span><span class="cx"> WriteBarrier<Unknown> m_handler;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeStructurecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/Structure.cpp (197538 => 197539)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/Structure.cpp        2016-03-04 01:58:34 UTC (rev 197538)
+++ trunk/Source/JavaScriptCore/runtime/Structure.cpp        2016-03-04 02:25:30 UTC (rev 197539)
</span><span class="lines">@@ -201,7 +201,7 @@
</span><span class="cx"> setHasGetterSetterProperties(classInfo->hasStaticSetterOrReadonlyProperties());
</span><span class="cx"> setHasCustomGetterSetterProperties(false);
</span><span class="cx"> setHasReadOnlyOrGetterSetterPropertiesExcludingProto(classInfo->hasStaticSetterOrReadonlyProperties());
</span><del>- setHasNonEnumerableProperties(false);
</del><ins>+ setIsQuickPropertyAccessAllowedForEnumeration(true);
</ins><span class="cx"> setAttributesInPrevious(0);
</span><span class="cx"> setDidPreventExtensions(false);
</span><span class="cx"> setDidTransition(false);
</span><span class="lines">@@ -233,7 +233,7 @@
</span><span class="cx"> setHasGetterSetterProperties(m_classInfo->hasStaticSetterOrReadonlyProperties());
</span><span class="cx"> setHasCustomGetterSetterProperties(false);
</span><span class="cx"> setHasReadOnlyOrGetterSetterPropertiesExcludingProto(m_classInfo->hasStaticSetterOrReadonlyProperties());
</span><del>- setHasNonEnumerableProperties(false);
</del><ins>+ setIsQuickPropertyAccessAllowedForEnumeration(true);
</ins><span class="cx"> setAttributesInPrevious(0);
</span><span class="cx"> setDidPreventExtensions(false);
</span><span class="cx"> setDidTransition(false);
</span><span class="lines">@@ -264,7 +264,7 @@
</span><span class="cx"> setHasGetterSetterProperties(previous->hasGetterSetterProperties());
</span><span class="cx"> setHasCustomGetterSetterProperties(previous->hasCustomGetterSetterProperties());
</span><span class="cx"> setHasReadOnlyOrGetterSetterPropertiesExcludingProto(previous->hasReadOnlyOrGetterSetterPropertiesExcludingProto());
</span><del>- setHasNonEnumerableProperties(previous->hasNonEnumerableProperties());
</del><ins>+ setIsQuickPropertyAccessAllowedForEnumeration(previous->isQuickPropertyAccessAllowedForEnumeration());
</ins><span class="cx"> setAttributesInPrevious(0);
</span><span class="cx"> setDidPreventExtensions(previous->didPreventExtensions());
</span><span class="cx"> setDidTransition(true);
</span><span class="lines">@@ -986,7 +986,7 @@
</span><span class="cx">
</span><span class="cx"> checkConsistency();
</span><span class="cx"> if (attributes & DontEnum)
</span><del>- setHasNonEnumerableProperties(true);
</del><ins>+ setIsQuickPropertyAccessAllowedForEnumeration(false);
</ins><span class="cx">
</span><span class="cx"> auto rep = propertyName.uid();
</span><span class="cx">
</span><span class="lines">@@ -1044,7 +1044,7 @@
</span><span class="cx">
</span><span class="cx"> PropertyTable::iterator end = propertyTable()->end();
</span><span class="cx"> for (PropertyTable::iterator iter = propertyTable()->begin(); iter != end; ++iter) {
</span><del>- ASSERT(hasNonEnumerableProperties() || !(iter->attributes & DontEnum));
</del><ins>+ ASSERT(!isQuickPropertyAccessAllowedForEnumeration() || !(iter->attributes & DontEnum));
</ins><span class="cx"> if (!(iter->attributes & DontEnum) || mode.includeDontEnumProperties()) {
</span><span class="cx"> if (iter->key->isSymbol() && !propertyNames.includeSymbolProperties())
</span><span class="cx"> continue;
</span><span class="lines">@@ -1311,7 +1311,7 @@
</span><span class="cx"> if (!propertyTable())
</span><span class="cx"> return;
</span><span class="cx">
</span><del>- if (!hasNonEnumerableProperties()) {
</del><ins>+ if (isQuickPropertyAccessAllowedForEnumeration()) {
</ins><span class="cx"> PropertyTable::iterator end = propertyTable()->end();
</span><span class="cx"> for (PropertyTable::iterator iter = propertyTable()->begin(); iter != end; ++iter) {
</span><span class="cx"> ASSERT(!(iter->attributes & DontEnum));
</span><span class="lines">@@ -1381,9 +1381,9 @@
</span><span class="cx"> return true;
</span><span class="cx"> }
</span><span class="cx">
</span><del>-bool Structure::canAccessPropertiesQuickly() const
</del><ins>+bool Structure::canAccessPropertiesQuicklyForEnumeration() const
</ins><span class="cx"> {
</span><del>- if (hasNonEnumerableProperties())
</del><ins>+ if (!isQuickPropertyAccessAllowedForEnumeration())
</ins><span class="cx"> return false;
</span><span class="cx"> if (hasGetterSetterProperties())
</span><span class="cx"> return false;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeStructureh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/Structure.h (197538 => 197539)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/Structure.h        2016-03-04 01:58:34 UTC (rev 197538)
+++ trunk/Source/JavaScriptCore/runtime/Structure.h        2016-03-04 02:25:30 UTC (rev 197539)
</span><span class="lines">@@ -377,7 +377,7 @@
</span><span class="cx"> void setCachedPropertyNameEnumerator(VM&, JSPropertyNameEnumerator*);
</span><span class="cx"> JSPropertyNameEnumerator* cachedPropertyNameEnumerator() const;
</span><span class="cx"> bool canCachePropertyNameEnumerator() const;
</span><del>- bool canAccessPropertiesQuickly() const;
</del><ins>+ bool canAccessPropertiesQuicklyForEnumeration() const;
</ins><span class="cx">
</span><span class="cx"> void getPropertyNamesFromStructure(VM&, PropertyNameArray&, EnumerationMode);
</span><span class="cx">
</span><span class="lines">@@ -577,7 +577,7 @@
</span><span class="cx"> DEFINE_BITFIELD(bool, isPinnedPropertyTable, IsPinnedPropertyTable, 1, 2);
</span><span class="cx"> DEFINE_BITFIELD(bool, hasGetterSetterProperties, HasGetterSetterProperties, 1, 3);
</span><span class="cx"> DEFINE_BITFIELD(bool, hasReadOnlyOrGetterSetterPropertiesExcludingProto, HasReadOnlyOrGetterSetterPropertiesExcludingProto, 1, 4);
</span><del>- DEFINE_BITFIELD(bool, hasNonEnumerableProperties, HasNonEnumerableProperties, 1, 5);
</del><ins>+ DEFINE_BITFIELD(bool, isQuickPropertyAccessAllowedForEnumeration, IsQuickPropertyAccessAllowedForEnumeration, 1, 5);
</ins><span class="cx"> DEFINE_BITFIELD(unsigned, attributesInPrevious, AttributesInPrevious, 14, 6);
</span><span class="cx"> DEFINE_BITFIELD(bool, didPreventExtensions, DidPreventExtensions, 1, 20);
</span><span class="cx"> DEFINE_BITFIELD(bool, didTransition, DidTransition, 1, 21);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeWeakMapConstructorcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/WeakMapConstructor.cpp (197538 => 197539)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/WeakMapConstructor.cpp        2016-03-04 01:58:34 UTC (rev 197538)
+++ trunk/Source/JavaScriptCore/runtime/WeakMapConstructor.cpp        2016-03-04 02:25:30 UTC (rev 197539)
</span><span class="lines">@@ -106,13 +106,13 @@
</span><span class="cx"> return JSValue::encode(jsUndefined());
</span><span class="cx"> }
</span><span class="cx">
</span><del>- JSValue key = nextItem.get(exec, 0);
</del><ins>+ JSValue key = nextItem.get(exec, static_cast<unsigned>(0));
</ins><span class="cx"> if (exec->hadException()) {
</span><span class="cx"> iteratorClose(exec, iterator);
</span><span class="cx"> return JSValue::encode(jsUndefined());
</span><span class="cx"> }
</span><span class="cx">
</span><del>- JSValue value = nextItem.get(exec, 1);
</del><ins>+ JSValue value = nextItem.get(exec, static_cast<unsigned>(1));
</ins><span class="cx"> if (exec->hadException()) {
</span><span class="cx"> iteratorClose(exec, iterator);
</span><span class="cx"> return JSValue::encode(jsUndefined());
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoretestses6yaml"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/tests/es6.yaml (197538 => 197539)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/tests/es6.yaml        2016-03-04 01:58:34 UTC (rev 197538)
+++ trunk/Source/JavaScriptCore/tests/es6.yaml        2016-03-04 02:25:30 UTC (rev 197539)
</span><span class="lines">@@ -935,7 +935,7 @@
</span><span class="cx"> - path: es6/Proxy_internal_defineProperty_calls_[[Set]].js
</span><span class="cx"> cmd: runES6 :fail
</span><span class="cx"> - path: es6/Proxy_internal_defineProperty_calls_SetIntegrityLevel.js
</span><del>- cmd: runES6 :fail
</del><ins>+ cmd: runES6 :normal
</ins><span class="cx"> - path: es6/Proxy_internal_deleteProperty_calls_Array.prototype.copyWithin.js
</span><span class="cx"> cmd: runES6 :normal
</span><span class="cx"> - path: es6/Proxy_internal_deleteProperty_calls_Array.prototype.pop.js
</span><span class="lines">@@ -985,9 +985,9 @@
</span><span class="cx"> - path: es6/Proxy_internal_get_calls_JSON.stringify.js
</span><span class="cx"> cmd: runES6 :fail
</span><span class="cx"> - path: es6/Proxy_internal_get_calls_Object.assign.js
</span><del>- cmd: runES6 :fail
</del><ins>+ cmd: runES6 :normal
</ins><span class="cx"> - path: es6/Proxy_internal_get_calls_Object.defineProperties.js
</span><del>- cmd: runES6 :fail
</del><ins>+ cmd: runES6 :normal
</ins><span class="cx"> - path: es6/Proxy_internal_get_calls_Promise_resolve_functions.js
</span><span class="cx"> cmd: runES6 :normal
</span><span class="cx"> - path: es6/Proxy_internal_get_calls_RegExp.prototype.flags.js
</span><span class="lines">@@ -1027,11 +1027,11 @@
</span><span class="cx"> - path: es6/Proxy_internal_getOwnPropertyDescriptor_calls_Object.prototype.hasOwnProperty.js
</span><span class="cx"> cmd: runES6 :normal
</span><span class="cx"> - path: es6/Proxy_internal_ownKeys_calls_SerializeJSONObject.js
</span><del>- cmd: runES6 :fail
</del><ins>+ cmd: runES6 :normal
</ins><span class="cx"> - path: es6/Proxy_internal_ownKeys_calls_SetIntegrityLevel.js
</span><del>- cmd: runES6 :fail
</del><ins>+ cmd: runES6 :normal
</ins><span class="cx"> - path: es6/Proxy_internal_ownKeys_calls_TestIntegrityLevel.js
</span><del>- cmd: runES6 :fail
</del><ins>+ cmd: runES6 :normal
</ins><span class="cx"> - path: es6/Proxy_internal_set_calls_Array.from.js
</span><span class="cx"> cmd: runES6 :normal
</span><span class="cx"> - path: es6/Proxy_internal_set_calls_Array.of.js
</span><span class="lines">@@ -1059,7 +1059,7 @@
</span><span class="cx"> - path: es6/Proxy_JSON.stringify_support.js
</span><span class="cx"> cmd: runES6 :fail
</span><span class="cx"> - path: es6/Proxy_ownKeys_handler.js
</span><del>- cmd: runES6 :fail
</del><ins>+ cmd: runES6 :normal
</ins><span class="cx"> - path: es6/Proxy_preventExtensions_handler.js
</span><span class="cx"> cmd: runES6 :normal
</span><span class="cx"> - path: es6/Proxy_Proxy.revocable.js
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoretestsstressproxyownkeysjs"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/tests/stress/proxy-own-keys.js (0 => 197539)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/tests/stress/proxy-own-keys.js         (rev 0)
+++ trunk/Source/JavaScriptCore/tests/stress/proxy-own-keys.js        2016-03-04 02:25:30 UTC (rev 197539)
</span><span class="lines">@@ -0,0 +1,560 @@
</span><ins>+function assert(b) {
+ if (!b)
+ throw new Error("Bad assertion.");
+}
+
+{
+ let error = null;
+ let target = { };
+ let handler = {
+ ownKeys: function() {
+ error = new Error;
+ throw error;
+ }
+ };
+
+ let proxy = new Proxy(target, handler);
+ for (let i = 0; i < 500; i++) {
+ let threw = false;
+ try {
+ Object.keys(proxy);
+ } catch(e) {
+ threw = true;
+ assert(e === error);
+ }
+ assert(threw);
+ }
+}
+
+{
+ let error = null;
+ let target = { };
+ let handler = {
+ get ownKeys() {
+ error = new Error;
+ throw error;
+ }
+ };
+
+ let proxy = new Proxy(target, handler);
+ for (let i = 0; i < 500; i++) {
+ let threw = false;
+ try {
+ Object.keys(proxy);
+ } catch(e) {
+ threw = true;
+ assert(e === error);
+ }
+ assert(threw);
+ }
+}
+
+{
+ let target = {
+ x: 40
+ };
+ let called = false;
+ let handler = {
+ ownKeys: function(theTarget) {
+ called = true;
+ return ["1", 2, 3];
+ }
+ };
+
+ let proxy = new Proxy(target, handler);
+ for (let i = 0; i < 500; i++) {
+ let threw = false;
+ try {
+ Object.keys(proxy);
+ } catch(e) {
+ threw = true;
+ assert(e.toString() === "TypeError: Proxy handler's 'ownKeys' method must return a array-like object containing only Strings and Symbols.");
+ }
+ assert(threw);
+ assert(called);
+ called = false;
+ }
+}
+
+{
+ let target = { };
+ Object.defineProperty(target, "x", {
+ configurable: false,
+ enumerable: true,
+ value: 400
+ });
+ let called = false;
+ let handler = {
+ ownKeys: function(theTarget) {
+ called = true;
+ return [];
+ }
+ };
+
+ let proxy = new Proxy(target, handler);
+ for (let i = 0; i < 500; i++) {
+ let threw = false;
+ try {
+ Object.keys(proxy);
+ } catch(e) {
+ threw = true;
+ assert(e.toString() === "TypeError: Proxy object's 'target' has the non-configurable property 'x' that was not in the result from the 'ownKeys' trap.");
+ }
+ assert(threw);
+ assert(called);
+ called = false;
+ }
+}
+
+{
+ let target = { };
+ Object.defineProperty(target, "x", {
+ configurable: true,
+ enumerable: true,
+ value: 400
+ });
+ Object.preventExtensions(target);
+ let called = false;
+ let handler = {
+ ownKeys: function(theTarget) {
+ called = true;
+ return [];
+ }
+ };
+
+ let proxy = new Proxy(target, handler);
+ for (let i = 0; i < 500; i++) {
+ let threw = false;
+ try {
+ Object.keys(proxy);
+ } catch(e) {
+ threw = true;
+ assert(e.toString() === "TypeError: Proxy object's non-extensible 'target' has configurable property 'x' that was not in the result from the 'ownKeys' trap.");
+ }
+ assert(threw);
+ assert(called);
+ called = false;
+ }
+}
+
+{
+ let target = { };
+ Object.defineProperty(target, "x", {
+ configurable: true,
+ enumerable: true,
+ value: 400
+ });
+ Object.preventExtensions(target);
+ let called = false;
+ let handler = {
+ ownKeys: function(theTarget) {
+ called = true;
+ return ["x", "y"];
+ }
+ };
+
+ let proxy = new Proxy(target, handler);
+ for (let i = 0; i < 500; i++) {
+ let threw = false;
+ try {
+ Object.keys(proxy);
+ } catch(e) {
+ threw = true;
+ assert(e.toString() === "TypeError: Proxy handler's 'ownKeys' method returned a key that was not present in its target or it returned duplicate keys.");
+ }
+ assert(threw);
+ assert(called);
+ called = false;
+ }
+}
+
+{
+ let target = { };
+ Object.defineProperty(target, "x", {
+ configurable: true,
+ enumerable: true,
+ value: 400
+ });
+ Object.preventExtensions(target);
+ let called = false;
+ let handler = {
+ ownKeys: function(theTarget) {
+ called = true;
+ return ["x", "x"];
+ }
+ };
+
+ let proxy = new Proxy(target, handler);
+ for (let i = 0; i < 500; i++) {
+ let threw = false;
+ try {
+ Object.keys(proxy);
+ } catch(e) {
+ threw = true;
+ assert(e.toString() === "TypeError: Proxy handler's 'ownKeys' method returned a key that was not present in its target or it returned duplicate keys.");
+ }
+ assert(threw);
+ assert(called);
+ called = false;
+ }
+}
+
+{
+ let target = { };
+ let handler = {
+ ownKeys: 45
+ };
+
+ let proxy = new Proxy(target, handler);
+ for (let i = 0; i < 500; i++) {
+ let threw = false;
+ try {
+ Object.keys(proxy);
+ } catch(e) {
+ threw = true;
+ assert(e.toString() === "TypeError: 'ownKeys' property of a Proxy's handler should be callable.");
+ }
+ assert(threw);
+ }
+}
+
+function shallowEq(a, b) {
+ if (a.length !== b.length)
+ return false;
+ for (let i = 0; i < a.length; i++) {
+ if (a[i] !== b[i])
+ return false;
+ }
+
+ return true;
+}
+
+{
+ let target = {
+ x: 40
+ };
+ let called = false;
+ let arr = ["a", "b", "c"];
+ let handler = {
+ ownKeys: function(theTarget) {
+ called = true;
+ return arr;
+ }
+ };
+
+ let proxy = new Proxy(target, handler);
+ for (let i = 0; i < 500; i++) {
+ let result = Object.keys(proxy);
+ assert(result !== arr);
+ assert(shallowEq(result, arr));
+ assert(called);
+ called = false;
+ }
+}
+
+{
+ let target = {
+ x: 40
+ };
+ let called = false;
+ let arr = ["a", "b", "c"];
+ let handler = {
+ ownKeys: function(theTarget) {
+ called = true;
+ return arr;
+ }
+ };
+
+ let proxy = new Proxy(target, handler);
+ for (let i = 0; i < 500; i++) {
+ let result = Reflect.ownKeys(proxy);
+ assert(result !== arr);
+ assert(shallowEq(result, arr));
+ assert(called);
+ called = false;
+ }
+}
+
+{
+ let target = {
+ x: 40
+ };
+ let called = false;
+ let s1 = Symbol();
+ let s2 = Symbol();
+ let arr = ["a", "b", s1, "c", s2];
+ let handler = {
+ ownKeys: function(theTarget) {
+ called = true;
+ return arr;
+ }
+ };
+
+ let proxy = new Proxy(target, handler);
+ for (let i = 0; i < 500; i++) {
+ let result = Object.getOwnPropertySymbols(proxy);
+ assert(shallowEq(result, [s1, s2]));
+ assert(called);
+ called = false;
+ }
+}
+
+{
+ let target = {
+ x: 40
+ };
+ let called = false;
+ let s1 = Symbol();
+ let s2 = Symbol();
+ let arr = ["a", "b", s1, "c", s2];
+ let handler = {
+ ownKeys: function(theTarget) {
+ called = true;
+ return arr;
+ }
+ };
+
+ let proxy = new Proxy(target, handler);
+ for (let i = 0; i < 500; i++) {
+ let result = Object.keys(proxy);
+ assert(shallowEq(result, ["a", "b", "c"]));
+ assert(called);
+ called = false;
+ }
+}
+
+{
+ let target = {
+ x: 40
+ };
+ let called = false;
+ let s1 = Symbol();
+ let s2 = Symbol();
+ let arr = ["a", "b", s1, "c", s2];
+ let handler = {
+ ownKeys: function(theTarget) {
+ called = true;
+ return arr;
+ }
+ };
+
+ let proxy = new Proxy(target, handler);
+ for (let i = 0; i < 500; i++) {
+ let result = Reflect.ownKeys(proxy);
+ assert(shallowEq(result, ["a", "b", "c", s1, s2]));
+ assert(called);
+ called = false;
+ }
+}
+
+{
+ let target = {
+ x: 40
+ };
+ let called = false;
+ let s1 = Symbol();
+ let s2 = Symbol();
+ let arr = ["a", "b", s1, "c", s2];
+ let handler = {
+ getOwnPropertyDescriptor: () => {
+ return { enumerable: true, configurable: true }
+ },
+ ownKeys: function(theTarget) {
+ called = true;
+ return arr;
+ }
+ };
+
+ let proxy = new Proxy(target, handler);
+ for (let i = 0; i < 500; i++) {
+ let set = new Set;
+ for (let p in proxy)
+ set.add(p);
+ assert(set.size === 3);
+ assert(set.has("a"));
+ assert(set.has("b"));
+ assert(set.has("c"));
+ assert(called);
+ called = false;
+ }
+}
+
+{
+ let target = {
+ x: 40
+ };
+ let called = false;
+ let s1 = Symbol();
+ let s2 = Symbol();
+ let arr = ["a", "b", s1, "c", s2];
+ let handler = {
+ getOwnPropertyDescriptor: () => {
+ return { enumerable: true, configurable: true }
+ },
+ ownKeys: function(theTarget) {
+ called = true;
+ return arr;
+ }
+ };
+
+ let proxy = new Proxy(target, handler);
+ for (let i = 0; i < 500; i++) {
+ let set = new Set;
+ for (let p in proxy)
+ set.add(p);
+ if (i === 40) { // Make sure we don't cache the result.
+ arr.push("d");
+ }
+ assert(set.size === i > 40 ? 4 : 3);
+ assert(set.has("a"));
+ assert(set.has("b"));
+ assert(set.has("c"));
+ if (i > 40)
+ assert(set.has("d"));
+ assert(called);
+ called = false;
+ }
+}
+
+{
+ let target = {
+ x: 40
+ };
+ let called = false;
+ let s1 = Symbol();
+ let s2 = Symbol();
+ let arr = ["a", "b", s1, "c", s2];
+ let handler = {
+ getOwnPropertyDescriptor: () => {
+ return { enumerable: true, configurable: true }
+ },
+ ownKeys: function(theTarget) {
+ called = true;
+ return arr;
+ }
+ };
+
+ let proxy = new Proxy(target, handler);
+ let proxyish = Object.create(proxy, {
+ d: { enumerable: true, configurable: true }
+ });
+ for (let i = 0; i < 500; i++) {
+ let set = new Set;
+ for (let p in proxyish)
+ set.add(p);
+ assert(set.size === 4);
+ assert(set.has("a"));
+ assert(set.has("b"));
+ assert(set.has("c"));
+ assert(set.has("d"));
+ assert(called);
+ called = false;
+ }
+}
+
+{
+ let target = {
+ x: 40
+ };
+ let called = false;
+ let s1 = Symbol();
+ let s2 = Symbol();
+ let arr = ["a", "b", s1, "c", s2];
+ let handler = {
+ getOwnPropertyDescriptor: () => {
+ return { enumerable: true, configurable: true }
+ },
+ ownKeys: function(theTarget) {
+ called = true;
+ return arr;
+ }
+ };
+
+ let proxy = new Proxy(target, handler);
+ let proxyish = Object.create(proxy, {
+ d: { enumerable: true, configurable: true }
+ });
+ for (let i = 0; i < 500; i++) {
+ let set = new Set;
+ for (let p in proxyish)
+ set.add(p);
+ assert(set.size === 4);
+ assert(set.has("a"));
+ assert(set.has("b"));
+ assert(set.has("c"));
+ assert(set.has("d"));
+ assert(called);
+ called = false;
+ }
+}
+
+{
+ let called = false;
+ let target = {x: 20, y: 40};
+ let handler = {
+ ownKeys: null
+ };
+
+ let proxy = new Proxy(target, handler);
+ for (let i = 0; i < 500; i++) {
+ let keys = Object.keys(proxy);
+ assert(keys.indexOf("x") !== -1);
+ assert(keys.indexOf("y") !== -1);
+ }
+}
+
+{
+ let called = false;
+ let target = new Proxy({}, {
+ ownKeys: function(theTarget) {
+ called = true;
+ return Reflect.ownKeys(theTarget);
+ }
+ });
+ let s1 = Symbol();
+ let s2 = Symbol();
+ let arr = ["a", "b", s1, "c", s2];
+ let handler = {
+ ownKeys: function(theTarget) {
+ return arr;
+ }
+ };
+
+ let proxy = new Proxy(target, handler);
+ for (let i = 0; i < 500; i++) {
+ let keys = Object.keys(proxy);
+ assert(called);
+ called = false;
+ }
+}
+
+{
+ let error = null;
+ let target = new Proxy({}, {
+ ownKeys: function(theTarget) {
+ error = new Error;
+ throw error;
+ }
+ });
+ let s1 = Symbol();
+ let s2 = Symbol();
+ let arr = ["a", "b", s1, "c", s2];
+ let handler = {
+ ownKeys: function(theTarget) {
+ return arr;
+ }
+ };
+
+ let proxy = new Proxy(target, handler);
+ for (let i = 0; i < 500; i++) {
+ let threw = false;
+ try {
+ Object.keys(proxy);
+ } catch(e) {
+ threw = true;
+ assert(e === error);
+ }
+ assert(threw);
+ error = null;
+ }
+}
</ins></span></pre>
</div>
</div>
</body>
</html>