1 /*
2  * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
3  *           (C) 2008 Maksim Orlovich <maksim@kde.org>
4  *
5  *  This library is free software; you can redistribute it and/or
6  *  modify it under the terms of the GNU Library General Public
7  *  License as published by the Free Software Foundation; either
8  *  version 2 of the License, or (at your option) any later version.
9  *
10  *  This library is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  *  Library General Public License for more details.
14  *
15  *  You should have received a copy of the GNU Library General Public License
16  *  along with this library; see the file COPYING.LIB.  If not, write to
17  *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18  *  Boston, MA 02110-1301, USA.
19  *
20  * Portions of this code that are (C) 2007, 2008 Apple Inc. were
21  * originally distributed under the following terms
22  *
23  *  Redistribution and use in source and binary forms, with or without
24  *  modification, are permitted provided that the following conditions
25  *   are met:
26  *
27  *   1.  Redistributions of source code must retain the above copyright
28  *       notice, this list of conditions and the following disclaimer.
29  *   2.  Redistributions in binary form must reproduce the above copyright
30  *       notice, this list of conditions and the following disclaimer in the
31  *       documentation and/or other materials provided with the distribution.
32  *   3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
33  *       its contributors may be used to endorse or promote products derived
34  *       from this software without specific prior written permission.
35  *
36  *   THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
37  *   EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
38  *   WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
39  *   DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
40  *   DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
41  *   (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
42  *   LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
43  *   ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
44  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
45  *   THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
46  */
47 
48 #ifndef JSVariableObject_h
49 #define JSVariableObject_h
50 
51 #include "LocalStorage.h"
52 #include "SymbolTable.h"
53 #include "object.h"
54 
55 #include <wtf/Vector.h>
56 
57 namespace KJS
58 {
59 class Interpreter;
60 
61 class JSVariableObject : public JSObject
62 {
63 public:
64     using KJS::JSObject::deleteProperty;
65     bool deleteProperty(ExecState *, const Identifier &) override;
66 
67     void getOwnPropertyNames(ExecState *, PropertyNameArray &, PropertyMap::PropertyMode mode) override;
68 
69     void mark() override;
70 
71     enum {
72         LengthSlot,
73         TearOffNeeded, // Set when a tearoff is requested;
74         // the actual tearoff will only happen once the function
75         // stops running, though
76         ScopeLink,
77         NumVarObjectSlots = 3
78     };
79 
lengthSlot()80     int32_t &lengthSlot()
81     {
82         return localStorage[LengthSlot].val.int32Val;
83     }
lengthSlot()84     const int32_t &lengthSlot() const
85     {
86         return localStorage[LengthSlot].val.int32Val;
87     }
88 
tearOffNeededSlot()89     bool &tearOffNeededSlot()
90     {
91         return localStorage[TearOffNeeded].val.boolVal;
92     }
93 
scopeLink()94     ScopeChainLink &scopeLink()
95     {
96         return localStorage[ScopeLink].val.scopeVal;
97     }
98 protected:
JSVariableObject()99     JSVariableObject(): localStorage(nullptr), symbolTable(nullptr) { }
100     ~JSVariableObject() override;
101 
102     bool symbolTableGet(const Identifier &, PropertySlot &);
103     bool symbolTablePut(const Identifier &, JSValue *, bool checkReadOnly);
104 
105 public:
106     LocalStorageEntry *localStorage; // Storage for variables in the symbol table.
107     SymbolTable       *symbolTable; // Maps name -> index in localStorage.
108 };
109 
symbolTableGet(const Identifier & propertyName,PropertySlot & slot)110 inline bool JSVariableObject::symbolTableGet(const Identifier &propertyName, PropertySlot &slot)
111 {
112     size_t index = symbolTable->get(propertyName.ustring().rep());
113     if (index != missingSymbolMarker()) {
114         slot.setValueSlot(this, &localStorage[index].val.valueVal);
115         return true;
116     }
117     return false;
118 }
119 
symbolTablePut(const Identifier & propertyName,JSValue * value,bool checkReadOnly)120 inline bool JSVariableObject::symbolTablePut(const Identifier &propertyName, JSValue *value, bool checkReadOnly)
121 {
122     size_t index = symbolTable->get(propertyName.ustring().rep());
123     if (index == missingSymbolMarker()) {
124         return false;
125     }
126     LocalStorageEntry &entry = localStorage[index];
127     if (checkReadOnly && (entry.attributes & ReadOnly)) {
128         return true;
129     }
130     entry.val.valueVal = value;
131     return true;
132 }
133 
~JSVariableObject()134 inline JSVariableObject::~JSVariableObject()
135 {
136     if (localStorage) {
137         scopeLink().deref();
138         if (tearOffNeededSlot()) {
139             delete[] localStorage;
140         }
141     }
142 }
143 
object()144 inline JSObject *ScopeChainLink::object() const
145 {
146     if (isToScopeChainNode()) {
147         return asScopeChainNode()->object;
148     } else {
149         return asVariableObject();
150     }
151 }
152 
next()153 inline ScopeChainLink ScopeChainLink::next() const
154 {
155     if (isToScopeChainNode()) {
156         return asScopeChainNode()->next;
157     } else {
158         return asVariableObject()->scopeLink();
159     }
160 }
161 
mark()162 inline void ScopeChain::mark()
163 {
164     for (ScopeChainLink n = m_top; n.ptr; n = n.next()) {
165         JSObject *o = n.object();
166         if (!o->marked()) {
167             o->mark();
168         }
169     }
170 }
171 
pushVariableObject(JSVariableObject * act)172 inline void ScopeChain::pushVariableObject(JSVariableObject *act)
173 {
174     // note: this assumes the new variable object is not in any
175     // scope chain in the moment.
176 
177     // Set the item's next pointer to the current top.
178     // there is no refcount ops since it's transferring a reference
179     act->scopeLink() = m_top;
180 
181     // new top!
182     m_top.set(act);
183 }
184 
185 class KJS_EXPORT JSGlobalObject :  public JSObject // ### TODO: should inherit off JSVariableObject
186 {
187 public:
JSGlobalObject()188     JSGlobalObject(): m_interpreter(nullptr) {}
JSGlobalObject(JSValue * proto)189     JSGlobalObject(JSValue *proto): JSObject(proto), m_interpreter(nullptr) {}
isGlobalObject()190     bool isGlobalObject() const override
191     {
192         return true;
193     }
194 
setInterpreter(Interpreter * intp)195     void setInterpreter(Interpreter *intp)
196     {
197         m_interpreter = intp;
198     }
interpreter()199     Interpreter *interpreter() const
200     {
201         return m_interpreter;
202     }
203 private:
204     Interpreter *m_interpreter;
205 };
206 } // namespace KJS
207 
208 #endif // JSVariableObject_h
209