1 /****************************************************************************
2 **
3 ** Copyright (C) 2018 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the QtQml 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 #ifndef QV4STACKFRAME_H
40 #define QV4STACKFRAME_H
41 
42 //
43 //  W A R N I N G
44 //  -------------
45 //
46 // This file is not part of the Qt API.  It exists purely as an
47 // implementation detail.  This header file may change from version to
48 // version without notice, or even be removed.
49 //
50 // We mean it.
51 //
52 
53 #include <private/qv4context_p.h>
54 #include <private/qv4enginebase_p.h>
55 #include <private/qv4calldata_p.h>
56 #include <private/qv4function_p.h>
57 
58 QT_BEGIN_NAMESPACE
59 
60 namespace QV4 {
61 
62 struct Q_QML_EXPORT CppStackFrame {
63     EngineBase *engine;
64     Value *savedStackTop;
65     CppStackFrame *parent;
66     Function *v4Function;
67     CallData *jsFrame;
68     const Value *originalArguments;
69     int originalArgumentsCount;
70     int instructionPointer;
71     const char *yield;
72     const char *unwindHandler;
73     const char *unwindLabel;
74     int unwindLevel;
75     bool yieldIsIterator;
76     bool callerCanHandleTailCall;
77     bool pendingTailCall;
78     bool isTailCalling;
79 
80     void init(EngineBase *engine, Function *v4Function, const Value *argv, int argc, bool callerCanHandleTailCall = false) {
81         this->engine = engine;
82 
83         this->v4Function = v4Function;
84         originalArguments = argv;
85         originalArgumentsCount = argc;
86         instructionPointer = 0;
87         yield = nullptr;
88         unwindHandler = nullptr;
89         unwindLabel = nullptr;
90         unwindLevel = 0;
91         yieldIsIterator = false;
92         this->callerCanHandleTailCall = callerCanHandleTailCall;
93         pendingTailCall = false;
94         isTailCalling = false;
95     }
96 
pushCppStackFrame97     void push() {
98         parent = engine->currentStackFrame;
99         engine->currentStackFrame = this;
100         savedStackTop = engine->jsStackTop;
101     }
102 
popCppStackFrame103     void pop() {
104         engine->currentStackFrame = parent;
105         engine->jsStackTop = savedStackTop;
106     }
107 
requiredJSStackFrameSizeCppStackFrame108     static uint requiredJSStackFrameSize(uint nRegisters) {
109         return CallData::HeaderSize() + nRegisters;
110     }
requiredJSStackFrameSizeCppStackFrame111     static uint requiredJSStackFrameSize(Function *v4Function) {
112         return CallData::HeaderSize() + v4Function->compiledFunction->nRegisters;
113     }
requiredJSStackFrameSizeCppStackFrame114     uint requiredJSStackFrameSize() const {
115         return requiredJSStackFrameSize(v4Function);
116     }
117     void setupJSFrame(Value *stackSpace, const Value &function, const Heap::ExecutionContext *scope,
118                       const Value &thisObject, const Value &newTarget = Value::undefinedValue()) {
119         setupJSFrame(stackSpace, function, scope, thisObject, newTarget,
120                      v4Function->compiledFunction->nFormals, v4Function->compiledFunction->nRegisters);
121     }
setupJSFrameCppStackFrame122     void setupJSFrame(Value *stackSpace, const Value &function, const Heap::ExecutionContext *scope,
123                       const Value &thisObject, const Value &newTarget, uint nFormals, uint nRegisters)
124     {
125         jsFrame = reinterpret_cast<CallData *>(stackSpace);
126         jsFrame->function = function;
127         jsFrame->context = scope->asReturnedValue();
128         jsFrame->accumulator = Encode::undefined();
129         jsFrame->thisObject = thisObject;
130         jsFrame->newTarget = newTarget;
131 
132         uint argc = uint(originalArgumentsCount);
133         if (argc > nFormals)
134             argc = nFormals;
135         jsFrame->setArgc(argc);
136 
137         memcpy(jsFrame->args, originalArguments, argc*sizeof(Value));
138         Q_STATIC_ASSERT(Encode::undefined() == 0);
139         memset(jsFrame->args + argc, 0, (nRegisters - argc)*sizeof(Value));
140 
141         if (v4Function && v4Function->compiledFunction) {
142             const int firstDeadZoneRegister = v4Function->compiledFunction->firstTemporalDeadZoneRegister;
143             const int registerDeadZoneSize = v4Function->compiledFunction->sizeOfRegisterTemporalDeadZone;
144 
145             const Value * tdzEnd = stackSpace + firstDeadZoneRegister + registerDeadZoneSize;
146             for (Value *v = stackSpace + firstDeadZoneRegister; v < tdzEnd; ++v)
147                 *v = Value::emptyValue().asReturnedValue();
148         }
149     }
150 
151     QString source() const;
152     QString function() const;
contextCppStackFrame153     inline QV4::ExecutionContext *context() const {
154         return static_cast<ExecutionContext *>(&jsFrame->context);
155     }
156     int lineNumber() const;
157 
callContextCppStackFrame158     inline QV4::Heap::CallContext *callContext() const {
159         Heap::ExecutionContext *ctx = static_cast<ExecutionContext &>(jsFrame->context).d();\
160         while (ctx->type != Heap::ExecutionContext::Type_CallContext)
161             ctx = ctx->outer;
162         return static_cast<Heap::CallContext *>(ctx);
163     }
164     ReturnedValue thisObject() const;
165 };
166 
167 }
168 
169 QT_END_NAMESPACE
170 
171 #endif
172