Diff
Modified: trunk/Source/_javascript_Core/ChangeLog (197511 => 197512)
--- trunk/Source/_javascript_Core/ChangeLog 2016-03-03 18:34:11 UTC (rev 197511)
+++ trunk/Source/_javascript_Core/ChangeLog 2016-03-03 19:18:35 UTC (rev 197512)
@@ -1,3 +1,38 @@
+2016-03-03 Saam barati <[email protected]>
+
+ [[SetPrototypeOf]] isn't properly implemented everywhere
+ https://bugs.webkit.org/show_bug.cgi?id=154943
+
+ Reviewed by Benjamin Poulain.
+
+ We were copy-pasting implememntation bits that belong in OrdinarySetPrototypeOf
+ in a few different places that call O.[[SetPrototypeOf]](v)
+ rather than having those bits in OrdinarySetPrototypeOf itself.
+ We need to put those copy-pasted bits into OrdinarySetPrototypeOf
+ and not the call sites of O.[[SetPrototypeOf]](v) because
+ O.[[SetPrototypeOf]](v) won't always call into OrdinarySetPrototypeOf.
+ This is needed for correctness because this behavior is now observable
+ with the ES6 Proxy object.
+
+ * runtime/ClassInfo.h:
+ * runtime/JSCell.cpp:
+ (JSC::JSCell::isExtensible):
+ (JSC::JSCell::setPrototype):
+ * runtime/JSCell.h:
+ * runtime/JSGlobalObjectFunctions.cpp:
+ (JSC::globalFuncProtoSetter):
+ * runtime/JSObject.cpp:
+ (JSC::JSObject::setPrototypeDirect):
+ (JSC::JSObject::setPrototypeWithCycleCheck):
+ (JSC::JSObject::setPrototype):
+ (JSC::JSObject::allowsAccessFrom):
+ * runtime/JSObject.h:
+ (JSC::JSObject::mayInterceptIndexedAccesses):
+ * runtime/ObjectConstructor.cpp:
+ (JSC::objectConstructorSetPrototypeOf):
+ * runtime/ReflectObject.cpp:
+ (JSC::reflectObjectSetPrototypeOf):
+
2016-03-03 Alex Christensen <[email protected]>
Fix Windows build after r197489.
Modified: trunk/Source/_javascript_Core/runtime/ClassInfo.h (197511 => 197512)
--- trunk/Source/_javascript_Core/runtime/ClassInfo.h 2016-03-03 18:34:11 UTC (rev 197511)
+++ trunk/Source/_javascript_Core/runtime/ClassInfo.h 2016-03-03 19:18:35 UTC (rev 197512)
@@ -109,7 +109,7 @@
typedef bool (*IsExtensibleFunctionPtr)(JSObject*, ExecState*);
IsExtensibleFunctionPtr isExtensible;
- typedef bool (*SetPrototypeFunctionPtr)(JSObject*, ExecState*, JSValue);
+ typedef bool (*SetPrototypeFunctionPtr)(JSObject*, ExecState*, JSValue, bool shouldThrowIfCantSet);
SetPrototypeFunctionPtr setPrototype;
typedef void (*DumpToStreamFunctionPtr)(const JSCell*, PrintStream&);
Modified: trunk/Source/_javascript_Core/runtime/JSCell.cpp (197511 => 197512)
--- trunk/Source/_javascript_Core/runtime/JSCell.cpp 2016-03-03 18:34:11 UTC (rev 197511)
+++ trunk/Source/_javascript_Core/runtime/JSCell.cpp 2016-03-03 19:18:35 UTC (rev 197512)
@@ -280,7 +280,7 @@
RELEASE_ASSERT_NOT_REACHED();
}
-bool JSCell::setPrototype(JSObject*, ExecState*, JSValue)
+bool JSCell::setPrototype(JSObject*, ExecState*, JSValue, bool)
{
RELEASE_ASSERT_NOT_REACHED();
}
Modified: trunk/Source/_javascript_Core/runtime/JSCell.h (197511 => 197512)
--- trunk/Source/_javascript_Core/runtime/JSCell.h 2016-03-03 18:34:11 UTC (rev 197511)
+++ trunk/Source/_javascript_Core/runtime/JSCell.h 2016-03-03 19:18:35 UTC (rev 197512)
@@ -208,7 +208,7 @@
static NO_RETURN_DUE_TO_CRASH void getGenericPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
static NO_RETURN_DUE_TO_CRASH bool preventExtensions(JSObject*, ExecState*);
static NO_RETURN_DUE_TO_CRASH bool isExtensible(JSObject*, ExecState*);
- static NO_RETURN_DUE_TO_CRASH bool setPrototype(JSObject*, ExecState*, JSValue);
+ static NO_RETURN_DUE_TO_CRASH bool setPrototype(JSObject*, ExecState*, JSValue, bool);
static String className(const JSObject*);
JS_EXPORT_PRIVATE static bool customHasInstance(JSObject*, ExecState*, JSValue);
Modified: trunk/Source/_javascript_Core/runtime/JSGlobalObjectFunctions.cpp (197511 => 197512)
--- trunk/Source/_javascript_Core/runtime/JSGlobalObjectFunctions.cpp 2016-03-03 18:34:11 UTC (rev 197511)
+++ trunk/Source/_javascript_Core/runtime/JSGlobalObjectFunctions.cpp 2016-03-03 19:18:35 UTC (rev 197512)
@@ -882,22 +882,9 @@
if (!value.isObject() && !value.isNull())
return JSValue::encode(jsUndefined());
- if (thisObject->prototype() == value)
- return JSValue::encode(jsUndefined());
-
- bool isExtensible = thisObject->isExtensible(exec);
- if (exec->hadException())
- return JSValue::encode(jsUndefined());
- if (!isExtensible)
- return throwVMError(exec, createTypeError(exec, StrictModeReadonlyPropertyWriteError));
-
VM& vm = exec->vm();
- if (!thisObject->setPrototype(vm, exec, value)) {
- if (!vm.exception())
- vm.throwException(exec, createError(exec, ASCIILiteral("cyclic __proto__ value")));
- return JSValue::encode(jsUndefined());
- }
- ASSERT(!exec->hadException());
+ bool shouldThrowIfCantSet = true;
+ thisObject->setPrototype(vm, exec, value, shouldThrowIfCantSet);
return JSValue::encode(jsUndefined());
}
Modified: trunk/Source/_javascript_Core/runtime/JSObject.cpp (197511 => 197512)
--- trunk/Source/_javascript_Core/runtime/JSObject.cpp 2016-03-03 18:34:11 UTC (rev 197511)
+++ trunk/Source/_javascript_Core/runtime/JSObject.cpp 2016-03-03 19:18:35 UTC (rev 197512)
@@ -1197,28 +1197,44 @@
switchToSlowPutArrayStorage(vm);
}
-bool JSObject::setPrototypeWithCycleCheck(VM& vm, ExecState* exec, JSValue prototype)
+bool JSObject::setPrototypeWithCycleCheck(VM& vm, ExecState* exec, JSValue prototype, bool shouldThrowIfCantSet)
{
- UNUSED_PARAM(exec);
ASSERT(methodTable(vm)->toThis(this, exec, NotStrictMode) == this);
+
+ if (this->prototype() == prototype)
+ return true;
+
+ bool isExtensible = this->isExtensible(exec);
+ if (vm.exception())
+ return false;
+
+ if (!isExtensible) {
+ if (shouldThrowIfCantSet)
+ throwVMError(exec, createTypeError(exec, StrictModeReadonlyPropertyWriteError));
+ return false;
+ }
+
JSValue nextPrototype = prototype;
while (nextPrototype && nextPrototype.isObject()) {
- if (nextPrototype == this)
+ if (nextPrototype == this) {
+ if (shouldThrowIfCantSet)
+ vm.throwException(exec, createError(exec, ASCIILiteral("cyclic __proto__ value")));
return false;
+ }
nextPrototype = asObject(nextPrototype)->prototype();
}
setPrototypeDirect(vm, prototype);
return true;
}
-bool JSObject::setPrototype(JSObject* object, ExecState* exec, JSValue prototype)
+bool JSObject::setPrototype(JSObject* object, ExecState* exec, JSValue prototype, bool shouldThrowIfCantSet)
{
- return object->setPrototypeWithCycleCheck(exec->vm(), exec, prototype);
+ return object->setPrototypeWithCycleCheck(exec->vm(), exec, prototype, shouldThrowIfCantSet);
}
-bool JSObject::setPrototype(VM& vm, ExecState* exec, JSValue prototype)
+bool JSObject::setPrototype(VM& vm, ExecState* exec, JSValue prototype, bool shouldThrowIfCantSet)
{
- return methodTable(vm)->setPrototype(this, exec, prototype);
+ return methodTable(vm)->setPrototype(this, exec, prototype, shouldThrowIfCantSet);
}
bool JSObject::allowsAccessFrom(ExecState* exec)
Modified: trunk/Source/_javascript_Core/runtime/JSObject.h (197511 => 197512)
--- trunk/Source/_javascript_Core/runtime/JSObject.h 2016-03-03 18:34:11 UTC (rev 197511)
+++ trunk/Source/_javascript_Core/runtime/JSObject.h 2016-03-03 19:18:35 UTC (rev 197512)
@@ -114,13 +114,13 @@
private:
// This is OrdinarySetPrototypeOf in the specification. Section 9.1.2.1
// https://tc39.github.io/ecma262/#sec-ordinarysetprototypeof
- JS_EXPORT_PRIVATE bool setPrototypeWithCycleCheck(VM&, ExecState*, JSValue prototype);
+ JS_EXPORT_PRIVATE bool setPrototypeWithCycleCheck(VM&, ExecState*, JSValue prototype, bool shouldThrowIfCantSet);
public:
// This is the fully virtual [[SetPrototypeOf]] internal function defined
// in the ECMAScript 6 specification. Use this when doing a [[SetPrototypeOf]]
// operation as dictated in the specification.
- bool setPrototype(VM&, ExecState*, JSValue prototype);
- JS_EXPORT_PRIVATE static bool setPrototype(JSObject*, ExecState*, JSValue prototype);
+ bool setPrototype(VM&, ExecState*, JSValue prototype, bool shouldThrowIfCantSet = false);
+ JS_EXPORT_PRIVATE static bool setPrototype(JSObject*, ExecState*, JSValue prototype, bool shouldThrowIfCantSet);
bool mayInterceptIndexedAccesses()
{
Modified: trunk/Source/_javascript_Core/runtime/ObjectConstructor.cpp (197511 => 197512)
--- trunk/Source/_javascript_Core/runtime/ObjectConstructor.cpp 2016-03-03 18:34:11 UTC (rev 197511)
+++ trunk/Source/_javascript_Core/runtime/ObjectConstructor.cpp 2016-03-03 19:18:35 UTC (rev 197512)
@@ -209,24 +209,10 @@
if (!checkProtoSetterAccessAllowed(exec, object))
return JSValue::encode(objectValue);
- if (object->prototype() == protoValue)
- return JSValue::encode(objectValue);
-
- bool isExtensible = object->isExtensible(exec);
- if (exec->hadException())
- return JSValue::encode(JSValue());
- if (!isExtensible)
- return throwVMError(exec, createTypeError(exec, StrictModeReadonlyPropertyWriteError));
-
VM& vm = exec->vm();
- bool didSetPrototype = object->setPrototype(vm, exec, protoValue);
- if (vm.exception())
- return JSValue::encode(JSValue());
- if (!didSetPrototype) {
- vm.throwException(exec, createError(exec, ASCIILiteral("cyclic __proto__ value")));
- return JSValue::encode(jsUndefined());
- }
-
+ bool shouldThrowIfCantSet = true;
+ bool didSetPrototype = object->setPrototype(vm, exec, protoValue, shouldThrowIfCantSet);
+ ASSERT_UNUSED(didSetPrototype, vm.exception() || didSetPrototype);
return JSValue::encode(objectValue);
}
Modified: trunk/Source/_javascript_Core/runtime/ReflectObject.cpp (197511 => 197512)
--- trunk/Source/_javascript_Core/runtime/ReflectObject.cpp 2016-03-03 18:34:11 UTC (rev 197511)
+++ trunk/Source/_javascript_Core/runtime/ReflectObject.cpp 2016-03-03 19:18:35 UTC (rev 197512)
@@ -212,17 +212,9 @@
if (!checkProtoSetterAccessAllowed(exec, object))
return JSValue::encode(jsBoolean(false));
- if (object->prototype() == proto)
- return JSValue::encode(jsBoolean(true));
-
- bool isExtensible = object->isExtensible(exec);
- if (exec->hadException())
- return JSValue::encode(JSValue());
- if (!isExtensible)
- return JSValue::encode(jsBoolean(false));
-
VM& vm = exec->vm();
- bool didSetPrototype = object->setPrototype(vm, exec, proto);
+ bool shouldThrowIfCantSet = false;
+ bool didSetPrototype = object->setPrototype(vm, exec, proto, shouldThrowIfCantSet);
if (vm.exception())
return JSValue::encode(JSValue());
return JSValue::encode(jsBoolean(didSetPrototype));