https://bugs.webkit.org/show_bug.cgi?id=147874
Reviewed by Darin Adler.
This patch implements ES6 Reflect.{getPrototypeOf, setPrototypeOf}.
The difference from the Object.* one is
1. They dont not perform ToObject onto the non-object arguments. They make it as a TypeError.
2. Reflect.setPrototyeOf returns false when the operation is failed. In Object.setPrototypeOf, it raises a TypeError.
* runtime/ObjectConstructor.cpp:
(JSC::ObjectConstructorGetPrototypeOfFunctor::ObjectConstructorGetPrototypeOfFunctor):
(JSC::ObjectConstructorGetPrototypeOfFunctor::result):
(JSC::ObjectConstructorGetPrototypeOfFunctor::operator()):
(JSC::objectConstructorGetPrototypeOf):
* runtime/ObjectConstructor.h:
* runtime/ReflectObject.cpp:
(JSC::reflectObjectGetPrototypeOf):
(JSC::reflectObjectSetPrototypeOf):
* tests/stress/reflect-get-prototype-of.js: Added.
(shouldBe):
(shouldThrow):
(Base):
(Derived):
* tests/stress/reflect-set-prototype-of.js: Added.
(shouldBe):
(shouldThrow):
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@188262
268f45cc-cd09-0410-ab3c-
d52691b4dbfc
+2015-08-11 Yusuke Suzuki <utatane.tea@gmail.com>
+
+ [ES6] Implement Reflect.getPrototypeOf and Reflect.setPrototypeOf
+ https://bugs.webkit.org/show_bug.cgi?id=147874
+
+ Reviewed by Darin Adler.
+
+ This patch implements ES6 Reflect.{getPrototypeOf, setPrototypeOf}.
+ The difference from the Object.* one is
+
+ 1. They dont not perform ToObject onto the non-object arguments. They make it as a TypeError.
+ 2. Reflect.setPrototyeOf returns false when the operation is failed. In Object.setPrototypeOf, it raises a TypeError.
+
+ * runtime/ObjectConstructor.cpp:
+ (JSC::ObjectConstructorGetPrototypeOfFunctor::ObjectConstructorGetPrototypeOfFunctor):
+ (JSC::ObjectConstructorGetPrototypeOfFunctor::result):
+ (JSC::ObjectConstructorGetPrototypeOfFunctor::operator()):
+ (JSC::objectConstructorGetPrototypeOf):
+ * runtime/ObjectConstructor.h:
+ * runtime/ReflectObject.cpp:
+ (JSC::reflectObjectGetPrototypeOf):
+ (JSC::reflectObjectSetPrototypeOf):
+ * tests/stress/reflect-get-prototype-of.js: Added.
+ (shouldBe):
+ (shouldThrow):
+ (Base):
+ (Derived):
+ * tests/stress/reflect-set-prototype-of.js: Added.
+ (shouldBe):
+ (shouldThrow):
+
2015-08-11 Ting-Wei Lan <lantw44@gmail.com>
Fix debug build when optimization is enabled
ObjectConstructorGetPrototypeOfFunctor(JSObject* object)
: m_hasSkippedFirstFrame(false)
, m_object(object)
- , m_result(JSValue::encode(jsUndefined()))
+ , m_result(jsUndefined())
{
}
- EncodedJSValue result() const { return m_result; }
+ JSValue result() const { return m_result; }
StackVisitor::Status operator()(StackVisitor& visitor)
{
}
if (m_object->allowsAccessFrom(visitor->callFrame()))
- m_result = JSValue::encode(m_object->prototype());
+ m_result = m_object->prototype();
return StackVisitor::Done;
}
private:
bool m_hasSkippedFirstFrame;
JSObject* m_object;
- EncodedJSValue m_result;
+ JSValue m_result;
};
-EncodedJSValue JSC_HOST_CALL objectConstructorGetPrototypeOf(ExecState* exec)
+JSValue objectConstructorGetPrototypeOf(ExecState* exec, JSObject* object)
{
- JSObject* object = exec->argument(0).toObject(exec);
- if (exec->hadException())
- return JSValue::encode(jsNull());
ObjectConstructorGetPrototypeOfFunctor functor(object);
exec->iterate(functor);
return functor.result();
}
+EncodedJSValue JSC_HOST_CALL objectConstructorGetPrototypeOf(ExecState* exec)
+{
+ JSObject* object = exec->argument(0).toObject(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+ return JSValue::encode(objectConstructorGetPrototypeOf(exec, object));
+}
+
EncodedJSValue JSC_HOST_CALL objectConstructorSetPrototypeOf(ExecState* exec)
{
JSValue objectValue = exec->argument(0);
}
JSObject* objectConstructorFreeze(ExecState*, JSObject*);
+JSValue objectConstructorGetPrototypeOf(ExecState*, JSObject*);
JSArray* ownPropertyKeys(ExecState*, JSObject*, PropertyNameMode, DontEnumPropertiesMode);
} // namespace JSC
#include "ReflectObject.h"
#include "JSCInlines.h"
+#include "JSGlobalObjectFunctions.h"
#include "JSPropertyNameIterator.h"
#include "Lookup.h"
#include "ObjectConstructor.h"
namespace JSC {
static EncodedJSValue JSC_HOST_CALL reflectObjectEnumerate(ExecState*);
+static EncodedJSValue JSC_HOST_CALL reflectObjectGetPrototypeOf(ExecState*);
static EncodedJSValue JSC_HOST_CALL reflectObjectIsExtensible(ExecState*);
static EncodedJSValue JSC_HOST_CALL reflectObjectOwnKeys(ExecState*);
static EncodedJSValue JSC_HOST_CALL reflectObjectPreventExtensions(ExecState*);
+static EncodedJSValue JSC_HOST_CALL reflectObjectSetPrototypeOf(ExecState*);
}
apply reflectObjectApply DontEnum|Function 3
deleteProperty reflectObjectDeleteProperty DontEnum|Function 2
enumerate reflectObjectEnumerate DontEnum|Function 1
+ getPrototypeOf reflectObjectGetPrototypeOf DontEnum|Function 1
isExtensible reflectObjectIsExtensible DontEnum|Function 1
ownKeys reflectObjectOwnKeys DontEnum|Function 1
preventExtensions reflectObjectPreventExtensions DontEnum|Function 1
+ setPrototypeOf reflectObjectSetPrototypeOf DontEnum|Function 2
@end
*/
return JSValue::encode(JSPropertyNameIterator::create(exec, exec->lexicalGlobalObject()->propertyNameIteratorStructure(), asObject(target)));
}
+EncodedJSValue JSC_HOST_CALL reflectObjectGetPrototypeOf(ExecState* exec)
+{
+ JSValue target = exec->argument(0);
+ if (!target.isObject())
+ return JSValue::encode(throwTypeError(exec, ASCIILiteral("Reflect.getPrototypeOf requires the first argument be an object")));
+ return JSValue::encode(objectConstructorGetPrototypeOf(exec, asObject(target)));
+}
+
EncodedJSValue JSC_HOST_CALL reflectObjectIsExtensible(ExecState* exec)
{
JSValue target = exec->argument(0);
return JSValue::encode(jsBoolean(true));
}
+EncodedJSValue JSC_HOST_CALL reflectObjectSetPrototypeOf(ExecState* exec)
+{
+ JSValue target = exec->argument(0);
+ if (!target.isObject())
+ return JSValue::encode(throwTypeError(exec, ASCIILiteral("Reflect.setPrototypeOf requires the first argument be an object")));
+ JSValue proto = exec->argument(1);
+ if (!proto.isObject() && !proto.isNull())
+ return JSValue::encode(throwTypeError(exec, ASCIILiteral("Reflect.setPrototypeOf requires the second argument be either an object or null")));
+
+ JSObject* object = asObject(target);
+
+ if (!checkProtoSetterAccessAllowed(exec, object))
+ return JSValue::encode(jsBoolean(false));
+
+ if (!object->isExtensible())
+ return JSValue::encode(jsBoolean(false));
+
+ return JSValue::encode(jsBoolean(object->setPrototypeWithCycleCheck(exec, proto)));
+}
+
} // namespace JSC
--- /dev/null
+function shouldBe(actual, expected) {
+ if (actual !== expected)
+ throw new Error('bad value: ' + actual);
+}
+
+function shouldThrow(func, message) {
+ var error = null;
+ try {
+ func();
+ } catch (e) {
+ error = e;
+ }
+ if (!error)
+ throw new Error("not thrown.");
+ if (String(error) !== message)
+ throw new Error("bad error: " + String(error));
+}
+
+shouldBe(Reflect.getPrototypeOf.length, 1);
+
+shouldThrow(() => {
+ Reflect.getPrototypeOf("hello");
+}, `TypeError: Reflect.getPrototypeOf requires the first argument be an object`);
+
+var object = { hello: 42 };
+shouldBe(Reflect.getPrototypeOf(object), Object.prototype);
+shouldBe(Reflect.getPrototypeOf(Reflect.getPrototypeOf(object)), null);
+var proto = [];
+object.__proto__ = proto;
+shouldBe(Reflect.getPrototypeOf(object), proto);
+
+var array = [];
+shouldBe(Reflect.getPrototypeOf(array), Array.prototype);
+var proto = [];
+array.__proto__ = Object.prototype;
+shouldBe(Reflect.getPrototypeOf(array), Object.prototype);
+
+class Base {
+}
+
+class Derived extends Base {
+}
+
+shouldBe(Reflect.getPrototypeOf(new Derived), Derived.prototype);
+shouldBe(Reflect.getPrototypeOf(Reflect.getPrototypeOf(new Derived)), Base.prototype);
+shouldBe(Reflect.getPrototypeOf(Reflect.getPrototypeOf(Reflect.getPrototypeOf(new Derived))), Object.prototype);
+shouldBe(Reflect.getPrototypeOf(Reflect.getPrototypeOf(Reflect.getPrototypeOf(Reflect.getPrototypeOf(new Derived)))), null);
+
+var object = Object.create(null);
+shouldBe(Reflect.getPrototypeOf(object), null);
--- /dev/null
+function shouldBe(actual, expected) {
+ if (actual !== expected)
+ throw new Error('bad value: ' + actual);
+}
+
+function shouldThrow(func, message) {
+ var error = null;
+ try {
+ func();
+ } catch (e) {
+ error = e;
+ }
+ if (!error)
+ throw new Error("not thrown.");
+ if (String(error) !== message)
+ throw new Error("bad error: " + String(error));
+}
+
+shouldBe(Reflect.setPrototypeOf.length, 2);
+
+shouldThrow(() => {
+ Reflect.setPrototypeOf("hello");
+}, `TypeError: Reflect.setPrototypeOf requires the first argument be an object`);
+
+shouldThrow(() => {
+ Reflect.setPrototypeOf(null);
+}, `TypeError: Reflect.setPrototypeOf requires the first argument be an object`);
+
+shouldThrow(() => {
+ Reflect.setPrototypeOf({}, 30);
+}, `TypeError: Reflect.setPrototypeOf requires the second argument be either an object or null`);
+
+shouldThrow(() => {
+ Reflect.setPrototypeOf({}, undefined);
+}, `TypeError: Reflect.setPrototypeOf requires the second argument be either an object or null`);
+
+var object = {};
+var prototype = {};
+shouldBe(Reflect.getPrototypeOf(object), Object.prototype);
+shouldBe(Reflect.setPrototypeOf(object, prototype), true);
+shouldBe(Reflect.getPrototypeOf(object), prototype);
+
+var object = {};
+shouldBe(Reflect.getPrototypeOf(object), Object.prototype);
+shouldBe(Reflect.setPrototypeOf(object, null), true);
+shouldBe(Reflect.getPrototypeOf(object), null);
+
+var array = [];
+var prototype = {};
+shouldBe(Reflect.getPrototypeOf(array), Array.prototype);
+shouldBe(Reflect.setPrototypeOf(array, prototype), true);
+shouldBe(Reflect.getPrototypeOf(array), prototype);
+
+var array = [];
+shouldBe(Reflect.getPrototypeOf(array), Array.prototype);
+shouldBe(Reflect.setPrototypeOf(array, null), true);
+shouldBe(Reflect.getPrototypeOf(array), null);
+
+var object = Object.create(null);
+shouldBe(Reflect.getPrototypeOf(object), null);
+shouldBe(Reflect.setPrototypeOf(object, Object.prototype), true);
+shouldBe(Reflect.getPrototypeOf(object), Object.prototype);
+
+// Extensible check.
+var object = {};
+shouldBe(Reflect.preventExtensions(object), true);
+shouldBe(Reflect.setPrototypeOf(object, null), false);
+shouldBe(Reflect.getPrototypeOf(object), Object.prototype);
+
+// Cyclic check.
+var prototype = {};
+var object = { __proto__: prototype };
+shouldBe(Reflect.setPrototypeOf(prototype, object), false);
+shouldBe(Reflect.getPrototypeOf(prototype), Object.prototype);
+