source: webkit/trunk/JavaScriptCore/kjs/JSFunction.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: 5.7 KB
Line 
1/*
2 * Copyright (C) 1999-2002 Harri Porten ([email protected])
3 * Copyright (C) 2001 Peter Kelly ([email protected])
4 * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
5 * Copyright (C) 2007 Cameron Zwarich ([email protected])
6 * Copyright (C) 2007 Maks Orlovich
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
17 *
18 * You should have received a copy of the GNU Library General Public License
19 * along with this library; see the file COPYING.LIB. If not, write to
20 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 * Boston, MA 02110-1301, USA.
22 *
23 */
24
25#include "config.h"
26#include "JSFunction.h"
27
28#include "CommonIdentifiers.h"
29#include "ExecState.h"
30#include "FunctionPrototype.h"
31#include "JSGlobalObject.h"
32#include "Machine.h"
33#include "ObjectPrototype.h"
34#include "Parser.h"
35#include "PropertyNameArray.h"
36#include "ScopeChainMark.h"
37
38using namespace WTF;
39using namespace Unicode;
40
41namespace KJS {
42
43ASSERT_CLASS_FITS_IN_CELL(JSFunction);
44
45const ClassInfo JSFunction::info = { "Function", 0, 0, 0 };
46
47JSFunction::JSFunction(ExecState* exec, const Identifier& name, FunctionBodyNode* body, ScopeChainNode* scopeChainNode)
48 : Base(exec, exec->lexicalGlobalObject()->functionPrototype(), name)
49 , m_body(body)
50 , m_scopeChain(scopeChainNode)
51{
52}
53
54void JSFunction::mark()
55{
56 Base::mark();
57 m_body->mark();
58 m_scopeChain.mark();
59}
60
61CallType JSFunction::getCallData(CallData& callData)
62{
63 callData.js.functionBody = m_body.get();
64 callData.js.scopeChain = m_scopeChain.node();
65 return CallTypeJS;
66}
67
68JSValue* JSFunction::call(ExecState* exec, JSValue* thisValue, const ArgList& args)
69{
70 return exec->machine()->execute(m_body.get(), exec, this, thisValue->toThisObject(exec), args, m_scopeChain.node(), exec->exceptionSlot());
71}
72
73JSValue* JSFunction::argumentsGetter(ExecState* exec, const Identifier&, const PropertySlot& slot)
74{
75 JSFunction* thisObj = static_cast<JSFunction*>(slot.slotBase());
76 return exec->machine()->retrieveArguments(exec, thisObj);
77}
78
79JSValue* JSFunction::callerGetter(ExecState* exec, const Identifier&, const PropertySlot& slot)
80{
81 JSFunction* thisObj = static_cast<JSFunction*>(slot.slotBase());
82 return exec->machine()->retrieveCaller(exec, thisObj);
83}
84
85JSValue* JSFunction::lengthGetter(ExecState* exec, const Identifier&, const PropertySlot& slot)
86{
87 JSFunction* thisObj = static_cast<JSFunction*>(slot.slotBase());
88 return jsNumber(exec, thisObj->m_body->parameters().size());
89}
90
91bool JSFunction::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
92{
93 if (propertyName == exec->propertyNames().arguments) {
94 slot.setCustom(this, argumentsGetter);
95 return true;
96 }
97
98 if (propertyName == exec->propertyNames().length) {
99 slot.setCustom(this, lengthGetter);
100 return true;
101 }
102
103 if (propertyName == exec->propertyNames().caller) {
104 slot.setCustom(this, callerGetter);
105 return true;
106 }
107
108 return Base::getOwnPropertySlot(exec, propertyName, slot);
109}
110
111void JSFunction::put(ExecState* exec, const Identifier& propertyName, JSValue* value, PutPropertySlot& slot)
112{
113 if (propertyName == exec->propertyNames().arguments || propertyName == exec->propertyNames().length)
114 return;
115 Base::put(exec, propertyName, value, slot);
116}
117
118bool JSFunction::deleteProperty(ExecState* exec, const Identifier& propertyName)
119{
120 if (propertyName == exec->propertyNames().arguments || propertyName == exec->propertyNames().length)
121 return false;
122 return Base::deleteProperty(exec, propertyName);
123}
124
125/* Returns the parameter name corresponding to the given index. eg:
126 * function f1(x, y, z): getParameterName(0) --> x
127 *
128 * If a name appears more than once, only the last index at which
129 * it appears associates with it. eg:
130 * function f2(x, x): getParameterName(0) --> null
131 */
132const Identifier& JSFunction::getParameterName(int index)
133{
134 Vector<Identifier>& parameters = m_body->parameters();
135
136 if (static_cast<size_t>(index) >= m_body->parameters().size())
137 return m_scopeChain.globalObject()->globalData()->propertyNames->nullIdentifier;
138
139 const Identifier& name = parameters[index];
140
141 // Are there any subsequent parameters with the same name?
142 size_t size = parameters.size();
143 for (size_t i = index + 1; i < size; ++i) {
144 if (parameters[i] == name)
145 return m_scopeChain.globalObject()->globalData()->propertyNames->nullIdentifier;
146 }
147
148 return name;
149}
150
151// ECMA 13.2.2 [[Construct]]
152ConstructType JSFunction::getConstructData(ConstructData& constructData)
153{
154 constructData.js.functionBody = m_body.get();
155 constructData.js.scopeChain = m_scopeChain.node();
156 return ConstructTypeJS;
157}
158
159JSObject* JSFunction::construct(ExecState* exec, const ArgList& args)
160{
161 JSObject* proto;
162 JSValue* p = get(exec, exec->propertyNames().prototype);
163 if (p->isObject())
164 proto = static_cast<JSObject*>(p);
165 else
166 proto = exec->lexicalGlobalObject()->objectPrototype();
167
168 JSObject* thisObj = new (exec) JSObject(proto);
169
170 JSValue* result = exec->machine()->execute(m_body.get(), exec, this, thisObj, args, m_scopeChain.node(), exec->exceptionSlot());
171 if (exec->hadException() || !result->isObject())
172 return thisObj;
173 return static_cast<JSObject*>(result);
174}
175
176} // namespace KJS
Note: See TracBrowser for help on using the repository browser.