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

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

[ES5] Implement getOwnPropertyDescriptor
https://bugs.webkit.org/show_bug.cgi?id=28724

Reviewed by Gavin Barraclough.

JavaScriptCore:
Implement the core runtime support for getOwnPropertyDescriptor.
This adds a virtual getOwnPropertyDescriptor method to every class
that implements getOwnPropertySlot that shadows the behaviour of
getOwnPropertySlot. The alternative would be to make getOwnPropertySlot
(or PropertySlots in general) provide property attribute information,
but quick testing showed this to be a regression.

WebCore:
Implement the WebCore side of getOwnPropertyDescriptor. This
requires a custom implementation of getOwnPropertyDescriptor
for every class with a custom implementation of getOwnPropertySlot.

The bindings generator has been updated to generate appropriate
versions of getOwnPropertyDescriptor for the general case where
a custom getOwnPropertyDescriptor is not needed. ES5 is vague
about how getOwnPropertyDescriptor should work in the context of
"host" functions with polymorphic GetOwnProperty, so it seems
okay that occasionally we "guess" what attributes -- eg. determining
whether a property is writable.

Test: fast/js/getOwnPropertyDescriptor.html

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