source: webkit/trunk/JavaScriptCore/API/JSObjectRef.cpp@ 36016

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

JavaScriptCore:

2008-09-01 Geoffrey Garen <[email protected]>

Reviewed by Darin Adler.

First cut at inline caching for access to vanilla JavaScript properties.


SunSpider says 4% faster. Tests heavy on dictionary-like access have
regressed a bit -- we have a lot of room to improve in this area,
but this patch is over-ripe as-is.


JSCells now have a StructureID that uniquely identifies their layout,
and holds their prototype.


JSValue::put takes a PropertySlot& argument, so it can fill in details
about where it put a value, for the sake of caching.

  • VM/CodeGenerator.cpp: (KJS::CodeGenerator::CodeGenerator): Avoid calling removeDirect if we can, since it disables inline caching in the global object. This can probably improve in the future.
  • kjs/JSGlobalObject.cpp: Nixed reset(), since it complicates caching, and wasn't really necessary.
  • kjs/JSObject.cpp: Tweaked getter / setter behavior not to rely on the IsGetterSetter flag, since the flag was buggy. This is necessary in order to avoid accidentally accessing a getter / setter as a normal property.


Also changed getter / setter creation to honor ReadOnly, matching Mozilla.


  • kjs/PropertyMap.cpp: Nixed clear(), since it complicates caching and isn't necessary.
  • kjs/Shell.cpp: Moved SamplingTool dumping outside the loop. This allows you to aggregate sampling of multiple files (or the same file repeatedly), which helped me track down regressions.
  • kjs/ustring.h: Moved IdentifierRepHash here to share it.

WebCore:

2008-09-01 Geoffrey Garen <[email protected]>

Reviewed by Darin Adler.

First cut at inline caching for access to vanilla JavaScript properties.

Updated for JavaScriptCore changes. Mostly mechanical addition of StructureIDs
to WebCore classes, and PutPropertySlot& arguments to put functions.

(WebCore::JSCSSStyleDeclaration::customPut): Be sure to play nice with
inline caching for global properties, so global assignment can be optimized.

  • ForwardingHeaders/kjs/StructureID.h: Added.
  • bindings/js/JSDOMBinding.h: (WebCore::DOMObject::DOMObject):
  • bindings/js/JSDOMWindowBase.cpp: (WebCore::JSDOMWindowBase::put):
  • bindings/js/JSDOMWindowBase.h:
  • bindings/js/JSDOMWindowCustom.h: (WebCore::JSDOMWindow::customPut):
  • bindings/js/JSDOMWindowShell.cpp: (WebCore::JSDOMWindowShell::JSDOMWindowShell): (WebCore::JSDOMWindowShell::put):
  • bindings/js/JSDOMWindowShell.h:
  • bindings/js/JSEventTargetBase.h: (WebCore::JSEventTargetBase::put):
  • bindings/js/JSEventTargetNode.h: (WebCore::JSEventTargetNode::put):
  • bindings/js/JSHTMLAppletElementCustom.cpp: (WebCore::JSHTMLAppletElement::customPut):
  • bindings/js/JSHTMLEmbedElementCustom.cpp: (WebCore::JSHTMLEmbedElement::customPut):
  • bindings/js/JSHTMLInputElementBase.cpp: (WebCore::JSHTMLInputElementBase::put):
  • bindings/js/JSHTMLInputElementBase.h:
  • bindings/js/JSHTMLObjectElementCustom.cpp: (WebCore::JSHTMLObjectElement::customPut):
  • bindings/js/JSHistoryCustom.cpp: (WebCore::JSHistory::customPut):
  • bindings/js/JSInspectedObjectWrapper.cpp: (WebCore::JSInspectedObjectWrapper::wrap): (WebCore::JSInspectedObjectWrapper::JSInspectedObjectWrapper):
  • bindings/js/JSInspectedObjectWrapper.h:
  • bindings/js/JSInspectorCallbackWrapper.cpp: (WebCore::JSInspectorCallbackWrapper::wrap): (WebCore::JSInspectorCallbackWrapper::JSInspectorCallbackWrapper):
  • bindings/js/JSInspectorCallbackWrapper.h:
  • bindings/js/JSLocationCustom.cpp: (WebCore::JSLocation::customPut):
  • bindings/js/JSPluginElementFunctions.cpp: (WebCore::runtimeObjectCustomPut):
  • bindings/js/JSPluginElementFunctions.h:
  • bindings/js/JSQuarantinedObjectWrapper.cpp: (WebCore::JSQuarantinedObjectWrapper::JSQuarantinedObjectWrapper): (WebCore::JSQuarantinedObjectWrapper::put):
  • bindings/js/JSQuarantinedObjectWrapper.h:
  • bindings/js/JSStorageCustom.cpp: (WebCore::JSStorage::customPut):
  • bindings/objc/WebScriptObject.mm: (-[WebScriptObject setValue:forKey:]):
  • bindings/scripts/CodeGeneratorJS.pm:
  • bridge/NP_jsobject.cpp: (_NPN_SetProperty):
  • bridge/jni/jni_jsobject.mm: (JavaJSObject::setMember):
  • bridge/objc/objc_class.mm: (KJS::Bindings::ObjcClass::fallbackObject):
  • bridge/objc/objc_runtime.h:
  • bridge/objc/objc_runtime.mm: (ObjcFallbackObjectImp::ObjcFallbackObjectImp): (ObjcFallbackObjectImp::put):
  • bridge/runtime.cpp: (KJS::Bindings::Instance::createRuntimeObject):
  • bridge/runtime_array.cpp: (RuntimeArray::put):
  • bridge/runtime_array.h:
  • bridge/runtime_object.cpp: (RuntimeObjectImp::RuntimeObjectImp): (RuntimeObjectImp::put):
  • bridge/runtime_object.h:

