source: webkit/trunk/JavaScriptCore/runtime/JSGlobalObject.h@ 41685

Last change on this file since 41685 was 41232, checked in by [email protected], 16 years ago

JavaScriptCore:

2009-02-25 Geoffrey Garen <[email protected]>

Reviewed by Maciej Stachowiak.


Fixed <rdar://problem/6611174> REGRESSION (r36701): Unable to select
messages on hotmail (24052)


The bug was that for-in enumeration used a cached prototype chain without
validating that it was up-to-date.


This led me to refactor prototype chain caching so it was easier to work
with and harder to get wrong.


After a bit of inlining, this patch is performance-neutral on SunSpider
and the v8 benchmarks.

  • interpreter/Interpreter.cpp: (JSC::Interpreter::tryCachePutByID): (JSC::Interpreter::tryCacheGetByID):
  • jit/JITStubs.cpp: (JSC::JITStubs::tryCachePutByID): (JSC::JITStubs::tryCacheGetByID): (JSC::JITStubs::cti_op_get_by_id_proto_list): Use the new refactored goodness. See lines beginning with "-" and smile.
  • runtime/JSGlobalObject.h: (JSC::Structure::prototypeForLookup): A shout out to const.
  • runtime/JSPropertyNameIterator.h: (JSC::JSPropertyNameIterator::next): We can use a pointer comparison to see if our cached structure chain is equal to the object's structure chain, since in the case of a cache hit, we share references to the same structure chain.
  • runtime/Operations.h: (JSC::countPrototypeChainEntriesAndCheckForProxies): Use the new refactored goodness.
  • runtime/PropertyNameArray.h: (JSC::PropertyNameArray::PropertyNameArray): (JSC::PropertyNameArray::setShouldCache): (JSC::PropertyNameArray::shouldCache): Renamed "cacheable" to "shouldCache" to communicate that the client is specifying a recommendation, not a capability.


  • runtime/Structure.cpp: (JSC::Structure::Structure): No need to initialize a RefPtr. (JSC::Structure::getEnumerablePropertyNames): Moved some code into helper functions.

(JSC::Structure::prototypeChain): New centralized accessor for a prototype
chain. Revalidates on every access, since the objects in the prototype
chain may have mutated.

(JSC::Structure::isValid): Helper function for revalidating a cached
prototype chain.

(JSC::Structure::getEnumerableNamesFromPropertyTable):
(JSC::Structure::getEnumerableNamesFromClassInfoTable): Factored out of
getEnumerablePropertyNames.

  • runtime/Structure.h:
  • runtime/StructureChain.cpp: (JSC::StructureChain::StructureChain):
  • runtime/StructureChain.h: (JSC::StructureChain::create): No need for structureChainsAreEqual, since we use pointer equality now. Refactored StructureChain to make a little more sense and eliminate special cases for null prototypes.

LayoutTests:

2009-02-24 Geoffrey Garen <[email protected]>

Reviewed by Maciej Stachowiak.


Added a test for <rdar://problem/6611174> REGRESSION (r36701): Unable to
select messages on hotmail (24052)

  • fast/js/for-in-cached-expected.txt: Added.
  • fast/js/for-in-cached.html: Added.
  • fast/js/resources/for-in-cached.js: Added. (forIn):
  • Property svn:eol-style set to native
