[JSC] Object constructor need to be aware of new.target
https://bugs.webkit.org/show_bug.cgi?id=157196
Reviewed by Darin Adler.
Object constructor should be aware of new.target.
When the new.target is specified, we should store it.prototype to the newly created
object's [[Prototype]].
* runtime/JSGlobalObject.cpp:
(JSC::JSGlobalObject::init):
(JSC::JSGlobalObject::visitChildren):
Take the design that caches the structure used for empty object.
This structure is also used in constructEmptyObject frequently.
* runtime/JSGlobalObject.h:
(JSC::JSGlobalObject::objectStructureForObjectConstructor):
* runtime/ObjectConstructor.cpp:
(JSC::constructObject):
(JSC::constructWithObjectConstructor):
(JSC::callObjectConstructor):
* runtime/ObjectConstructor.h:
(JSC::constructEmptyObject):
Construct the object by using the plain structure that is also used in the ObjectConstructor.
* tests/stress/object-constructor-should-be-new-target-aware.js: Added.
(shouldBe):
(Hello):
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@200421 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog
index 606290a..87da5ed 100644
--- a/Source/JavaScriptCore/ChangeLog
+++ b/Source/JavaScriptCore/ChangeLog
@@ -1,3 +1,34 @@
+2016-05-04 Yusuke Suzuki <utatane.tea@gmail.com>
+
+ [JSC] Object constructor need to be aware of new.target
+ https://bugs.webkit.org/show_bug.cgi?id=157196
+
+ Reviewed by Darin Adler.
+
+ Object constructor should be aware of new.target.
+ When the new.target is specified, we should store it.prototype to the newly created
+ object's [[Prototype]].
+
+ * runtime/JSGlobalObject.cpp:
+ (JSC::JSGlobalObject::init):
+ (JSC::JSGlobalObject::visitChildren):
+ Take the design that caches the structure used for empty object.
+ This structure is also used in constructEmptyObject frequently.
+
+ * runtime/JSGlobalObject.h:
+ (JSC::JSGlobalObject::objectStructureForObjectConstructor):
+ * runtime/ObjectConstructor.cpp:
+ (JSC::constructObject):
+ (JSC::constructWithObjectConstructor):
+ (JSC::callObjectConstructor):
+ * runtime/ObjectConstructor.h:
+ (JSC::constructEmptyObject):
+ Construct the object by using the plain structure that is also used in the ObjectConstructor.
+
+ * tests/stress/object-constructor-should-be-new-target-aware.js: Added.
+ (shouldBe):
+ (Hello):
+
2016-05-04 Chris Dumez <cdumez@apple.com>
Unreviewed, rolling out r200383 and r200406.
diff --git a/Source/JavaScriptCore/runtime/JSGlobalObject.cpp b/Source/JavaScriptCore/runtime/JSGlobalObject.cpp
index 3448f11a4..bdb558a 100644
--- a/Source/JavaScriptCore/runtime/JSGlobalObject.cpp
+++ b/Source/JavaScriptCore/runtime/JSGlobalObject.cpp
@@ -315,6 +315,7 @@
protoAccessor->setSetter(vm, this, JSFunction::create(vm, this, 0, makeString("set ", vm.propertyNames->underscoreProto.string()), globalFuncProtoSetter));
m_objectPrototype->putDirectNonIndexAccessor(vm, vm.propertyNames->underscoreProto, protoAccessor, Accessor | DontEnum);
m_functionPrototype->structure()->setPrototypeWithoutTransition(vm, m_objectPrototype.get());
+ m_objectStructureForObjectConstructor.set(vm, this, vm.prototypeMap.emptyObjectStructureForPrototype(m_objectPrototype.get(), JSFinalObject::defaultInlineCapacity()));
JSTypedArrayViewPrototype* typedArrayProto = JSTypedArrayViewPrototype::create(vm, this, JSTypedArrayViewPrototype::createStructure(vm, this, m_objectPrototype.get()));
@@ -966,6 +967,7 @@
visitor.append(&thisObject->m_directArgumentsStructure);
visitor.append(&thisObject->m_scopedArgumentsStructure);
visitor.append(&thisObject->m_clonedArgumentsStructure);
+ visitor.append(&thisObject->m_objectStructureForObjectConstructor);
for (unsigned i = 0; i < NumberOfIndexingShapes; ++i)
visitor.append(&thisObject->m_originalArrayStructureForIndexingShape[i]);
for (unsigned i = 0; i < NumberOfIndexingShapes; ++i)
diff --git a/Source/JavaScriptCore/runtime/JSGlobalObject.h b/Source/JavaScriptCore/runtime/JSGlobalObject.h
index 8bb14c3..8863a1c 100644
--- a/Source/JavaScriptCore/runtime/JSGlobalObject.h
+++ b/Source/JavaScriptCore/runtime/JSGlobalObject.h
@@ -254,6 +254,8 @@
WriteBarrier<Structure> m_directArgumentsStructure;
WriteBarrier<Structure> m_scopedArgumentsStructure;
WriteBarrier<Structure> m_clonedArgumentsStructure;
+
+ WriteBarrier<Structure> m_objectStructureForObjectConstructor;
// Lists the actual structures used for having these particular indexing shapes.
WriteBarrier<Structure> m_originalArrayStructureForIndexingShape[NumberOfIndexingShapes];
@@ -499,6 +501,7 @@
Structure* directArgumentsStructure() const { return m_directArgumentsStructure.get(); }
Structure* scopedArgumentsStructure() const { return m_scopedArgumentsStructure.get(); }
Structure* clonedArgumentsStructure() const { return m_clonedArgumentsStructure.get(); }
+ Structure* objectStructureForObjectConstructor() const { return m_objectStructureForObjectConstructor.get(); }
Structure* originalArrayStructureForIndexingType(IndexingType indexingType) const
{
ASSERT(indexingType & IsArray);
diff --git a/Source/JavaScriptCore/runtime/ObjectConstructor.cpp b/Source/JavaScriptCore/runtime/ObjectConstructor.cpp
index 15eeba5..3fcf9ec 100644
--- a/Source/JavaScriptCore/runtime/ObjectConstructor.cpp
+++ b/Source/JavaScriptCore/runtime/ObjectConstructor.cpp
@@ -118,19 +118,37 @@
return getStaticFunctionSlot<JSObject>(exec, objectConstructorTable, jsCast<ObjectConstructor*>(object), propertyName, slot);
}
-static ALWAYS_INLINE JSObject* constructObject(ExecState* exec)
+// ES 19.1.1.1 Object([value])
+static ALWAYS_INLINE JSObject* constructObject(ExecState* exec, JSValue newTarget)
{
- JSGlobalObject* globalObject = exec->callee()->globalObject();
+ ObjectConstructor* objectConstructor = jsCast<ObjectConstructor*>(exec->callee());
+ JSGlobalObject* globalObject = objectConstructor->globalObject();
+
+ // We need to check newTarget condition in this caller side instead of InternalFunction::createSubclassStructure side.
+ // Since if we found this condition is met, we should not fall into the type conversion in the step 3.
+
+ // 1. If NewTarget is neither undefined nor the active function, then
+ if (newTarget && newTarget != objectConstructor) {
+ // a. Return ? OrdinaryCreateFromConstructor(NewTarget, "%ObjectPrototype%").
+ Structure* objectStructure = InternalFunction::createSubclassStructure(exec, newTarget, globalObject->objectStructureForObjectConstructor());
+ if (exec->hadException())
+ return nullptr;
+ return constructEmptyObject(exec, objectStructure);
+ }
+
+ // 2. If value is null, undefined or not supplied, return ObjectCreate(%ObjectPrototype%).
ArgList args(exec);
JSValue arg = args.at(0);
if (arg.isUndefinedOrNull())
- return constructEmptyObject(exec, globalObject->objectPrototype());
+ return constructEmptyObject(exec, globalObject->objectStructureForObjectConstructor());
+
+ // 3. Return ToObject(value).
return arg.toObject(exec, globalObject);
}
static EncodedJSValue JSC_HOST_CALL constructWithObjectConstructor(ExecState* exec)
{
- return JSValue::encode(constructObject(exec));
+ return JSValue::encode(constructObject(exec, exec->newTarget()));
}
ConstructType ObjectConstructor::getConstructData(JSCell*, ConstructData& constructData)
@@ -141,7 +159,7 @@
static EncodedJSValue JSC_HOST_CALL callObjectConstructor(ExecState* exec)
{
- return JSValue::encode(constructObject(exec));
+ return JSValue::encode(constructObject(exec, JSValue()));
}
CallType ObjectConstructor::getCallData(JSCell*, CallData& callData)
diff --git a/Source/JavaScriptCore/runtime/ObjectConstructor.h b/Source/JavaScriptCore/runtime/ObjectConstructor.h
index 1b22ab6..d148ab0 100644
--- a/Source/JavaScriptCore/runtime/ObjectConstructor.h
+++ b/Source/JavaScriptCore/runtime/ObjectConstructor.h
@@ -88,7 +88,7 @@
inline JSObject* constructEmptyObject(ExecState* exec)
{
- return constructEmptyObject(exec, exec->lexicalGlobalObject()->objectPrototype());
+ return constructEmptyObject(exec, exec->lexicalGlobalObject()->objectStructureForObjectConstructor());
}
// Section 6.2.4.4 of the ES6 specification.
diff --git a/Source/JavaScriptCore/tests/stress/object-constructor-should-be-new-target-aware.js b/Source/JavaScriptCore/tests/stress/object-constructor-should-be-new-target-aware.js
new file mode 100644
index 0000000..aa392bd
--- /dev/null
+++ b/Source/JavaScriptCore/tests/stress/object-constructor-should-be-new-target-aware.js
@@ -0,0 +1,16 @@
+function shouldBe(actual, expected) {
+ if (actual !== expected)
+ throw new Error('bad value: ' + actual);
+}
+
+class Hello extends Object {
+ constructor()
+ {
+ super();
+ }
+}
+
+var hello = new Hello();
+shouldBe(hello.__proto__, Hello.prototype);
+
+shouldBe(Reflect.construct(Object, [], Hello).__proto__, Hello.prototype);