1 | // Copyright (C) 2016 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 QMLJS_ENVIRONMENT_H |
4 | #define QMLJS_ENVIRONMENT_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 "qv4global_p.h" |
18 | #include "qv4managed_p.h" |
19 | |
20 | QT_BEGIN_NAMESPACE |
21 | |
22 | namespace QV4 { |
23 | |
24 | |
25 | namespace Heap { |
26 | |
27 | #define ExecutionContextMembers(class, Member) \ |
28 | Member(class, Pointer, ExecutionContext *, outer) \ |
29 | Member(class, Pointer, Object *, activation) |
30 | |
31 | DECLARE_HEAP_OBJECT(ExecutionContext, Base) { |
32 | DECLARE_MARKOBJECTS(ExecutionContext) |
33 | |
34 | enum ContextType { |
35 | Type_GlobalContext = 0x1, |
36 | Type_WithContext = 0x2, |
37 | Type_QmlContext = 0x3, |
38 | Type_BlockContext = 0x4, |
39 | Type_CallContext = 0x5 |
40 | }; |
41 | |
42 | void init(ContextType t) |
43 | { |
44 | Base::init(); |
45 | |
46 | type = t; |
47 | } |
48 | |
49 | const VTable *vtable() const { |
50 | return internalClass->vtable; |
51 | } |
52 | |
53 | quint32 type : 8; |
54 | quint32 nArgs : 24; |
55 | #if QT_POINTER_SIZE == 8 |
56 | quint8 padding_[4]; |
57 | #endif |
58 | }; |
59 | Q_STATIC_ASSERT(std::is_trivial_v<ExecutionContext>); |
60 | Q_STATIC_ASSERT(sizeof(ExecutionContext) == sizeof(Base) + sizeof(ExecutionContextData) + QT_POINTER_SIZE); |
61 | |
62 | Q_STATIC_ASSERT(std::is_standard_layout<ExecutionContextData>::value); |
63 | Q_STATIC_ASSERT(offsetof(ExecutionContextData, outer) == 0); |
64 | Q_STATIC_ASSERT(offsetof(ExecutionContextData, activation) == offsetof(ExecutionContextData, outer) + QT_POINTER_SIZE); |
65 | |
66 | #define CallContextMembers(class, Member) \ |
67 | Member(class, Pointer, FunctionObject *, function) \ |
68 | Member(class, ValueArray, ValueArray, locals) |
69 | |
70 | DECLARE_HEAP_OBJECT(CallContext, ExecutionContext) { |
71 | DECLARE_MARKOBJECTS(CallContext) |
72 | |
73 | void init() |
74 | { |
75 | ExecutionContext::init(t: Type_CallContext); |
76 | } |
77 | |
78 | int argc() const { |
79 | return static_cast<int>(nArgs); |
80 | } |
81 | const Value *args() const { |
82 | return locals.data() + locals.size; |
83 | } |
84 | void setArg(uint index, Value v); |
85 | |
86 | template <typename BlockOrFunction> |
87 | void setupLocalTemporalDeadZone(BlockOrFunction *bof) { |
88 | for (uint i = bof->nLocals - bof->sizeOfLocalTemporalDeadZone; i < bof->nLocals; ++i) |
89 | locals.values[i] = Value::emptyValue(); |
90 | } |
91 | }; |
92 | Q_STATIC_ASSERT(std::is_trivial_v<CallContext>); |
93 | Q_STATIC_ASSERT(std::is_standard_layout<CallContextData>::value); |
94 | Q_STATIC_ASSERT(offsetof(CallContextData, function) == 0); |
95 | //### The following size check fails on Win8. With the ValueArray at the end of the |
96 | // CallContextMembers, it doesn't look very useful. |
97 | //#if defined(Q_PROCESSOR_ARM_32) && !defined(Q_OS_IOS) |
98 | //Q_STATIC_ASSERT(sizeof(CallContext) == sizeof(ExecutionContext) + sizeof(CallContextData) + QT_POINTER_SIZE); |
99 | //#else |
100 | //Q_STATIC_ASSERT(sizeof(CallContext) == sizeof(ExecutionContext) + sizeof(CallContextData)); |
101 | //#endif |
102 | |
103 | |
104 | } |
105 | |
106 | struct Q_QML_EXPORT ExecutionContext : public Managed |
107 | { |
108 | enum { |
109 | IsExecutionContext = true |
110 | }; |
111 | |
112 | V4_MANAGED(ExecutionContext, Managed) |
113 | Q_MANAGED_TYPE(ExecutionContext) |
114 | V4_INTERNALCLASS(ExecutionContext) |
115 | |
116 | static Heap::CallContext *newBlockContext(QV4::CppStackFrame *frame, int blockIndex); |
117 | static Heap::CallContext *cloneBlockContext(ExecutionEngine *engine, |
118 | Heap::CallContext *callContext); |
119 | static Heap::CallContext *newCallContext(JSTypesStackFrame *frame); |
120 | Heap::ExecutionContext *newWithContext(Heap::Object *with) const; |
121 | static Heap::ExecutionContext *newCatchContext(CppStackFrame *frame, int blockIndex, Heap::String *exceptionVarName); |
122 | |
123 | void createMutableBinding(String *name, bool deletable); |
124 | |
125 | enum Error { |
126 | NoError, |
127 | TypeError, |
128 | RangeError |
129 | }; |
130 | |
131 | Error setProperty(String *name, const Value &value); |
132 | |
133 | ReturnedValue getProperty(String *name); |
134 | ReturnedValue getPropertyAndBase(String *name, Value *base); |
135 | bool deleteProperty(String *name); |
136 | |
137 | inline CallContext *asCallContext(); |
138 | inline const CallContext *asCallContext() const; |
139 | |
140 | protected: |
141 | // vtable method required for compilation |
142 | static bool virtualDeleteProperty(Managed *, PropertyKey) { |
143 | Q_UNREACHABLE(); |
144 | } |
145 | }; |
146 | |
147 | struct Q_QML_EXPORT CallContext : public ExecutionContext |
148 | { |
149 | V4_MANAGED(CallContext, ExecutionContext) |
150 | V4_INTERNALCLASS(CallContext) |
151 | |
152 | int argc() const { |
153 | return d()->argc(); |
154 | } |
155 | const Value *args() const { |
156 | return d()->args(); |
157 | } |
158 | }; |
159 | |
160 | inline CallContext *ExecutionContext::asCallContext() |
161 | { |
162 | return d()->type == Heap::ExecutionContext::Type_CallContext ? static_cast<CallContext *>(this) : nullptr; |
163 | } |
164 | |
165 | inline const CallContext *ExecutionContext::asCallContext() const |
166 | { |
167 | return d()->type == Heap::ExecutionContext::Type_CallContext ? static_cast<const CallContext *>(this) : nullptr; |
168 | } |
169 | |
170 | } // namespace QV4 |
171 | |
172 | QT_END_NAMESPACE |
173 | |
174 | #endif |
175 | |