File size: 15.8 KB
Line 
1/*
2 * Copyright (C) 2007 Eric Seidel <[email protected]>
3 * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
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 */
21
22#ifndef JSGlobalObject_h
23#define JSGlobalObject_h
24
25#include "JSGlobalData.h"
26#include "JSVariableObject.h"
27#include "NumberPrototype.h"
28#include "StringPrototype.h"
29#include <wtf/HashSet.h>
30#include <wtf/OwnPtr.h>
31
32namespace JSC {
33
34 class ArrayPrototype;
35 class BooleanPrototype;
36 class DatePrototype;
37 class Debugger;
38 class ErrorConstructor;
39 class FunctionPrototype;
40 class GlobalEvalFunction;
41 class NativeErrorConstructor;
42 class ProgramCodeBlock;
43 class RegExpConstructor;
44 class RegExpPrototype;
45 class RegisterFile;
46
47 struct ActivationStackNode;
48 struct HashTable;
49
50 typedef Vector<ExecState*, 16> ExecStateStack;
51
52 class JSGlobalObject : public JSVariableObject {
53 protected:
54 using JSVariableObject::JSVariableObjectData;
55
56 struct JSGlobalObjectData : public JSVariableObjectData {
57 JSGlobalObjectData()
58 : JSVariableObjectData(&symbolTable, 0)
59 , registerArraySize(0)
60 , globalScopeChain(NoScopeChain())
61 , regExpConstructor(0)
62 , errorConstructor(0)
63 , evalErrorConstructor(0)
64 , rangeErrorConstructor(0)
65 , referenceErrorConstructor(0)
66 , syntaxErrorConstructor(0)
67 , typeErrorConstructor(0)
68 , URIErrorConstructor(0)
69 , evalFunction(0)
70 , objectPrototype(0)
71 , functionPrototype(0)
72 , arrayPrototype(0)
73 , booleanPrototype(0)
74 , stringPrototype(0)
75 , numberPrototype(0)
76 , datePrototype(0)
77 , regExpPrototype(0)
78 {
79 }
80
81 virtual ~JSGlobalObjectData()
82 {
83 }
84
85 size_t registerArraySize;
86
87 JSGlobalObject* next;
88 JSGlobalObject* prev;
89
90 Debugger* debugger;
91
92 ScopeChain globalScopeChain;
93 Register globalCallFrame[RegisterFile::CallFrameHeaderSize];
94
95 int recursion;
96
97 RegExpConstructor* regExpConstructor;
98 ErrorConstructor* errorConstructor;
99 NativeErrorConstructor* evalErrorConstructor;
100 NativeErrorConstructor* rangeErrorConstructor;
101 NativeErrorConstructor* referenceErrorConstructor;
102 NativeErrorConstructor* syntaxErrorConstructor;
103 NativeErrorConstructor* typeErrorConstructor;
104 NativeErrorConstructor* URIErrorConstructor;
105
106 GlobalEvalFunction* evalFunction;
107
108 ObjectPrototype* objectPrototype;
109 FunctionPrototype* functionPrototype;
110 ArrayPrototype* arrayPrototype;
111 BooleanPrototype* booleanPrototype;
112 StringPrototype* stringPrototype;
113 NumberPrototype* numberPrototype;
114 DatePrototype* datePrototype;
115 RegExpPrototype* regExpPrototype;
116
117 RefPtr<Structure> argumentsStructure;
118 RefPtr<Structure> arrayStructure;
119 RefPtr<Structure> booleanObjectStructure;
120 RefPtr<Structure> callbackConstructorStructure;
121 RefPtr<Structure> callbackFunctionStructure;
122 RefPtr<Structure> callbackObjectStructure;
123 RefPtr<Structure> dateStructure;
124 RefPtr<Structure> emptyObjectStructure;
125 RefPtr<Structure> errorStructure;
126 RefPtr<Structure> functionStructure;
127 RefPtr<Structure> numberObjectStructure;
128 RefPtr<Structure> prototypeFunctionStructure;
129 RefPtr<Structure> regExpMatchesArrayStructure;
130 RefPtr<Structure> regExpStructure;
131 RefPtr<Structure> stringObjectStructure;
132
133 SymbolTable symbolTable;
134 unsigned profileGroup;
135
136 RefPtr<JSGlobalData> globalData;
137
138 HashSet<ProgramCodeBlock*> codeBlocks;
139 };
140
141 public:
142 void* operator new(size_t, JSGlobalData*);
143
144 explicit JSGlobalObject()
145 : JSVariableObject(JSGlobalObject::createStructure(jsNull()), new JSGlobalObjectData)
146 {
147 init(this);
148 }
149
150 protected:
151 JSGlobalObject(PassRefPtr<Structure> structure, JSGlobalObjectData* data, JSObject* thisValue)
152 : JSVariableObject(structure, data)
153 {
154 init(thisValue);
155 }
156
157 public:
158 virtual ~JSGlobalObject();
159
160 virtual void mark();
161
162 virtual bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&);
163 virtual bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&, bool& slotIsWriteable);
164 virtual void put(ExecState*, const Identifier&, JSValuePtr, PutPropertySlot&);
165 virtual void putWithAttributes(ExecState*, const Identifier& propertyName, JSValuePtr value, unsigned attributes);
166
167 virtual void defineGetter(ExecState*, const Identifier& propertyName, JSObject* getterFunc);
168 virtual void defineSetter(ExecState*, const Identifier& propertyName, JSObject* setterFunc);
169
170 // Linked list of all global objects that use the same JSGlobalData.
171 JSGlobalObject*& head() { return d()->globalData->head; }
172 JSGlobalObject* next() { return d()->next; }
173
174 // The following accessors return pristine values, even if a script
175 // replaces the global object's associated property.
176
177 RegExpConstructor* regExpConstructor() const { return d()->regExpConstructor; }
178
179 ErrorConstructor* errorConstructor() const { return d()->errorConstructor; }
180 NativeErrorConstructor* evalErrorConstructor() const { return d()->evalErrorConstructor; }
181 NativeErrorConstructor* rangeErrorConstructor() const { return d()->rangeErrorConstructor; }
182 NativeErrorConstructor* referenceErrorConstructor() const { return d()->referenceErrorConstructor; }
183 NativeErrorConstructor* syntaxErrorConstructor() const { return d()->syntaxErrorConstructor; }
184 NativeErrorConstructor* typeErrorConstructor() const { return d()->typeErrorConstructor; }
185 NativeErrorConstructor* URIErrorConstructor() const { return d()->URIErrorConstructor; }
186
187 GlobalEvalFunction* evalFunction() const { return d()->evalFunction; }
188
189 ObjectPrototype* objectPrototype() const { return d()->objectPrototype; }
190 FunctionPrototype* functionPrototype() const { return d()->functionPrototype; }
191 ArrayPrototype* arrayPrototype() const { return d()->arrayPrototype; }
192 BooleanPrototype* booleanPrototype() const { return d()->booleanPrototype; }
193 StringPrototype* stringPrototype() const { return d()->stringPrototype; }
194 NumberPrototype* numberPrototype() const { return d()->numberPrototype; }
195 DatePrototype* datePrototype() const { return d()->datePrototype; }
196 RegExpPrototype* regExpPrototype() const { return d()->regExpPrototype; }
197
198 Structure* argumentsStructure() const { return d()->argumentsStructure.get(); }
199 Structure* arrayStructure() const { return d()->arrayStructure.get(); }
200 Structure* booleanObjectStructure() const { return d()->booleanObjectStructure.get(); }
201 Structure* callbackConstructorStructure() const { return d()->callbackConstructorStructure.get(); }
202 Structure* callbackFunctionStructure() const { return d()->callbackFunctionStructure.get(); }
203 Structure* callbackObjectStructure() const { return d()->callbackObjectStructure.get(); }
204 Structure* dateStructure() const { return d()->dateStructure.get(); }
205 Structure* emptyObjectStructure() const { return d()->emptyObjectStructure.get(); }
206 Structure* errorStructure() const { return d()->errorStructure.get(); }
207 Structure* functionStructure() const { return d()->functionStructure.get(); }
208 Structure* numberObjectStructure() const { return d()->numberObjectStructure.get(); }
209 Structure* prototypeFunctionStructure() const { return d()->prototypeFunctionStructure.get(); }
210 Structure* regExpMatchesArrayStructure() const { return d()->regExpMatchesArrayStructure.get(); }
211 Structure* regExpStructure() const { return d()->regExpStructure.get(); }
212 Structure* stringObjectStructure() const { return d()->stringObjectStructure.get(); }
213
214 void setProfileGroup(unsigned value) { d()->profileGroup = value; }
215 unsigned profileGroup() const { return d()->profileGroup; }
216
217 Debugger* debugger() const { return d()->debugger; }
218 void setDebugger(Debugger* debugger) { d()->debugger = debugger; }
219
220 virtual bool supportsProfiling() const { return false; }
221
222 int recursion() { return d()->recursion; }
223 void incRecursion() { ++d()->recursion; }
224 void decRecursion() { --d()->recursion; }
225
226 ScopeChain& globalScopeChain() { return d()->globalScopeChain; }
227
228 virtual bool isGlobalObject() const { return true; }
229
230 virtual ExecState* globalExec();
231
232 virtual bool shouldInterruptScript() const { return true; }
233
234 virtual bool allowsAccessFrom(const JSGlobalObject*) const { return true; }
235
236 virtual bool isDynamicScope() const;
237
238 HashSet<ProgramCodeBlock*>& codeBlocks() { return d()->codeBlocks; }
239
240 void copyGlobalsFrom(RegisterFile&);
241 void copyGlobalsTo(RegisterFile&);
242
243 void resetPrototype(JSValuePtr prototype);
244
245 JSGlobalData* globalData() { return d()->globalData.get(); }
246 JSGlobalObjectData* d() const { return static_cast<JSGlobalObjectData*>(JSVariableObject::d); }
247
248 static PassRefPtr<Structure> createStructure(JSValuePtr prototype)
249 {
250 return Structure::create(prototype, TypeInfo(ObjectType));
251 }
252
253 protected:
254 struct GlobalPropertyInfo {
255 GlobalPropertyInfo(const Identifier& i, JSValuePtr v, unsigned a)
256 : identifier(i)
257 , value(v)
258 , attributes(a)
259 {
260 }
261
262 const Identifier identifier;
263 JSValuePtr value;
264 unsigned attributes;
265 };
266 void addStaticGlobals(GlobalPropertyInfo*, int count);
267
268 private:
269 // FIXME: Fold reset into init.
270 void init(JSObject* thisValue);
271 void reset(JSValuePtr prototype);
272
273 void setRegisters(Register* registers, Register* registerArray, size_t count);
274
275 void* operator new(size_t); // can only be allocated with JSGlobalData
276 };
277
278 JSGlobalObject* asGlobalObject(JSValuePtr);
279
280 inline JSGlobalObject* asGlobalObject(JSValuePtr value)
281 {
282 ASSERT(asObject(value)->isGlobalObject());
283 return static_cast<JSGlobalObject*>(asObject(value));
284 }
285
286 inline void JSGlobalObject::setRegisters(Register* registers, Register* registerArray, size_t count)
287 {
288 JSVariableObject::setRegisters(registers, registerArray);
289 d()->registerArraySize = count;
290 }
291
292 inline void JSGlobalObject::addStaticGlobals(GlobalPropertyInfo* globals, int count)
293 {
294 size_t oldSize = d()->registerArraySize;
295 size_t newSize = oldSize + count;
296 Register* registerArray = new Register[newSize];
297 if (d()->registerArray)
298 memcpy(registerArray + count, d()->registerArray.get(), oldSize * sizeof(Register));
299 setRegisters(registerArray + newSize, registerArray, newSize);
300
301 for (int i = 0, index = -static_cast<int>(oldSize) - 1; i < count; ++i, --index) {
302 GlobalPropertyInfo& global = globals[i];
303 ASSERT(global.attributes & DontDelete);
304 SymbolTableEntry newEntry(index, global.attributes);
305 symbolTable().add(global.identifier.ustring().rep(), newEntry);
306 registerAt(index) = global.value;
307 }
308 }
309
310 inline bool JSGlobalObject::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
311 {
312 if (JSVariableObject::getOwnPropertySlot(exec, propertyName, slot))
313 return true;
314 return symbolTableGet(propertyName, slot);
315 }
316
317 inline bool JSGlobalObject::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot, bool& slotIsWriteable)
318 {
319 if (JSVariableObject::getOwnPropertySlotForWrite(exec, propertyName, slot, slotIsWriteable))
320 return true;
321 return symbolTableGet(propertyName, slot, slotIsWriteable);
322 }
323
324 inline JSGlobalObject* ScopeChainNode::globalObject() const
325 {
326 const ScopeChainNode* n = this;
327 while (n->next)
328 n = n->next;
329 return asGlobalObject(n->object);
330 }
331
332 inline JSValuePtr Structure::prototypeForLookup(ExecState* exec) const
333 {
334 if (typeInfo().type() == ObjectType)
335 return m_prototype;
336
337 if (typeInfo().type() == StringType)
338 return exec->lexicalGlobalObject()->stringPrototype();
339
340 ASSERT(typeInfo().type() == NumberType);
341 return exec->lexicalGlobalObject()->numberPrototype();
342 }
343
344 inline StructureChain* Structure::prototypeChain(ExecState* exec) const
345 {
346 // We cache our prototype chain so our clients can share it.
347 if (!isValid(exec, m_cachedPrototypeChain.get())) {
348 JSValuePtr prototype = prototypeForLookup(exec);
349 m_cachedPrototypeChain = StructureChain::create(prototype.isNull() ? 0 : asObject(prototype)->structure());
350 }
351 return m_cachedPrototypeChain.get();
352 }
353
354 inline bool Structure::isValid(ExecState* exec, StructureChain* cachedPrototypeChain) const
355 {
356 if (!cachedPrototypeChain)
357 return false;
358
359 JSValuePtr prototype = prototypeForLookup(exec);
360 RefPtr<Structure>* cachedStructure = cachedPrototypeChain->head();
361 while(*cachedStructure && !prototype.isNull()) {
362 if (asObject(prototype)->structure() != *cachedStructure)
363 return false;
364 ++cachedStructure;
365 prototype = asObject(prototype)->prototype();
366 }
367 return prototype.isNull() && !*cachedStructure;
368 }
369
370 inline JSGlobalObject* ExecState::dynamicGlobalObject()
371 {
372 if (this == lexicalGlobalObject()->globalExec())
373 return lexicalGlobalObject();
374
375 // For any ExecState that's not a globalExec, the
376 // dynamic global object must be set since code is running
377 ASSERT(globalData().dynamicGlobalObject);
378 return globalData().dynamicGlobalObject;
379 }
380
381 class DynamicGlobalObjectScope : Noncopyable {
382 public:
383 DynamicGlobalObjectScope(CallFrame* callFrame, JSGlobalObject* dynamicGlobalObject)
384 : m_dynamicGlobalObjectSlot(callFrame->globalData().dynamicGlobalObject)
385 , m_savedDynamicGlobalObject(m_dynamicGlobalObjectSlot)
386 {
387 m_dynamicGlobalObjectSlot = dynamicGlobalObject;
388 }
389
390 ~DynamicGlobalObjectScope()
391 {
392 m_dynamicGlobalObjectSlot = m_savedDynamicGlobalObject;
393 }
394
395 private:
396 JSGlobalObject*& m_dynamicGlobalObjectSlot;
397 JSGlobalObject* m_savedDynamicGlobalObject;
398 };
399
400} // namespace JSC
401
402#endif // JSGlobalObject_h
Note: See TracBrowser for help on using the repository browser.