LayoutTests:

2008-09-01 Geoffrey Garen <[email protected]>

Reviewed by Darin Adler.

First cut at inline caching for access to vanilla JavaScript properties.


Tests for things I broke along the way.


  • fast/dom/getter-on-window-object2-expected.txt:
  • fast/js/pic: Added.
  • fast/js/pic/cached-deleted-properties-expected.txt: Added.
  • fast/js/pic/cached-deleted-properties.html: Added.
  • fast/js/pic/cached-getter-dictionary-and-proto-expected.txt: Added.
  • fast/js/pic/cached-getter-dictionary-and-proto.html: Added.
  • fast/js/pic/cached-getter-setter-expected.txt: Added.
  • fast/js/pic/cached-getter-setter.html: Added.
  • fast/js/pic/cached-prototype-setter-expected.txt: Added.
  • fast/js/pic/cached-prototype-setter.html: Added.
  • fast/js/pic/cached-single-entry-transition-expected.txt: Added.
  • fast/js/pic/cached-single-entry-transition.html: Added.
  • fast/js/pic/get-empty-string-expected.txt: Added.
  • fast/js/pic/get-empty-string.html: Added.
  • fast/js/pic/get-set-proxy-object-expected.txt: Added.
  • fast/js/pic/get-set-proxy-object.html: Added.
  • fast/js/pic/rehash-poisons-structure-expected.txt: Added.
  • fast/js/pic/rehash-poisons-structure.html: Added.
  • Property svn:eol-style set to native
