1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 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 QV4PROPERTYDESCRIPTOR_H
40 #define QV4PROPERTYDESCRIPTOR_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 "qv4global_p.h"
54 #include "qv4value_p.h"
55 
56 QT_BEGIN_NAMESPACE
57 
58 namespace QV4 {
59 
60 struct FunctionObject;
61 
62 struct Property {
63     Value value;
64     Value set;
65 
66     // Section 8.10
fullyPopulatedProperty67     inline void fullyPopulated(PropertyAttributes *attrs) {
68         if (!attrs->hasType()) {
69             value = Value::undefinedValue();
70         }
71         if (attrs->type() == PropertyAttributes::Accessor) {
72             attrs->clearWritable();
73             if (value.isEmpty())
74                 value = Value::undefinedValue();
75             if (set.isEmpty())
76                 set = Value::undefinedValue();
77         }
78         attrs->resolve();
79     }
80 
81     // ES8: 6.2.5.6
completedProperty82     void completed(PropertyAttributes *attrs) {
83         if (value.isEmpty())
84             value = Encode::undefined();
85         if (attrs->isGeneric() || attrs->isData()) {
86             attrs->setType(PropertyAttributes::Data);
87             if (!attrs->hasWritable())
88                 attrs->setWritable(false);
89         } else {
90             if (set.isEmpty())
91                 set = Encode::undefined();
92         }
93         if (!attrs->hasEnumerable())
94             attrs->setEnumerable(false);
95         if (!attrs->hasConfigurable())
96             attrs->setConfigurable(false);
97     }
98 
99     inline bool isSubset(const PropertyAttributes &attrs, const Property *other, PropertyAttributes otherAttrs) const;
100     inline void merge(PropertyAttributes &attrs, const Property *other, PropertyAttributes otherAttrs);
101 
getterProperty102     inline Heap::FunctionObject *getter() const { return reinterpret_cast<Heap::FunctionObject *>(value.heapObject()); }
setterProperty103     inline Heap::FunctionObject *setter() const { return reinterpret_cast<Heap::FunctionObject *>(set.heapObject()); }
setGetterProperty104     inline void setGetter(FunctionObject *g) { value = reinterpret_cast<Managed *>(g); }
setSetterProperty105     inline void setSetter(FunctionObject *s) { set = (s ? reinterpret_cast<Managed *>(s) : nullptr); }
106 
copyProperty107     void copy(const Property *other, PropertyAttributes attrs) {
108         value = other->value;
109         if (attrs.isAccessor())
110             set = other->set;
111     }
112 
113     // ES8, section 9.1.6.2/9,.1.6.3
isCompatibleProperty114     bool isCompatible(PropertyAttributes &attrs, const Property *other, PropertyAttributes otherAttrs) const {
115         if (otherAttrs.isEmpty())
116             return true;
117         if (!attrs.isConfigurable()) {
118             if (otherAttrs.hasConfigurable() && otherAttrs.isConfigurable())
119                 return false;
120             if (otherAttrs.hasEnumerable() && otherAttrs.isEnumerable() != attrs.isEnumerable())
121                 return false;
122         }
123         if (otherAttrs.isGeneric())
124             return true;
125         if (attrs.isData() != otherAttrs.isData()) {
126             if (!attrs.isConfigurable())
127                 return false;
128         } else if (attrs.isData() && otherAttrs.isData()) {
129             if (!attrs.isConfigurable() && !attrs.isWritable()) {
130                 if (otherAttrs.hasWritable() && otherAttrs.isWritable())
131                     return false;
132                 if (!other->value.isEmpty() && !value.sameValue(other->value))
133                     return false;
134             }
135         } else if (attrs.isAccessor() && otherAttrs.isAccessor()) {
136             if (!attrs.isConfigurable()) {
137                 if (!other->value.isEmpty() && !value.sameValue(other->value))
138                     return false;
139                 if (!other->set.isEmpty() && !set.sameValue(other->set))
140                     return false;
141             }
142         }
143         return true;
144     }
145 
146 
PropertyProperty147     explicit Property()  { value = Encode::undefined(); set = Value::fromHeapObject(nullptr); }
PropertyProperty148     Property(Heap::FunctionObject *getter, Heap::FunctionObject *setter) {
149         value.setM(reinterpret_cast<Heap::Base *>(getter));
150         set.setM(reinterpret_cast<Heap::Base *>(setter));
151     }
152 private:
153     Q_DISABLE_COPY(Property)
154 };
155 
isSubset(const PropertyAttributes & attrs,const Property * other,PropertyAttributes otherAttrs)156 inline bool Property::isSubset(const PropertyAttributes &attrs, const Property *other, PropertyAttributes otherAttrs) const
157 {
158     if (attrs.type() != PropertyAttributes::Generic && attrs.type() != otherAttrs.type())
159         return false;
160     if (attrs.hasEnumerable() && attrs.isEnumerable() != otherAttrs.isEnumerable())
161         return false;
162     if (attrs.hasConfigurable() && attrs.isConfigurable() != otherAttrs.isConfigurable())
163         return false;
164     if (attrs.hasWritable() && attrs.isWritable() != otherAttrs.isWritable())
165         return false;
166     if (attrs.type() == PropertyAttributes::Data && !value.sameValue(other->value))
167         return false;
168     if (attrs.type() == PropertyAttributes::Accessor) {
169         if (value.heapObject() != other->value.heapObject())
170             return false;
171         if (set.heapObject() != other->set.heapObject())
172             return false;
173     }
174     return true;
175 }
176 
merge(PropertyAttributes & attrs,const Property * other,PropertyAttributes otherAttrs)177 inline void Property::merge(PropertyAttributes &attrs, const Property *other, PropertyAttributes otherAttrs)
178 {
179     if (otherAttrs.hasEnumerable())
180         attrs.setEnumerable(otherAttrs.isEnumerable());
181     if (otherAttrs.hasConfigurable())
182         attrs.setConfigurable(otherAttrs.isConfigurable());
183     if (otherAttrs.hasWritable())
184         attrs.setWritable(otherAttrs.isWritable());
185     if (otherAttrs.type() == PropertyAttributes::Accessor) {
186         attrs.setType(PropertyAttributes::Accessor);
187         if (!other->value.isEmpty())
188             value = other->value;
189         if (!other->set.isEmpty())
190             set = other->set;
191     } else if (otherAttrs.type() == PropertyAttributes::Data){
192         attrs.setType(PropertyAttributes::Data);
193         value = other->value;
194     }
195 }
196 
197 struct PropertyIndex {
198     Heap::Base *base;
199     Value *slot;
200 
setPropertyIndex201     void set(EngineBase *e, Value newVal) {
202         WriteBarrier::write(e, base, slot->data_ptr(), newVal.asReturnedValue());
203     }
204     const Value *operator->() const { return slot; }
205     const Value &operator*() const { return *slot; }
isNullPropertyIndex206     bool isNull() const { return !slot; }
207 };
208 
209 
210 }
211 
212 Q_DECLARE_TYPEINFO(QV4::Property, Q_MOVABLE_TYPE);
213 
214 QT_END_NAMESPACE
215 
216 #endif
217