Log Message
Object.freeze() and seal() should throw if [[PreventExtensions]]() fails. https://bugs.webkit.org/show_bug.cgi?id=163160
Reviewed by Saam Barati. JSTests: * stress/object-freeze-with-proxy-preventExtensions.js: Added. * stress/object-seal-with-proxy-preventExtensions.js: Added. Source/_javascript_Core: See https://tc39.github.io/ecma262/#sec-object.freeze, https://tc39.github.io/ecma262/#sec-object.seal, and https://tc39.github.io/ecma262/#sec-setintegritylevel. We need to call preventExtensions first before proceeding to freeze / seal the object. If preventExtensions fails, we should throw a TypeError. * runtime/ObjectConstructor.cpp: (JSC::setIntegrityLevel): (JSC::objectConstructorSeal): (JSC::objectConstructorFreeze):
Modified Paths
- trunk/JSTests/ChangeLog
- trunk/Source/_javascript_Core/ChangeLog
- trunk/Source/_javascript_Core/runtime/ObjectConstructor.cpp
Added Paths
Diff
Modified: trunk/JSTests/ChangeLog (206947 => 206948)
--- trunk/JSTests/ChangeLog 2016-10-08 02:07:09 UTC (rev 206947)
+++ trunk/JSTests/ChangeLog 2016-10-08 03:20:53 UTC (rev 206948)
@@ -1,3 +1,13 @@
+2016-10-07 Mark Lam <[email protected]>
+
+ Object.freeze() and seal() should throw if [[PreventExtensions]]() fails.
+ https://bugs.webkit.org/show_bug.cgi?id=163160
+
+ Reviewed by Saam Barati.
+
+ * stress/object-freeze-with-proxy-preventExtensions.js: Added.
+ * stress/object-seal-with-proxy-preventExtensions.js: Added.
+
2016-10-05 Yusuke Suzuki <[email protected]>
[DOMJIT] Add initial CheckDOM and CallDOM implementations
Added: trunk/JSTests/stress/object-freeze-with-proxy-preventExtensions.js (0 => 206948)
--- trunk/JSTests/stress/object-freeze-with-proxy-preventExtensions.js (rev 0)
+++ trunk/JSTests/stress/object-freeze-with-proxy-preventExtensions.js 2016-10-08 03:20:53 UTC (rev 206948)
@@ -0,0 +1,29 @@
+// See https://tc39.github.io/ecma262/#sec-object.freeze
+// See https://tc39.github.io/ecma262/#sec-setintegritylevel
+
+var x = [10];
+var visited = [];
+
+var proxy = new Proxy(x, {
+ preventExtensions() {
+ visited.push("proxy_preventExtensions");
+ return false;
+ }
+});
+
+var exception;
+try {
+ visited.push("before_freeze");
+ Object.freeze(proxy);
+ visited.push("after_freeze");
+} catch (e) {
+ visited.push("catch");
+ exception = e;
+}
+
+var exceptionStr = "" + exception;
+if (!exceptionStr.startsWith("TypeError:"))
+ throw "Did not throw expected TypeError";
+
+if (visited != "before_freeze,proxy_preventExtensions,catch")
+ throw "ERROR: visited = " + visited;
Added: trunk/JSTests/stress/object-seal-with-proxy-preventExtensions.js (0 => 206948)
--- trunk/JSTests/stress/object-seal-with-proxy-preventExtensions.js (rev 0)
+++ trunk/JSTests/stress/object-seal-with-proxy-preventExtensions.js 2016-10-08 03:20:53 UTC (rev 206948)
@@ -0,0 +1,29 @@
+// See https://tc39.github.io/ecma262/#sec-object.seal
+// See https://tc39.github.io/ecma262/#sec-setintegritylevel
+
+var x = [10];
+var visited = [];
+
+var proxy = new Proxy(x, {
+ preventExtensions() {
+ visited.push("proxy_preventExtensions");
+ return false;
+ }
+});
+
+var exception;
+try {
+ visited.push("before_seal");
+ Object.seal(proxy);
+ visited.push("after_seal");
+} catch (e) {
+ visited.push("catch");
+ exception = e;
+}
+
+var exceptionStr = "" + exception;
+if (!exceptionStr.startsWith("TypeError:"))
+ throw "Did not throw expected TypeError";
+
+if (visited != "before_seal,proxy_preventExtensions,catch")
+ throw "ERROR: visited = " + visited;
Modified: trunk/Source/_javascript_Core/ChangeLog (206947 => 206948)
--- trunk/Source/_javascript_Core/ChangeLog 2016-10-08 02:07:09 UTC (rev 206947)
+++ trunk/Source/_javascript_Core/ChangeLog 2016-10-08 03:20:53 UTC (rev 206948)
@@ -1,3 +1,21 @@
+2016-10-07 Mark Lam <[email protected]>
+
+ Object.freeze() and seal() should throw if [[PreventExtensions]]() fails.
+ https://bugs.webkit.org/show_bug.cgi?id=163160
+
+ Reviewed by Saam Barati.
+
+ See https://tc39.github.io/ecma262/#sec-object.freeze,
+ https://tc39.github.io/ecma262/#sec-object.seal, and
+ https://tc39.github.io/ecma262/#sec-setintegritylevel. We need to call
+ preventExtensions first before proceeding to freeze / seal the object. If
+ preventExtensions fails, we should throw a TypeError.
+
+ * runtime/ObjectConstructor.cpp:
+ (JSC::setIntegrityLevel):
+ (JSC::objectConstructorSeal):
+ (JSC::objectConstructorFreeze):
+
2016-10-06 Yusuke Suzuki <[email protected]>
[DOMJIT] Support slow path call
Modified: trunk/Source/_javascript_Core/runtime/ObjectConstructor.cpp (206947 => 206948)
--- trunk/Source/_javascript_Core/runtime/ObjectConstructor.cpp 2016-10-08 02:07:09 UTC (rev 206947)
+++ trunk/Source/_javascript_Core/runtime/ObjectConstructor.cpp 2016-10-08 03:20:53 UTC (rev 206948)
@@ -471,6 +471,51 @@
return JSValue::encode(defineProperties(exec, newObject, asObject(exec->argument(1))));
}
+enum class IntegrityLevel {
+ Sealed,
+ Frozen
+};
+
+template<IntegrityLevel level>
+bool setIntegrityLevel(ExecState* exec, VM& vm, JSObject* object)
+{
+ // See https://tc39.github.io/ecma262/#sec-setintegritylevel.
+ auto scope = DECLARE_THROW_SCOPE(vm);
+
+ bool success = object->methodTable(vm)->preventExtensions(object, exec);
+ RETURN_IF_EXCEPTION(scope, false);
+ if (UNLIKELY(!success))
+ return false;
+
+ PropertyNameArray properties(exec, PropertyNameMode::StringsAndSymbols);
+ object->methodTable(vm)->getOwnPropertyNames(object, exec, properties, EnumerationMode(DontEnumPropertiesMode::Include));
+ RETURN_IF_EXCEPTION(scope, false);
+
+ PropertyNameArray::const_iterator end = properties.end();
+ for (PropertyNameArray::const_iterator iter = properties.begin(); iter != end; ++iter) {
+ Identifier propertyName = *iter;
+ if (vm.propertyNames->isPrivateName(propertyName))
+ continue;
+
+ PropertyDescriptor desc;
+ if (level == IntegrityLevel::Sealed)
+ desc.setConfigurable(false);
+ else {
+ if (!object->getOwnPropertyDescriptor(exec, propertyName, desc))
+ continue;
+
+ if (desc.isDataDescriptor())
+ desc.setWritable(false);
+
+ desc.setConfigurable(false);
+ }
+
+ object->methodTable(vm)->defineOwnProperty(object, exec, propertyName, desc, true);
+ RETURN_IF_EXCEPTION(scope, false);
+ }
+ return true;
+}
+
EncodedJSValue JSC_HOST_CALL objectConstructorSeal(ExecState* exec)
{
VM& vm = exec->vm();
@@ -487,31 +532,13 @@
return JSValue::encode(obj);
}
- // 2. For each named own property name P of O,
- PropertyNameArray properties(exec, PropertyNameMode::StringsAndSymbols);
- object->methodTable(vm)->getOwnPropertyNames(object, exec, properties, EnumerationMode(DontEnumPropertiesMode::Include));
+ bool success = setIntegrityLevel<IntegrityLevel::Sealed>(exec, vm, object);
RETURN_IF_EXCEPTION(scope, encodedJSValue());
- PropertyNameArray::const_iterator end = properties.end();
- for (PropertyNameArray::const_iterator iter = properties.begin(); iter != end; ++iter) {
- Identifier propertyName = *iter;
- if (exec->propertyNames().isPrivateName(propertyName))
- continue;
- // a. Let desc be the result of calling the [[GetOwnProperty]] internal method of O with P.
- PropertyDescriptor desc;
- if (!object->getOwnPropertyDescriptor(exec, propertyName, desc))
- continue;
- // b. If desc.[[Configurable]] is true, set desc.[[Configurable]] to false.
- desc.setConfigurable(false);
- // c. Call the [[DefineOwnProperty]] internal method of O with P, desc, and true as arguments.
- object->methodTable(vm)->defineOwnProperty(object, exec, propertyName, desc, true);
- RETURN_IF_EXCEPTION(scope, encodedJSValue());
+ if (!success) {
+ throwTypeError(exec, scope, ASCIILiteral("Unable to prevent extension in Object.seal"));
+ return encodedJSValue();
}
- // 3. Set the [[Extensible]] internal property of O to false.
- object->methodTable(vm)->preventExtensions(object, exec);
- RETURN_IF_EXCEPTION(scope, encodedJSValue());
-
- // 4. Return O.
return JSValue::encode(obj);
}
@@ -525,35 +552,10 @@
return object;
}
- // 2. For each named own property name P of O,
- PropertyNameArray properties(exec, PropertyNameMode::StringsAndSymbols);
- object->methodTable(vm)->getOwnPropertyNames(object, exec, properties, EnumerationMode(DontEnumPropertiesMode::Include));
+ bool success = setIntegrityLevel<IntegrityLevel::Frozen>(exec, vm, object);
RETURN_IF_EXCEPTION(scope, nullptr);
- PropertyNameArray::const_iterator end = properties.end();
- for (PropertyNameArray::const_iterator iter = properties.begin(); iter != end; ++iter) {
- Identifier propertyName = *iter;
- if (exec->propertyNames().isPrivateName(propertyName))
- continue;
- // a. Let desc be the result of calling the [[GetOwnProperty]] internal method of O with P.
- PropertyDescriptor desc;
- if (!object->getOwnPropertyDescriptor(exec, propertyName, desc))
- continue;
- // b. If IsDataDescriptor(desc) is true, then
- // i. If desc.[[Writable]] is true, set desc.[[Writable]] to false.
- if (desc.isDataDescriptor())
- desc.setWritable(false);
- // c. If desc.[[Configurable]] is true, set desc.[[Configurable]] to false.
- desc.setConfigurable(false);
- // d. Call the [[DefineOwnProperty]] internal method of O with P, desc, and true as arguments.
- object->methodTable(vm)->defineOwnProperty(object, exec, propertyName, desc, true);
- RETURN_IF_EXCEPTION(scope, nullptr);
- }
-
- // 3. Set the [[Extensible]] internal property of O to false.
- object->methodTable(vm)->preventExtensions(object, exec);
- RETURN_IF_EXCEPTION(scope, nullptr);
-
- // 4. Return O.
+ if (!success)
+ return throwTypeError(exec, scope, ASCIILiteral("Unable to prevent extension in Object.freeze"));
return object;
}
_______________________________________________ webkit-changes mailing list [email protected] https://lists.webkit.org/mailman/listinfo/webkit-changes