File size: 13.1 KB
Line 
1/*
2 * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27#include "JSObjectRef.h"
28
29#include "APICast.h"
30#include "FunctionConstructor.h"
31#include "JSCallbackConstructor.h"
32#include "JSCallbackFunction.h"
33#include "JSCallbackObject.h"
34#include "JSClassRef.h"
35#include "JSFunction.h"
36#include "JSGlobalObject.h"
37#include "JSObject.h"
38#include "JSRetainPtr.h"
39#include "JSString.h"
40#include "JSValueRef.h"
41#include "ObjectPrototype.h"
42#include "PropertyNameArray.h"
43#include "identifier.h"
44#include <wtf/Platform.h>
45
46using namespace KJS;
47
48JSClassRef JSClassCreate(const JSClassDefinition* definition)
49{
50 RefPtr<OpaqueJSClass> jsClass = (definition->attributes & kJSClassAttributeNoAutomaticPrototype)
51 ? OpaqueJSClass::createNoAutomaticPrototype(definition)
52 : OpaqueJSClass::create(definition);
53
54 return jsClass.release().releaseRef();
55}
56
57JSClassRef JSClassRetain(JSClassRef jsClass)
58{
59 jsClass->ref();
60 return jsClass;
61}
62
63void JSClassRelease(JSClassRef jsClass)
64{
65 jsClass->deref();
66}
67
68JSObjectRef JSObjectMake(JSContextRef ctx, JSClassRef jsClass, void* data)
69{
70 ExecState* exec = toJS(ctx);
71 exec->globalData().heap->registerThread();
72 JSLock lock(exec);
73
74 if (!jsClass)
75 return toRef(new (exec) JSObject(exec->lexicalGlobalObject()->objectPrototype())); // slightly more efficient
76
77 JSObject* jsPrototype = jsClass->prototype(exec);
78 if (!jsPrototype)
79 jsPrototype = exec->lexicalGlobalObject()->objectPrototype();
80
81 return toRef(new (exec) JSCallbackObject<JSObject>(exec, jsClass, jsPrototype, data));
82}
83
84JSObjectRef JSObjectMakeFunctionWithCallback(JSContextRef ctx, JSStringRef name, JSObjectCallAsFunctionCallback callAsFunction)
85{
86 ExecState* exec = toJS(ctx);
87 exec->globalData().heap->registerThread();
88 JSLock lock(exec);
89
90 Identifier nameID = name ? name->identifier(exec) : Identifier(exec, "anonymous");
91
92 return toRef(new (exec) JSCallbackFunction(exec, callAsFunction, nameID));
93}
94
95JSObjectRef JSObjectMakeConstructor(JSContextRef ctx, JSClassRef jsClass, JSObjectCallAsConstructorCallback callAsConstructor)
96{
97 ExecState* exec = toJS(ctx);
98 exec->globalData().heap->registerThread();
99 JSLock lock(exec);
100
101 JSValue* jsPrototype = jsClass
102 ? jsClass->prototype(exec)
103 : exec->dynamicGlobalObject()->objectPrototype();
104
105 JSCallbackConstructor* constructor = new (exec) JSCallbackConstructor(exec, jsClass, callAsConstructor);
106 constructor->putDirect(exec->propertyNames().prototype, jsPrototype, DontEnum | DontDelete | ReadOnly);
107 return toRef(constructor);
108}
109
110JSObjectRef JSObjectMakeFunction(JSContextRef ctx, JSStringRef name, unsigned parameterCount, const JSStringRef parameterNames[], JSStringRef body, JSStringRef sourceURL, int startingLineNumber, JSValueRef* exception)
111{
112 ExecState* exec = toJS(ctx);
113 exec->globalData().heap->registerThread();
114 JSLock lock(exec);
115
116 Identifier nameID = name ? name->identifier(exec) : Identifier(exec, "anonymous");
117
118 ArgList args;
119 for (unsigned i = 0; i < parameterCount; i++)
120 args.append(jsString(exec, parameterNames[i]->ustring()));
121 args.append(jsString(exec, body->ustring()));
122
123 JSObject* result = constructFunction(exec, args, nameID, sourceURL->ustring(), startingLineNumber);
124 if (exec->hadException()) {
125 if (exception)
126 *exception = toRef(exec->exception());
127 exec->clearException();
128 result = 0;
129 }
130 return toRef(result);
131}
132
133JSValueRef JSObjectGetPrototype(JSContextRef, JSObjectRef object)
134{
135 JSObject* jsObject = toJS(object);
136 return toRef(jsObject->prototype());
137}
138
139void JSObjectSetPrototype(JSContextRef, JSObjectRef object, JSValueRef value)
140{
141 JSObject* jsObject = toJS(object);
142 JSValue* jsValue = toJS(value);
143
144 jsObject->setPrototype(jsValue->isObject() ? jsValue : jsNull());
145}
146
147bool JSObjectHasProperty(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName)
148{
149 ExecState* exec = toJS(ctx);
150 exec->globalData().heap->registerThread();
151 JSLock lock(exec);
152
153 JSObject* jsObject = toJS(object);
154
155 return jsObject->hasProperty(exec, propertyName->identifier(exec));
156}
157
158JSValueRef JSObjectGetProperty(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception)
159{
160 ExecState* exec = toJS(ctx);
161 exec->globalData().heap->registerThread();
162 JSLock lock(exec);
163
164 JSObject* jsObject = toJS(object);
165
166 JSValue* jsValue = jsObject->get(exec, propertyName->identifier(exec));
167 if (exec->hadException()) {
168 if (exception)
169 *exception = toRef(exec->exception());
170 exec->clearException();
171 }
172 return toRef(jsValue);
173}
174
175void JSObjectSetProperty(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef value, JSPropertyAttributes attributes, JSValueRef* exception)
176{
177 ExecState* exec = toJS(ctx);
178 exec->globalData().heap->registerThread();
179 JSLock lock(exec);
180
181 JSObject* jsObject = toJS(object);
182 Identifier name(propertyName->identifier(exec));
183 JSValue* jsValue = toJS(value);
184
185 if (attributes && !jsObject->hasProperty(exec, name))
186 jsObject->putWithAttributes(exec, name, jsValue, attributes);
187 else {
188 PutPropertySlot slot;
189 jsObject->put(exec, name, jsValue, slot);
190 }
191
192 if (exec->hadException()) {
193 if (exception)
194 *exception = toRef(exec->exception());
195 exec->clearException();
196 }
197}
198
199JSValueRef JSObjectGetPropertyAtIndex(JSContextRef ctx, JSObjectRef object, unsigned propertyIndex, JSValueRef* exception)
200{
201 ExecState* exec = toJS(ctx);
202 exec->globalData().heap->registerThread();
203 JSLock lock(exec);
204
205 JSObject* jsObject = toJS(object);
206
207 JSValue* jsValue = jsObject->get(exec, propertyIndex);
208 if (exec->hadException()) {
209 if (exception)
210 *exception = toRef(exec->exception());
211 exec->clearException();
212 }
213 return toRef(jsValue);
214}
215
216
217void JSObjectSetPropertyAtIndex(JSContextRef ctx, JSObjectRef object, unsigned propertyIndex, JSValueRef value, JSValueRef* exception)
218{
219 ExecState* exec = toJS(ctx);
220 exec->globalData().heap->registerThread();
221 JSLock lock(exec);
222
223 JSObject* jsObject = toJS(object);
224 JSValue* jsValue = toJS(value);
225
226 jsObject->put(exec, propertyIndex, jsValue);
227 if (exec->hadException()) {
228 if (exception)
229 *exception = toRef(exec->exception());
230 exec->clearException();
231 }
232}
233
234bool JSObjectDeleteProperty(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception)
235{
236 ExecState* exec = toJS(ctx);
237 exec->globalData().heap->registerThread();
238 JSLock lock(exec);
239
240 JSObject* jsObject = toJS(object);
241
242 bool result = jsObject->deleteProperty(exec, propertyName->identifier(exec));
243 if (exec->hadException()) {
244 if (exception)
245 *exception = toRef(exec->exception());
246 exec->clearException();
247 }
248 return result;
249}
250
251void* JSObjectGetPrivate(JSObjectRef object)
252{
253 JSObject* jsObject = toJS(object);
254
255 if (jsObject->inherits(&JSCallbackObject<JSGlobalObject>::info))
256 return static_cast<JSCallbackObject<JSGlobalObject>*>(jsObject)->getPrivate();
257 else if (jsObject->inherits(&JSCallbackObject<JSObject>::info))
258 return static_cast<JSCallbackObject<JSObject>*>(jsObject)->getPrivate();
259
260 return 0;
261}
262
263bool JSObjectSetPrivate(JSObjectRef object, void* data)
264{
265 JSObject* jsObject = toJS(object);
266
267 if (jsObject->inherits(&JSCallbackObject<JSGlobalObject>::info)) {
268 static_cast<JSCallbackObject<JSGlobalObject>*>(jsObject)->setPrivate(data);
269 return true;
270 } else if (jsObject->inherits(&JSCallbackObject<JSObject>::info)) {
271 static_cast<JSCallbackObject<JSObject>*>(jsObject)->setPrivate(data);
272 return true;
273 }
274
275 return false;
276}
277
278bool JSObjectIsFunction(JSContextRef, JSObjectRef object)
279{
280 CallData callData;
281 return toJS(object)->getCallData(callData) != CallTypeNone;
282}
283
284JSValueRef JSObjectCallAsFunction(JSContextRef ctx, JSObjectRef object, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
285{
286 ExecState* exec = toJS(ctx);
287 exec->globalData().heap->registerThread();
288 JSLock lock(exec);
289
290 JSObject* jsObject = toJS(object);
291 JSObject* jsThisObject = toJS(thisObject);
292
293 if (!jsThisObject)
294 jsThisObject = exec->globalThisValue();
295
296 ArgList argList;
297 for (size_t i = 0; i < argumentCount; i++)
298 argList.append(toJS(arguments[i]));
299
300 CallData callData;
301 CallType callType = jsObject->getCallData(callData);
302 if (callType == CallTypeNone)
303 return 0;
304
305 JSValueRef result = toRef(call(exec, jsObject, callType, callData, jsThisObject, argList));
306 if (exec->hadException()) {
307 if (exception)
308 *exception = toRef(exec->exception());
309 exec->clearException();
310 result = 0;
311 }
312 return result;
313}
314
315bool JSObjectIsConstructor(JSContextRef, JSObjectRef object)
316{
317 JSObject* jsObject = toJS(object);
318 ConstructData constructData;
319 return jsObject->getConstructData(constructData) != ConstructTypeNone;
320}
321
322JSObjectRef JSObjectCallAsConstructor(JSContextRef ctx, JSObjectRef object, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
323{
324 ExecState* exec = toJS(ctx);
325 exec->globalData().heap->registerThread();
326 JSLock lock(exec);
327
328 JSObject* jsObject = toJS(object);
329
330 ConstructData constructData;
331 ConstructType constructType = jsObject->getConstructData(constructData);
332 if (constructType == ConstructTypeNone)
333 return 0;
334
335 ArgList argList;
336 for (size_t i = 0; i < argumentCount; i++)
337 argList.append(toJS(arguments[i]));
338 JSObjectRef result = toRef(construct(exec, jsObject, constructType, constructData, argList));
339 if (exec->hadException()) {
340 if (exception)
341 *exception = toRef(exec->exception());
342 exec->clearException();
343 result = 0;
344 }
345 return result;
346}
347
348struct OpaqueJSPropertyNameArray {
349 OpaqueJSPropertyNameArray(JSGlobalData* globalData)
350 : refCount(0)
351 , globalData(globalData)
352 {
353 }
354
355 unsigned refCount;
356 JSGlobalData* globalData;
357 Vector<JSRetainPtr<JSStringRef> > array;
358};
359
360JSPropertyNameArrayRef JSObjectCopyPropertyNames(JSContextRef ctx, JSObjectRef object)
361{
362 JSObject* jsObject = toJS(object);
363 ExecState* exec = toJS(ctx);
364 exec->globalData().heap->registerThread();
365 JSLock lock(exec);
366
367 JSGlobalData* globalData = &exec->globalData();
368
369 JSPropertyNameArrayRef propertyNames = new OpaqueJSPropertyNameArray(globalData);
370 PropertyNameArray array(globalData);
371 jsObject->getPropertyNames(exec, array);
372
373 size_t size = array.size();
374 propertyNames->array.reserveCapacity(size);
375 for (size_t i = 0; i < size; ++i)
376 propertyNames->array.append(JSRetainPtr<JSStringRef>(Adopt, OpaqueJSString::create(array[i].ustring()).releaseRef()));
377
378 return JSPropertyNameArrayRetain(propertyNames);
379}
380
381JSPropertyNameArrayRef JSPropertyNameArrayRetain(JSPropertyNameArrayRef array)
382{
383 ++array->refCount;
384 return array;
385}
386
387void JSPropertyNameArrayRelease(JSPropertyNameArrayRef array)
388{
389 if (--array->refCount == 0) {
390 JSLock lock(array->globalData->isSharedInstance);
391 delete array;
392 }
393}
394
395size_t JSPropertyNameArrayGetCount(JSPropertyNameArrayRef array)
396{
397 return array->array.size();
398}
399
400JSStringRef JSPropertyNameArrayGetNameAtIndex(JSPropertyNameArrayRef array, size_t index)
401{
402 return array->array[static_cast<unsigned>(index)].get();
403}
404
405void JSPropertyNameAccumulatorAddName(JSPropertyNameAccumulatorRef array, JSStringRef propertyName)
406{
407 PropertyNameArray* propertyNames = toJS(array);
408
409 propertyNames->globalData()->heap->registerThread();
410 JSLock lock(propertyNames->globalData()->isSharedInstance);
411
412 propertyNames->add(propertyName->identifier(propertyNames->globalData()));
413}
Note: See TracBrowser for help on using the repository browser.