1/****************************************************************************
2**
3** Copyright (C) 2015 The Qt Company Ltd.
4** Contact: http://www.qt.io/licensing/
5**
6** This file is part of the QtScript 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
40#include "config.h"
41#include "qscriptstaticscopeobject_p.h"
42
43namespace JSC
44{
45 ASSERT_CLASS_FITS_IN_CELL(QT_PREPEND_NAMESPACE(QScriptStaticScopeObject));
46}
47
48QT_BEGIN_NAMESPACE
49
50/*!
51 \class QScriptStaticScopeObject
52 \internal
53
54 Represents a static scope object.
55
56 This class allows the VM to determine at JS script compile time whether
57 the object has a given property or not. If the object has the property,
58 a fast, index-based read/write operation will be used. If the object
59 doesn't have the property, the compiler knows it can safely skip this
60 object when dynamically resolving the property. Either way, this can
61 greatly improve performance.
62
63 \sa QScriptContext::pushScope()
64*/
65
66const JSC::ClassInfo QScriptStaticScopeObject::info = { .className: "QScriptStaticScopeObject", .parentClass: 0, .staticPropHashTable: 0, .classPropHashTableGetterFunction: 0 };
67
68/*!
69 Creates a static scope object with a fixed set of undeletable properties.
70
71 It's not possible to add new properties to the object after construction.
72*/
73QScriptStaticScopeObject::QScriptStaticScopeObject(WTF::NonNullPassRefPtr<JSC::Structure> structure,
74 int propertyCount, const PropertyInfo* props)
75 : JSC::JSVariableObject(structure, new Data(/*canGrow=*/false))
76{
77 int index = growRegisterArray(propertyCount);
78 for (int i = 0; i < propertyCount; ++i, --index) {
79 const PropertyInfo& prop = props[i];
80 JSC::SymbolTableEntry entry(index, prop.attributes);
81 symbolTable().add(key: prop.identifier.ustring().rep(), mapped: entry);
82 registerAt(index) = prop.value;
83 }
84}
85
86/*!
87 Creates an empty static scope object.
88
89 Properties can be added to the object after construction, either by
90 calling QScriptValue::setProperty(), or by pushing the object on the
91 scope chain; variable declarations ("var" statements) and function
92 declarations in JavaScript will create properties on the scope object.
93
94 Note that once the scope object has been used in a closure and the
95 resulting function has been compiled, it's no longer safe to add
96 properties to the scope object (because the VM will bypass this
97 object the next time the function is executed).
98*/
99QScriptStaticScopeObject::QScriptStaticScopeObject(WTF::NonNullPassRefPtr<JSC::Structure> structure)
100 : JSC::JSVariableObject(structure, new Data(/*canGrow=*/true))
101{
102}
103
104QScriptStaticScopeObject::~QScriptStaticScopeObject()
105{
106 delete d_ptr();
107}
108
109bool QScriptStaticScopeObject::getOwnPropertySlot(JSC::ExecState*, const JSC::Identifier& propertyName, JSC::PropertySlot& slot)
110{
111 return symbolTableGet(propertyName, slot);
112}
113
114bool QScriptStaticScopeObject::getOwnPropertyDescriptor(JSC::ExecState*, const JSC::Identifier& propertyName, JSC::PropertyDescriptor& descriptor)
115{
116 return symbolTableGet(propertyName, descriptor);
117}
118
119void QScriptStaticScopeObject::putWithAttributes(JSC::ExecState* exec, const JSC::Identifier &propertyName, JSC::JSValue value, unsigned attributes)
120{
121 if (symbolTablePutWithAttributes(propertyName, value, attributes))
122 return;
123 Q_ASSERT(d_ptr()->canGrow);
124 addSymbolTableProperty(propertyName, value, attributes);
125}
126
127void QScriptStaticScopeObject::put(JSC::ExecState* exec, const JSC::Identifier& propertyName, JSC::JSValue value, JSC::PutPropertySlot&)
128{
129 if (symbolTablePut(propertyName, value))
130 return;
131 Q_ASSERT(d_ptr()->canGrow);
132 addSymbolTableProperty(propertyName, value, /*attributes=*/0);
133}
134
135bool QScriptStaticScopeObject::deleteProperty(JSC::ExecState*, const JSC::Identifier&)
136{
137 return false;
138}
139
140void QScriptStaticScopeObject::markChildren(JSC::MarkStack& markStack)
141{
142 JSC::Register* registerArray = d_ptr()->registerArray.get();
143 if (!registerArray)
144 return;
145 markStack.appendValues(values: reinterpret_cast<JSC::JSValue*>(registerArray), count: d_ptr()->registerArraySize);
146}
147
148void QScriptStaticScopeObject::addSymbolTableProperty(const JSC::Identifier& name, JSC::JSValue value, unsigned attributes)
149{
150 int index = growRegisterArray(1);
151 JSC::SymbolTableEntry newEntry(index, attributes | JSC::DontDelete);
152 symbolTable().add(key: name.ustring().rep(), mapped: newEntry);
153 registerAt(index) = value;
154}
155
156/*!
157 Grows the register array by \a count elements, and returns the offset of
158 the newly added elements (note that the register file grows downwards,
159 starting at index -1).
160*/
161int QScriptStaticScopeObject::growRegisterArray(int count)
162{
163 size_t oldSize = d_ptr()->registerArraySize;
164 size_t newSize = oldSize + count;
165 JSC::Register* registerArray = new JSC::Register[newSize];
166 if (d_ptr()->registerArray)
167 memcpy(dest: registerArray + count, src: d_ptr()->registerArray.get(), n: oldSize * sizeof(JSC::Register));
168 setRegisters(registers: registerArray + newSize, registerArray);
169 d_ptr()->registerArraySize = newSize;
170 return -oldSize - 1;
171}
172
173QT_END_NAMESPACE
174

source code of qtscript/src/script/bridge/qscriptstaticscopeobject.cpp