Add newTarget accessor to JS constructor written in C++
authorutatane.tea@gmail.com <utatane.tea@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 22 Jul 2015 00:29:39 +0000 (00:29 +0000)
committerutatane.tea@gmail.com <utatane.tea@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 22 Jul 2015 00:29:39 +0000 (00:29 +0000)
https://bugs.webkit.org/show_bug.cgi?id=147160

Reviewed by Geoffrey Garen.

This patch adds `ExecState#newTarget()` which returns `new.target` defined in ECMA262 6th.
It enables some C++ constructors (like Intl.XXX constructors) to leverage this to complete
its implementation.

When the constructor is called, |this| in the arguments is used for storing new.target instead.
So by adding the accessor for |this|, JS constructor written in C++ can access new.target.

And at the same time, this patch extends the existing `construct` to accept new.target value.
It is corresponding to the spec's Construct abstract operation.

* interpreter/CallFrame.h:
(JSC::ExecState::newTarget):
* interpreter/Interpreter.cpp:
(JSC::Interpreter::executeConstruct):
* interpreter/Interpreter.h:
* runtime/ConstructData.cpp:
(JSC::construct):
* runtime/ConstructData.h:
(JSC::construct):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@187142 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/interpreter/CallFrame.h
Source/JavaScriptCore/interpreter/Interpreter.cpp
Source/JavaScriptCore/interpreter/Interpreter.h
Source/JavaScriptCore/runtime/ConstructData.cpp
Source/JavaScriptCore/runtime/ConstructData.h

index 6afb5e2..ac686cd 100644 (file)
@@ -1,3 +1,30 @@
+2015-07-21  Yusuke Suzuki  <utatane.tea@gmail.com>
+
+        Add newTarget accessor to JS constructor written in C++
+        https://bugs.webkit.org/show_bug.cgi?id=147160
+
+        Reviewed by Geoffrey Garen.
+
+        This patch adds `ExecState#newTarget()` which returns `new.target` defined in ECMA262 6th.
+        It enables some C++ constructors (like Intl.XXX constructors) to leverage this to complete
+        its implementation.
+
+        When the constructor is called, |this| in the arguments is used for storing new.target instead.
+        So by adding the accessor for |this|, JS constructor written in C++ can access new.target.
+
+        And at the same time, this patch extends the existing `construct` to accept new.target value.
+        It is corresponding to the spec's Construct abstract operation.
+
+        * interpreter/CallFrame.h:
+        (JSC::ExecState::newTarget):
+        * interpreter/Interpreter.cpp:
+        (JSC::Interpreter::executeConstruct):
+        * interpreter/Interpreter.h:
+        * runtime/ConstructData.cpp:
+        (JSC::construct):
+        * runtime/ConstructData.h:
+        (JSC::construct):
+
 2015-07-21  Filip Pizlo  <fpizlo@apple.com>
 
         Unreviewed, fix a lot of tests. Need to initialize WTF threading sooner.
index 806ccea..afa8d3c 100644 (file)
@@ -251,6 +251,10 @@ namespace JSC  {
         JSValue thisValue() { return this[thisArgumentOffset()].jsValue(); }
         void setThisValue(JSValue value) { this[thisArgumentOffset()] = value; }
 
+        // Under the constructor implemented in C++, thisValue holds the newTarget instead of the automatically constructed value.
+        // The result of this function is only effective under the "construct" context.
+        JSValue newTarget() { return thisValue(); }
+
         JSValue argumentAfterCapture(size_t argument);
 
         static int offsetFor(size_t argumentCountIncludingThis) { return argumentCountIncludingThis + JSStack::ThisArgument - 1; }
index 687140e..bf94b90 100644 (file)
@@ -976,7 +976,7 @@ JSValue Interpreter::executeCall(CallFrame* callFrame, JSObject* function, CallT
     return checkedReturn(result);
 }
 
-JSObject* Interpreter::executeConstruct(CallFrame* callFrame, JSObject* constructor, ConstructType constructType, const ConstructData& constructData, const ArgList& args)
+JSObject* Interpreter::executeConstruct(CallFrame* callFrame, JSObject* constructor, ConstructType constructType, const ConstructData& constructData, const ArgList& args, JSValue newTarget)
 {
     VM& vm = callFrame->vm();
     ASSERT(!callFrame->hadException());
@@ -1021,7 +1021,7 @@ JSObject* Interpreter::executeConstruct(CallFrame* callFrame, JSObject* construc
         return throwTerminatedExecutionException(callFrame);
 
     ProtoCallFrame protoCallFrame;
-    protoCallFrame.init(newCodeBlock, constructor, constructor, argsCount, args.data());
+    protoCallFrame.init(newCodeBlock, constructor, newTarget, argsCount, args.data());
 
     if (LegacyProfiler* profiler = vm.enabledProfiler())
         profiler->willExecute(callFrame, constructor);
index ef4ec0d..ad9df6f 100644 (file)
@@ -208,7 +208,7 @@ namespace JSC {
 
         JSValue execute(ProgramExecutable*, CallFrame*, JSObject* thisObj);
         JSValue executeCall(CallFrame*, JSObject* function, CallType, const CallData&, JSValue thisValue, const ArgList&);
-        JSObject* executeConstruct(CallFrame*, JSObject* function, ConstructType, const ConstructData&, const ArgList&);
+        JSObject* executeConstruct(CallFrame*, JSObject* function, ConstructType, const ConstructData&, const ArgList&, JSValue newTarget);
         JSValue execute(EvalExecutable*, CallFrame*, JSValue thisValue, JSScope*);
 
         void getArgumentsData(CallFrame*, JSFunction*&, ptrdiff_t& firstParameterIndex, Register*& argv, int& argc);
index 7445cc6..6010e63 100644 (file)
 
 namespace JSC {
 
-JSObject* construct(ExecState* exec, JSValue constructorObject, ConstructType constructType, const ConstructData& constructData, const ArgList& args)
+JSObject* construct(ExecState* exec, JSValue constructorObject, ConstructType constructType, const ConstructData& constructData, const ArgList& args, JSValue newTarget)
 {
     ASSERT(constructType == ConstructTypeJS || constructType == ConstructTypeHost);
-    return exec->interpreter()->executeConstruct(exec, asObject(constructorObject), constructType, constructData, args);
+    return exec->interpreter()->executeConstruct(exec, asObject(constructorObject), constructType, constructData, args, newTarget);
 }
 
 } // namespace JSC
index 8d4ed8f..17e1a5d 100644 (file)
@@ -56,7 +56,12 @@ union ConstructData {
     } js;
 };
 
-JS_EXPORT_PRIVATE JSObject* construct(ExecState*, JSValue constructor, ConstructType, const ConstructData&, const ArgList&);
+JS_EXPORT_PRIVATE JSObject* construct(ExecState*, JSValue constructor, ConstructType, const ConstructData&, const ArgList&, JSValue newTarget);
+
+ALWAYS_INLINE JSObject* construct(ExecState* exec, JSValue constructorObject, ConstructType constructType, const ConstructData& constructData, const ArgList& args)
+{
+    return construct(exec, constructorObject, constructType, constructData, args, constructorObject);
+}
 
 } // namespace JSC