1 /****************************************************************************
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
5 **
6 ** This file is part of the QtScript module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39 
40 #include "config.h"
41 #include "qscriptfunction_p.h"
42 
43 #include "private/qscriptengine_p.h"
44 #include "qscriptcontext.h"
45 #include "private/qscriptcontext_p.h"
46 #include "private/qscriptvalue_p.h"
47 #include "qscriptactivationobject_p.h"
48 #include "qscriptobject_p.h"
49 
50 #include "JSGlobalObject.h"
51 #include "DebuggerCallFrame.h"
52 #include "Debugger.h"
53 
54 namespace JSC
55 {
56 ASSERT_CLASS_FITS_IN_CELL(QT_PREPEND_NAMESPACE(QScript::FunctionWrapper));
57 ASSERT_CLASS_FITS_IN_CELL(QT_PREPEND_NAMESPACE(QScript::FunctionWithArgWrapper));
58 }
59 
60 QT_BEGIN_NAMESPACE
61 
62 namespace QScript
63 {
64 
65 const JSC::ClassInfo FunctionWrapper::info = { "QtNativeFunctionWrapper", &PrototypeFunction::info, 0, 0 };
66 const JSC::ClassInfo FunctionWithArgWrapper::info = { "QtNativeFunctionWithArgWrapper", &PrototypeFunction::info, 0, 0 };
67 
FunctionWrapper(JSC::ExecState * exec,int length,const JSC::Identifier & name,QScriptEngine::FunctionSignature function)68 FunctionWrapper::FunctionWrapper(JSC::ExecState *exec, int length, const JSC::Identifier &name,
69                                  QScriptEngine::FunctionSignature function)
70     : JSC::PrototypeFunction(exec, length, name, proxyCall),
71       data(new Data())
72 {
73     data->function = function;
74 }
75 
~FunctionWrapper()76 FunctionWrapper::~FunctionWrapper()
77 {
78     delete data;
79 }
80 
getConstructData(JSC::ConstructData & consData)81 JSC::ConstructType FunctionWrapper::getConstructData(JSC::ConstructData& consData)
82 {
83     consData.native.function = proxyConstruct;
84     consData.native.function.doNotCallDebuggerFunctionExit();
85     return JSC::ConstructTypeHost;
86 }
87 
proxyCall(JSC::ExecState * exec,JSC::JSObject * callee,JSC::JSValue thisObject,const JSC::ArgList & args)88 JSC::JSValue FunctionWrapper::proxyCall(JSC::ExecState *exec, JSC::JSObject *callee,
89                                         JSC::JSValue thisObject, const JSC::ArgList &args)
90 {
91     FunctionWrapper *self = static_cast<FunctionWrapper*>(callee);
92     QScriptEnginePrivate *eng_p = QScript::scriptEngineFromExec(exec);
93 
94     JSC::ExecState *oldFrame = eng_p->currentFrame;
95     eng_p->pushContext(exec, thisObject, args, callee);
96     QScriptContext *ctx = eng_p->contextForFrame(eng_p->currentFrame);
97 
98     QScriptValue result = self->data->function(ctx, QScriptEnginePrivate::get(eng_p));
99     if (!result.isValid())
100         result = QScriptValue(QScriptValue::UndefinedValue);
101 
102     eng_p->popContext();
103     eng_p->currentFrame = oldFrame;
104 
105     return eng_p->scriptValueToJSCValue(result);
106 }
107 
proxyConstruct(JSC::ExecState * exec,JSC::JSObject * callee,const JSC::ArgList & args)108 JSC::JSObject* FunctionWrapper::proxyConstruct(JSC::ExecState *exec, JSC::JSObject *callee,
109                                                const JSC::ArgList &args)
110 {
111     FunctionWrapper *self = static_cast<FunctionWrapper*>(callee);
112     QScriptEnginePrivate *eng_p = QScript::scriptEngineFromExec(exec);
113 
114     JSC::ExecState *oldFrame = eng_p->currentFrame;
115     eng_p->pushContext(exec, JSC::JSValue(), args, callee, true);
116     QScriptContext *ctx = eng_p->contextForFrame(eng_p->currentFrame);
117 
118     QScriptValue result = self->data->function(ctx, QScriptEnginePrivate::get(eng_p));
119 
120     if (JSC::Debugger* debugger = eng_p->originalGlobalObject()->debugger())
121         debugger->functionExit(QScriptValuePrivate::get(result)->jscValue, -1);
122 
123     if (!result.isObject())
124         result = ctx->thisObject();
125 
126     eng_p->popContext();
127     eng_p->currentFrame = oldFrame;
128 
129     return JSC::asObject(eng_p->scriptValueToJSCValue(result));
130 }
131 
FunctionWithArgWrapper(JSC::ExecState * exec,int length,const JSC::Identifier & name,QScriptEngine::FunctionWithArgSignature function,void * arg)132 FunctionWithArgWrapper::FunctionWithArgWrapper(JSC::ExecState *exec, int length, const JSC::Identifier &name,
133                                                QScriptEngine::FunctionWithArgSignature function, void *arg)
134     : JSC::PrototypeFunction(exec, length, name, proxyCall),
135       data(new Data())
136 {
137     data->function = function;
138     data->arg = arg;
139 }
140 
~FunctionWithArgWrapper()141 FunctionWithArgWrapper::~FunctionWithArgWrapper()
142 {
143     delete data;
144 }
145 
getConstructData(JSC::ConstructData & consData)146 JSC::ConstructType FunctionWithArgWrapper::getConstructData(JSC::ConstructData& consData)
147 {
148     consData.native.function = proxyConstruct;
149     return JSC::ConstructTypeHost;
150 }
151 
proxyCall(JSC::ExecState * exec,JSC::JSObject * callee,JSC::JSValue thisObject,const JSC::ArgList & args)152 JSC::JSValue FunctionWithArgWrapper::proxyCall(JSC::ExecState *exec, JSC::JSObject *callee,
153                                                JSC::JSValue thisObject, const JSC::ArgList &args)
154 {
155     FunctionWithArgWrapper *self = static_cast<FunctionWithArgWrapper*>(callee);
156     QScriptEnginePrivate *eng_p = QScript::scriptEngineFromExec(exec);
157 
158     JSC::ExecState *oldFrame = eng_p->currentFrame;
159     eng_p->pushContext(exec, thisObject, args, callee);
160     QScriptContext *ctx = eng_p->contextForFrame(eng_p->currentFrame);
161 
162     QScriptValue result = self->data->function(ctx, QScriptEnginePrivate::get(eng_p), self->data->arg);
163 
164     eng_p->popContext();
165     eng_p->currentFrame = oldFrame;
166 
167     return eng_p->scriptValueToJSCValue(result);
168 }
169 
proxyConstruct(JSC::ExecState * exec,JSC::JSObject * callee,const JSC::ArgList & args)170 JSC::JSObject* FunctionWithArgWrapper::proxyConstruct(JSC::ExecState *exec, JSC::JSObject *callee,
171                                                       const JSC::ArgList &args)
172 {
173     FunctionWithArgWrapper *self = static_cast<FunctionWithArgWrapper*>(callee);
174     QScriptEnginePrivate *eng_p = QScript::scriptEngineFromExec(exec);
175 
176     JSC::ExecState *oldFrame = eng_p->currentFrame;
177     eng_p->pushContext(exec, JSC::JSValue(), args, callee, true);
178     QScriptContext *ctx = eng_p->contextForFrame(eng_p->currentFrame);
179 
180     QScriptValue result = self->data->function(ctx, QScriptEnginePrivate::get(eng_p) , self->data->arg);
181     if (!result.isObject())
182         result = ctx->thisObject();
183 
184     eng_p->popContext();
185     eng_p->currentFrame = oldFrame;
186 
187     return JSC::asObject(eng_p->scriptValueToJSCValue(result));
188 }
189 
190 } // namespace QScript
191 
192 QT_END_NAMESPACE
193