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 
43 namespace JSC
44 {
45     ASSERT_CLASS_FITS_IN_CELL(QT_PREPEND_NAMESPACE(QScriptStaticScopeObject));
46 }
47 
48 QT_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 
66 const JSC::ClassInfo QScriptStaticScopeObject::info = { "QScriptStaticScopeObject", 0, 0, 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 */
QScriptStaticScopeObject(WTF::NonNullPassRefPtr<JSC::Structure> structure,int propertyCount,const PropertyInfo * props)73 QScriptStaticScopeObject::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(prop.identifier.ustring().rep(), 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 */
QScriptStaticScopeObject(WTF::NonNullPassRefPtr<JSC::Structure> structure)99 QScriptStaticScopeObject::QScriptStaticScopeObject(WTF::NonNullPassRefPtr<JSC::Structure> structure)
100     : JSC::JSVariableObject(structure, new Data(/*canGrow=*/true))
101 {
102 }
103 
~QScriptStaticScopeObject()104 QScriptStaticScopeObject::~QScriptStaticScopeObject()
105 {
106     delete d_ptr();
107 }
108 
getOwnPropertySlot(JSC::ExecState *,const JSC::Identifier & propertyName,JSC::PropertySlot & slot)109 bool QScriptStaticScopeObject::getOwnPropertySlot(JSC::ExecState*, const JSC::Identifier& propertyName, JSC::PropertySlot& slot)
110 {
111     return symbolTableGet(propertyName, slot);
112 }
113 
getOwnPropertyDescriptor(JSC::ExecState *,const JSC::Identifier & propertyName,JSC::PropertyDescriptor & descriptor)114 bool QScriptStaticScopeObject::getOwnPropertyDescriptor(JSC::ExecState*, const JSC::Identifier& propertyName, JSC::PropertyDescriptor& descriptor)
115 {
116     return symbolTableGet(propertyName, descriptor);
117 }
118 
putWithAttributes(JSC::ExecState * exec,const JSC::Identifier & propertyName,JSC::JSValue value,unsigned attributes)119 void 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 
put(JSC::ExecState * exec,const JSC::Identifier & propertyName,JSC::JSValue value,JSC::PutPropertySlot &)127 void 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 
deleteProperty(JSC::ExecState *,const JSC::Identifier &)135 bool QScriptStaticScopeObject::deleteProperty(JSC::ExecState*, const JSC::Identifier&)
136 {
137     return false;
138 }
139 
markChildren(JSC::MarkStack & markStack)140 void QScriptStaticScopeObject::markChildren(JSC::MarkStack& markStack)
141 {
142     JSC::Register* registerArray = d_ptr()->registerArray.get();
143     if (!registerArray)
144         return;
145     markStack.appendValues(reinterpret_cast<JSC::JSValue*>(registerArray), d_ptr()->registerArraySize);
146 }
147 
addSymbolTableProperty(const JSC::Identifier & name,JSC::JSValue value,unsigned attributes)148 void 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(name.ustring().rep(), 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 */
growRegisterArray(int count)161 int 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(registerArray + count, d_ptr()->registerArray.get(), oldSize * sizeof(JSC::Register));
168     setRegisters(registerArray + newSize, registerArray);
169     d_ptr()->registerArraySize = newSize;
170     return -oldSize - 1;
171 }
172 
173 QT_END_NAMESPACE
174