Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
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_EXPORT CppStackFrameBase
31{
32 enum class Kind : quint8 { JS, Meta };
33
38
40 QT_WARNING_DISABLE_MSVC(4201) // nonstandard extension used: nameless struct/union
41 union {
42 struct {
46 const char *yield;
47 const char *unwindHandler;
48 const char *unwindLabel;
54 };
55 struct {
61 };
62 };
64
66};
67
68struct Q_QML_EXPORT CppStackFrame : protected CppStackFrameBase
69{
70 // We want to have those public but we can't declare them as public without making the struct
71 // non-standard layout. So we have this other struct with "using" in between.
72 using CppStackFrameBase::instructionPointer;
73 using CppStackFrameBase::v4Function;
74
75 void init(Function *v4Function, int argc, Kind kind) {
76 this->v4Function = v4Function;
77 originalArgumentsCount = argc;
78 instructionPointer = 0;
79 this->kind = kind;
80 }
81
82 bool isJSTypesFrame() const { return kind == Kind::JS; }
83 bool isMetaTypesFrame() const { return kind == Kind::Meta; }
84
85 QString source() const;
86 QString function() const;
87 int lineNumber() const;
88 int statementNumber() const;
89
90 int missingLineNumber() const;
91
92 CppStackFrame *parentFrame() const { return parent; }
93 void setParentFrame(CppStackFrame *parentFrame) { parent = parentFrame; }
94
95 int argc() const { return originalArgumentsCount; }
96
97 inline ExecutionContext *context() const;
98
99 Heap::CallContext *callContext() const { return callContext(context()->d()); }
100 ReturnedValue thisObject() const;
101
102protected:
103 CppStackFrame() = default;
104
106 {
107 Q_ASSERT(kind == Kind::JS || kind == Kind::Meta);
108 parent = engine->currentStackFrame;
109 engine->currentStackFrame = this;
110 }
111
113 {
114 engine->currentStackFrame = parent;
115 }
116
117 Heap::CallContext *callContext(Heap::ExecutionContext *ctx) const
118 {
119 while (ctx->type != Heap::ExecutionContext::Type_CallContext)
120 ctx = ctx->outer;
121 return static_cast<Heap::CallContext *>(ctx);
122 }
123};
124
125struct Q_QML_EXPORT MetaTypesStackFrame : public CppStackFrame
126{
127 using CppStackFrame::push;
128 using CppStackFrame::pop;
129
130 void init(Function *v4Function, QObject *thisObject, ExecutionContext *context,
131 void **returnAndArgs, const QMetaType *metaTypes, int argc)
132 {
133 CppStackFrame::init(v4Function, argc, Kind::Meta);
134 CppStackFrameBase::thisObject = thisObject;
135 CppStackFrameBase::context = context;
136 CppStackFrameBase::metaTypes = metaTypes;
137 CppStackFrameBase::returnAndArgs = returnAndArgs;
138 CppStackFrameBase::returnValueIsUndefined = false;
139 }
140
141 QMetaType returnType() const { return metaTypes[0]; }
142 void *returnValue() const { return returnAndArgs[0]; }
143
144 bool isReturnValueUndefined() const { return CppStackFrameBase::returnValueIsUndefined; }
145 void setReturnValueUndefined() { CppStackFrameBase::returnValueIsUndefined = true; }
146
147 const QMetaType *argTypes() const { return metaTypes + 1; }
148 void **argv() const { return returnAndArgs + 1; }
149
150 const QMetaType *returnAndArgTypes() const { return metaTypes; }
151 void **returnAndArgValues() const { return returnAndArgs; }
152
153 QObject *thisObject() const { return CppStackFrameBase::thisObject; }
154
155 ExecutionContext *context() const { return CppStackFrameBase::context; }
156 void setContext(ExecutionContext *context) { CppStackFrameBase::context = context; }
157
158 Heap::CallContext *callContext() const
159 {
160 return CppStackFrame::callContext(CppStackFrameBase::context->d());
161 }
162};
163
164struct Q_QML_EXPORT JSTypesStackFrame : public CppStackFrame
165{
166 using CppStackFrame::jsFrame;
167
168 // The JIT needs to poke directly into those using offsetof
169 using CppStackFrame::unwindHandler;
170 using CppStackFrame::unwindLabel;
171 using CppStackFrame::unwindLevel;
172
173 void init(Function *v4Function, const Value *argv, int argc,
174 bool callerCanHandleTailCall = false)
175 {
176 CppStackFrame::init(v4Function, argc, Kind::JS);
177 CppStackFrame::originalArguments = argv;
178 CppStackFrame::yield = nullptr;
179 CppStackFrame::unwindHandler = nullptr;
180 CppStackFrame::yieldIsIterator = false;
181 CppStackFrame::callerCanHandleTailCall = callerCanHandleTailCall;
182 CppStackFrame::pendingTailCall = false;
183 CppStackFrame::isTailCalling = false;
184 CppStackFrame::unwindLabel = nullptr;
185 CppStackFrame::unwindLevel = 0;
186 }
187
188 const Value *argv() const { return originalArguments; }
189
190 static uint requiredJSStackFrameSize(uint nRegisters) {
191 return CallData::HeaderSize() + nRegisters;
192 }
194 return CallData::HeaderSize() + v4Function->compiledFunction->nRegisters;
195 }
197 return requiredJSStackFrameSize(v4Function);
198 }
199
200 void setupJSFrame(Value *stackSpace, const Value &function, const Heap::ExecutionContext *scope,
201 const Value &thisObject, const Value &newTarget = Value::undefinedValue()) {
202 setupJSFrame(stackSpace, function, scope, thisObject, newTarget,
203 v4Function->compiledFunction->nFormals,
204 v4Function->compiledFunction->nRegisters);
205 }
206
208 Value *stackSpace, const Value &function, const Heap::ExecutionContext *scope,
209 const Value &thisObject, const Value &newTarget, uint nFormals, uint nRegisters)
210 {
211 jsFrame = reinterpret_cast<CallData *>(stackSpace);
212 jsFrame->function = function;
213 jsFrame->context = scope->asReturnedValue();
214 jsFrame->accumulator = Encode::undefined();
215 jsFrame->thisObject = thisObject;
216 jsFrame->newTarget = newTarget;
217
218 uint argc = uint(originalArgumentsCount);
219 if (argc > nFormals)
220 argc = nFormals;
221 jsFrame->setArgc(argc);
222
223 // memcpy requires non-null ptr, even if argc * sizeof(Value) == 0
224 if (originalArguments)
225 memcpy(jsFrame->args, originalArguments, argc * sizeof(Value));
226 Q_STATIC_ASSERT(Encode::undefined() == 0);
227 memset(jsFrame->args + argc, 0, (nRegisters - argc) * sizeof(Value));
228
229 if (v4Function && v4Function->compiledFunction) {
230 const int firstDeadZoneRegister
231 = v4Function->compiledFunction->firstTemporalDeadZoneRegister;
232 const int registerDeadZoneSize
233 = v4Function->compiledFunction->sizeOfRegisterTemporalDeadZone;
234
235 const Value * tdzEnd = stackSpace + firstDeadZoneRegister + registerDeadZoneSize;
236 for (Value *v = stackSpace + firstDeadZoneRegister; v < tdzEnd; ++v)
237 *v = Value::emptyValue().asReturnedValue();
238 }
239 }
240
242 {
243 return static_cast<ExecutionContext *>(&jsFrame->context);
244 }
245
247 {
248 jsFrame->context = context;
249 }
250
251 Heap::CallContext *callContext() const
252 {
253 return CppStackFrame::callContext(static_cast<ExecutionContext &>(jsFrame->context).d());
254 }
255
256 bool isTailCalling() const { return CppStackFrame::isTailCalling; }
257 void setTailCalling(bool tailCalling) { CppStackFrame::isTailCalling = tailCalling; }
258
259 bool pendingTailCall() const { return CppStackFrame::pendingTailCall; }
260 void setPendingTailCall(bool pending) { CppStackFrame::pendingTailCall = pending; }
261
262 const char *yield() const { return CppStackFrame::yield; }
263 void setYield(const char *yield) { CppStackFrame::yield = yield; }
264
265 bool yieldIsIterator() const { return CppStackFrame::yieldIsIterator; }
266 void setYieldIsIterator(bool isIter) { CppStackFrame::yieldIsIterator = isIter; }
267
268 bool callerCanHandleTailCall() const { return CppStackFrame::callerCanHandleTailCall; }
269
271 {
272 return jsFrame->thisObject.asReturnedValue();
273 }
274
275 Value *framePointer() const { return savedStackTop; }
276
278 CppStackFrame::push(engine);
279 savedStackTop = engine->jsStackTop;
280 }
281
283 CppStackFrame::pop(engine);
284 engine->jsStackTop = savedStackTop;
285 }
286};
287
289{
290 if (isJSTypesFrame())
291 return static_cast<const JSTypesStackFrame *>(this)->context();
292
294 return static_cast<const MetaTypesStackFrame *>(this)->context();
295}
296
298{
300 : engine(scope.engine)
301 {
302 if (auto currentFrame = engine->currentStackFrame) {
303 frame.init(currentFrame->v4Function, nullptr, context, nullptr, nullptr, 0);
304 frame.instructionPointer = currentFrame->instructionPointer;
305 } else {
306 frame.init(nullptr, nullptr, context, nullptr, nullptr, 0);
307 }
308 frame.push(engine);
309 }
310
312 {
313 frame.pop(engine);
314 }
315
316private:
317 ExecutionEngine *engine = nullptr;
319};
320
323Q_STATIC_ASSERT(std::is_standard_layout_v<CppStackFrame>);
324Q_STATIC_ASSERT(std::is_standard_layout_v<JSTypesStackFrame>);
325Q_STATIC_ASSERT(std::is_standard_layout_v<MetaTypesStackFrame>);
326
327}
328
330
331#endif
\inmodule QtCore
Definition qmetatype.h:341
\inmodule QtCore
Definition qobject.h:103
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
EGLContext ctx
Combined button and popup list for selecting options.
quint64 ReturnedValue
static void * context
#define Q_STATIC_ASSERT(Condition)
Definition qassert.h:108
#define QT_WARNING_POP
#define QT_WARNING_DISABLE_MSVC(number)
#define QT_WARNING_PUSH
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:34
unsigned char quint8
Definition qtypes.h:46
QJSEngine engine
[0]
StaticValue function
QT_WARNING_POP Kind kind
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)
void ** returnAndArgValues() const
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)
const QMetaType * returnAndArgTypes() const
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