Qt 6.x
The Qt SDK
Loading...
Searching...
No Matches
qv4stackframe_p.h
Go to the documentation of this file.
1// Copyright (C) 2018 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3#ifndef QV4STACKFRAME_H
4#define QV4STACKFRAME_H
5
6//
7// W A R N I N G
8// -------------
9//
10// This file is not part of the Qt API. It exists purely as an
11// implementation detail. This header file may change from version to
12// version without notice, or even be removed.
13//
14// We mean it.
15//
16
17#include <private/qv4scopedvalue_p.h>
18#include <private/qv4context_p.h>
19#include <private/qv4enginebase_p.h>
20#include <private/qv4calldata_p.h>
21#include <private/qv4function_p.h>
22
23#include <type_traits>
24
26
27namespace QV4 {
28
29struct CppStackFrame;
30struct Q_QML_PRIVATE_EXPORT CppStackFrameBase
31{
32 enum class Kind : quint8 { JS, Meta };
33
38
39 union {
40 struct {
44 const char *yield;
45 const char *unwindHandler;
46 const char *unwindLabel;
52 };
53 struct {
59 };
60 };
61
63};
64
65struct Q_QML_PRIVATE_EXPORT CppStackFrame : protected CppStackFrameBase
66{
67 // We want to have those public but we can't declare them as public without making the struct
68 // non-standard layout. So we have this other struct with "using" in between.
69 using CppStackFrameBase::instructionPointer;
70 using CppStackFrameBase::v4Function;
71
72 void init(Function *v4Function, int argc, Kind kind) {
73 this->v4Function = v4Function;
74 originalArgumentsCount = argc;
75 instructionPointer = 0;
76 this->kind = kind;
77 }
78
79 bool isJSTypesFrame() const { return kind == Kind::JS; }
80 bool isMetaTypesFrame() const { return kind == Kind::Meta; }
81
82 QString source() const;
83 QString function() const;
84 int lineNumber() const;
85 int statementNumber() const;
86
87 int missingLineNumber() const;
88
89 CppStackFrame *parentFrame() const { return parent; }
90 void setParentFrame(CppStackFrame *parentFrame) { parent = parentFrame; }
91
92 int argc() const { return originalArgumentsCount; }
93
94 inline ExecutionContext *context() const;
95
96 Heap::CallContext *callContext() const { return callContext(context()->d()); }
97 ReturnedValue thisObject() const;
98
99protected:
100 CppStackFrame() = default;
101
103 {
104 Q_ASSERT(kind == Kind::JS || kind == Kind::Meta);
105 parent = engine->currentStackFrame;
106 engine->currentStackFrame = this;
107 }
108
110 {
111 engine->currentStackFrame = parent;
112 }
113
114 Heap::CallContext *callContext(Heap::ExecutionContext *ctx) const
115 {
116 while (ctx->type != Heap::ExecutionContext::Type_CallContext)
117 ctx = ctx->outer;
118 return static_cast<Heap::CallContext *>(ctx);
119 }
120};
121
122struct Q_QML_PRIVATE_EXPORT MetaTypesStackFrame : public CppStackFrame
123{
124 using CppStackFrame::push;
125 using CppStackFrame::pop;
126
127 void init(Function *v4Function, QObject *thisObject, ExecutionContext *context,
128 void **returnAndArgs, const QMetaType *metaTypes, int argc)
129 {
130 CppStackFrame::init(v4Function, argc, Kind::Meta);
131 CppStackFrameBase::thisObject = thisObject;
132 CppStackFrameBase::context = context;
133 CppStackFrameBase::metaTypes = metaTypes;
134 CppStackFrameBase::returnAndArgs = returnAndArgs;
135 CppStackFrameBase::returnValueIsUndefined = false;
136 }
137
138 QMetaType returnType() const { return metaTypes[0]; }
139 void *returnValue() const { return returnAndArgs[0]; }
140
141 bool isReturnValueUndefined() const { return CppStackFrameBase::returnValueIsUndefined; }
142 void setReturnValueUndefined() { CppStackFrameBase::returnValueIsUndefined = true; }
143
144 const QMetaType *argTypes() const { return metaTypes + 1; }
145 void **argv() const { return returnAndArgs + 1; }
146
147 QObject *thisObject() const { return CppStackFrameBase::thisObject; }
148
149 ExecutionContext *context() const { return CppStackFrameBase::context; }
150 void setContext(ExecutionContext *context) { CppStackFrameBase::context = context; }
151
152 Heap::CallContext *callContext() const
153 {
154 return CppStackFrame::callContext(CppStackFrameBase::context->d());
155 }
156};
157
158struct Q_QML_PRIVATE_EXPORT JSTypesStackFrame : public CppStackFrame
159{
160 using CppStackFrame::jsFrame;
161
162 // The JIT needs to poke directly into those using offsetof
163 using CppStackFrame::unwindHandler;
164 using CppStackFrame::unwindLabel;
165 using CppStackFrame::unwindLevel;
166
167 void init(Function *v4Function, const Value *argv, int argc,
168 bool callerCanHandleTailCall = false)
169 {
170 CppStackFrame::init(v4Function, argc, Kind::JS);
171 CppStackFrame::originalArguments = argv;
172 CppStackFrame::yield = nullptr;
173 CppStackFrame::unwindHandler = nullptr;
174 CppStackFrame::yieldIsIterator = false;
175 CppStackFrame::callerCanHandleTailCall = callerCanHandleTailCall;
176 CppStackFrame::pendingTailCall = false;
177 CppStackFrame::isTailCalling = false;
178 CppStackFrame::unwindLabel = nullptr;
179 CppStackFrame::unwindLevel = 0;
180 }
181
182 const Value *argv() const { return originalArguments; }
183
184 static uint requiredJSStackFrameSize(uint nRegisters) {
185 return CallData::HeaderSize() + nRegisters;
186 }
188 return CallData::HeaderSize() + v4Function->compiledFunction->nRegisters;
189 }
191 return requiredJSStackFrameSize(v4Function);
192 }
193
194 void setupJSFrame(Value *stackSpace, const Value &function, const Heap::ExecutionContext *scope,
195 const Value &thisObject, const Value &newTarget = Value::undefinedValue()) {
196 setupJSFrame(stackSpace, function, scope, thisObject, newTarget,
197 v4Function->compiledFunction->nFormals,
198 v4Function->compiledFunction->nRegisters);
199 }
200
202 Value *stackSpace, const Value &function, const Heap::ExecutionContext *scope,
203 const Value &thisObject, const Value &newTarget, uint nFormals, uint nRegisters)
204 {
205 jsFrame = reinterpret_cast<CallData *>(stackSpace);
206 jsFrame->function = function;
207 jsFrame->context = scope->asReturnedValue();
208 jsFrame->accumulator = Encode::undefined();
209 jsFrame->thisObject = thisObject;
210 jsFrame->newTarget = newTarget;
211
212 uint argc = uint(originalArgumentsCount);
213 if (argc > nFormals)
214 argc = nFormals;
215 jsFrame->setArgc(argc);
216
217 // memcpy requires non-null ptr, even if argc * sizeof(Value) == 0
218 if (originalArguments)
219 memcpy(jsFrame->args, originalArguments, argc * sizeof(Value));
220 Q_STATIC_ASSERT(Encode::undefined() == 0);
221 memset(jsFrame->args + argc, 0, (nRegisters - argc) * sizeof(Value));
222
223 if (v4Function && v4Function->compiledFunction) {
224 const int firstDeadZoneRegister
225 = v4Function->compiledFunction->firstTemporalDeadZoneRegister;
226 const int registerDeadZoneSize
227 = v4Function->compiledFunction->sizeOfRegisterTemporalDeadZone;
228
229 const Value * tdzEnd = stackSpace + firstDeadZoneRegister + registerDeadZoneSize;
230 for (Value *v = stackSpace + firstDeadZoneRegister; v < tdzEnd; ++v)
231 *v = Value::emptyValue().asReturnedValue();
232 }
233 }
234
236 {
237 return static_cast<ExecutionContext *>(&jsFrame->context);
238 }
239
241 {
242 jsFrame->context = context;
243 }
244
245 Heap::CallContext *callContext() const
246 {
247 return CppStackFrame::callContext(static_cast<ExecutionContext &>(jsFrame->context).d());
248 }
249
250 bool isTailCalling() const { return CppStackFrame::isTailCalling; }
251 void setTailCalling(bool tailCalling) { CppStackFrame::isTailCalling = tailCalling; }
252
253 bool pendingTailCall() const { return CppStackFrame::pendingTailCall; }
254 void setPendingTailCall(bool pending) { CppStackFrame::pendingTailCall = pending; }
255
256 const char *yield() const { return CppStackFrame::yield; }
257 void setYield(const char *yield) { CppStackFrame::yield = yield; }
258
259 bool yieldIsIterator() const { return CppStackFrame::yieldIsIterator; }
260 void setYieldIsIterator(bool isIter) { CppStackFrame::yieldIsIterator = isIter; }
261
262 bool callerCanHandleTailCall() const { return CppStackFrame::callerCanHandleTailCall; }
263
265 {
266 return jsFrame->thisObject.asReturnedValue();
267 }
268
269 Value *framePointer() const { return savedStackTop; }
270
272 CppStackFrame::push(engine);
273 savedStackTop = engine->jsStackTop;
274 }
275
277 CppStackFrame::pop(engine);
278 engine->jsStackTop = savedStackTop;
279 }
280};
281
283{
284 if (isJSTypesFrame())
285 return static_cast<const JSTypesStackFrame *>(this)->context();
286
288 return static_cast<const MetaTypesStackFrame *>(this)->context();
289}
290
292{
294 : engine(scope.engine)
295 {
296 if (auto currentFrame = engine->currentStackFrame) {
297 frame.init(currentFrame->v4Function, nullptr, context, nullptr, nullptr, 0);
298 frame.instructionPointer = currentFrame->instructionPointer;
299 } else {
300 frame.init(nullptr, nullptr, context, nullptr, nullptr, 0);
301 }
302 frame.push(engine);
303 }
304
306 {
307 frame.pop(engine);
308 }
309
310private:
311 ExecutionEngine *engine = nullptr;
313};
314
317Q_STATIC_ASSERT(std::is_standard_layout_v<CppStackFrame>);
318Q_STATIC_ASSERT(std::is_standard_layout_v<JSTypesStackFrame>);
319Q_STATIC_ASSERT(std::is_standard_layout_v<MetaTypesStackFrame>);
320
321}
322
324
325#endif
\inmodule QtCore
Definition qmetatype.h:320
\inmodule QtCore
Definition qobject.h:90
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:127
EGLContext ctx
Combined button and popup list for selecting options.
\qmltype Particle \inqmlmodule QtQuick.Particles
quint64 ReturnedValue
static void * context
#define Q_STATIC_ASSERT(Condition)
Definition qassert.h:105
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction function
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter int const void return DBusMessageIter DBusMessageIter return DBusMessageIter void DBusMessageIter void int return DBusMessage DBusMessageIter return DBusMessageIter return DBusMessageIter DBusMessageIter const char const char const char const char return DBusMessage return DBusMessage const char return DBusMessage dbus_bool_t return DBusMessage dbus_uint32_t return DBusMessage return DBusPendingCall * pending
GLsizei const GLfloat * v
[13]
GLsizei GLsizei GLchar * source
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
unsigned int uint
Definition qtypes.h:29
unsigned char quint8
Definition qtypes.h:41
QJSEngine engine
[0]
StaticValue function
const Value * originalArguments
ExecutionContext * context
const QMetaType * metaTypes
bool isJSTypesFrame() const
void setParentFrame(CppStackFrame *parentFrame)
Heap::CallContext * callContext(Heap::ExecutionContext *ctx) const
void init(Function *v4Function, int argc, Kind kind)
void pop(EngineBase *engine)
ExecutionContext * context() const
void push(EngineBase *engine)
CppStackFrame()=default
Heap::CallContext * callContext() const
CppStackFrame * parentFrame() const
bool isMetaTypesFrame() const
CppStackFrame * currentStackFrame
const CompiledData::Function * compiledFunction
Heap::CallContext * callContext() const
void setYield(const char *yield)
static uint requiredJSStackFrameSize(Function *v4Function)
ReturnedValue thisObject() const
void setYieldIsIterator(bool isIter)
void setContext(ExecutionContext *context)
static uint requiredJSStackFrameSize(uint nRegisters)
const Value * argv() const
bool callerCanHandleTailCall() const
void setupJSFrame(Value *stackSpace, const Value &function, const Heap::ExecutionContext *scope, const Value &thisObject, const Value &newTarget=Value::undefinedValue())
ExecutionContext * context() const
const char * yield() const
void setTailCalling(bool tailCalling)
void push(EngineBase *engine)
uint requiredJSStackFrameSize() const
void init(Function *v4Function, const Value *argv, int argc, bool callerCanHandleTailCall=false)
Value * framePointer() const
void setPendingTailCall(bool pending)
void pop(EngineBase *engine)
void setupJSFrame(Value *stackSpace, const Value &function, const Heap::ExecutionContext *scope, const Value &thisObject, const Value &newTarget, uint nFormals, uint nRegisters)
ExecutionContext * context() const
void setContext(ExecutionContext *context)
void pop(EngineBase *engine)
const QMetaType * argTypes() const
QObject * thisObject() const
Heap::CallContext * callContext() const
void push(EngineBase *engine)
QMetaType returnType() const
void init(Function *v4Function, QObject *thisObject, ExecutionContext *context, void **returnAndArgs, const QMetaType *metaTypes, int argc)
bool isReturnValueUndefined() const
ScopedStackFrame(const Scope &scope, ExecutionContext *context)
constexpr ReturnedValue asReturnedValue() const
IUIAutomationTreeWalker __RPC__deref_out_opt IUIAutomationElement ** parent