source: webkit/trunk/JavaScriptCore/kjs/Arguments.cpp@ 37048

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

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

Reviewed by Darin Adler.


Changed the layout of the call frame from


{ header, parameters, locals | constants, temporaries }


to


{ parameters, header | locals, constants, temporaries }


This simplifies function entry+exit, and enables a number of future
optimizations.


13.5% speedup on empty call benchmark for bytecode; 23.6% speedup on
empty call benchmark for CTI.


SunSpider says no change. SunSpider --v8 says 1% faster.

  • VM/CTI.cpp:


Added a bit of abstraction for calculating whether a register is a
constant, since this patch changes that calculation:
(JSC::CTI::isConstant):
(JSC::CTI::getConstant):
(JSC::CTI::emitGetArg):
(JSC::CTI::emitGetPutArg):
(JSC::CTI::getConstantImmediateNumericArg):

Updated for changes to callframe header location:
(JSC::CTI::emitPutToCallFrameHeader):
(JSC::CTI::emitGetFromCallFrameHeader):
(JSC::CTI::printOpcodeOperandTypes):


Renamed to spite Oliver:
(JSC::CTI::emitInitRegister):


Added an abstraction for emitting a call through a register, so that
calls through registers generate exception info, too:
(JSC::CTI::emitCall):

Updated to match the new callframe header layout, and to support calls
through registers, which have no destination address:
(JSC::CTI::compileOpCall):
(JSC::CTI::privateCompileMainPass):
(JSC::CTI::privateCompileSlowCases):
(JSC::CTI::privateCompile):

  • VM/CTI.h:

More of the above:
(JSC::CallRecord::CallRecord):

  • VM/CodeBlock.cpp:

Updated for new register layout:
(JSC::registerName):
(JSC::CodeBlock::dump):

  • VM/CodeBlock.h:


Updated CodeBlock to track slightly different information about the
register frame, and tweaked the style of an ASSERT_NOT_REACHED.
(JSC::CodeBlock::CodeBlock):
(JSC::CodeBlock::getStubInfo):

  • VM/CodeGenerator.cpp:


Added some abstraction around constant register allocation, since this
patch changes it, changed codegen to account for the new callframe
layout, and added abstraction around register fetching code
that used to assume that all local registers lived at negative indices,
since vars now live at positive indices:
(JSC::CodeGenerator::generate):
(JSC::CodeGenerator::addVar):
(JSC::CodeGenerator::addGlobalVar):
(JSC::CodeGenerator::allocateConstants):
(JSC::CodeGenerator::CodeGenerator):
(JSC::CodeGenerator::addParameter):
(JSC::CodeGenerator::registerFor):
(JSC::CodeGenerator::constRegisterFor):
(JSC::CodeGenerator::newRegister):
(JSC::CodeGenerator::newTemporary):
(JSC::CodeGenerator::highestUsedRegister):
(JSC::CodeGenerator::addConstant):


ASSERT that our caller referenced the registers it passed to us.
Otherwise, we might overwrite them with parameters:
(JSC::CodeGenerator::emitCall):
(JSC::CodeGenerator::emitConstruct):

  • VM/CodeGenerator.h:


Added some abstraction for getting a RegisterID for a given index,
since the rules are a little weird:
(JSC::CodeGenerator::registerFor):

  • VM/Machine.cpp:

Utility function to transform a machine return PC to a virtual machine
return VPC, for the sake of stack unwinding, since both PCs are stored
in the same location now:
(JSC::vPCForPC):

Tweaked to account for new call frame:
(JSC::Machine::initializeCallFrame):


Tweaked to account for registerOffset supplied by caller:
(JSC::slideRegisterWindowForCall):

Tweaked to account for new register layout:
(JSC::scopeChainForCall):
(JSC::Machine::callEval):
(JSC::Machine::dumpRegisters):
(JSC::Machine::unwindCallFrame):
(JSC::Machine::execute):

Changed op_call and op_construct to implement the new calling convention:
(JSC::Machine::privateExecute):

Tweaked to account for the new register layout:
(JSC::Machine::retrieveArguments):
(JSC::Machine::retrieveCaller):
(JSC::Machine::retrieveLastCaller):
(JSC::Machine::callFrame):
(JSC::Machine::getArgumentsData):

Changed CTI call helpers to implement the new calling convention:
(JSC::Machine::cti_op_call_JSFunction):
(JSC::Machine::cti_op_call_NotJSFunction):
(JSC::Machine::cti_op_ret_activation):
(JSC::Machine::cti_op_ret_profiler):
(JSC::Machine::cti_op_construct_JSConstruct):
(JSC::Machine::cti_op_construct_NotJSConstruct):
(JSC::Machine::cti_op_call_eval):

  • VM/Machine.h:
  • VM/Opcode.h:


Renamed op_initialise_locals to op_init, because this opcode
doesn't initialize all locals, and it doesn't initialize only locals.
Also, to spite Oliver.


  • VM/RegisterFile.h:


New call frame enumeration values:
(JSC::RegisterFile::):

Simplified the calculation of whether a RegisterID is a temporary,
since we can no longer assume that all positive non-constant registers
are temporaries:

  • VM/RegisterID.h: (JSC::RegisterID::RegisterID): (JSC::RegisterID::setTemporary): (JSC::RegisterID::isTemporary):

Renamed firstArgumentIndex to firstParameterIndex because the assumption
that this variable pertained to the actual arguments supplied by the
caller caused me to write some buggy code:

  • kjs/Arguments.cpp: (JSC::ArgumentsData::ArgumentsData): (JSC::Arguments::Arguments): (JSC::Arguments::fillArgList): (JSC::Arguments::getOwnPropertySlot): (JSC::Arguments::put):

Updated for new call frame layout:

  • kjs/DebuggerCallFrame.cpp: (JSC::DebuggerCallFrame::functionName): (JSC::DebuggerCallFrame::type):
  • kjs/DebuggerCallFrame.h:

Changed the activation object to account for the fact that a call frame
header now sits between parameters and local variables. This change
requires all variable objects to do their own marking, since they
now use their register storage differently:

  • kjs/JSActivation.cpp: (JSC::JSActivation::mark): (JSC::JSActivation::copyRegisters): (JSC::JSActivation::createArgumentsObject):
  • kjs/JSActivation.h:

Updated global object to use the new interfaces required by the change
to JSActivation above:

  • kjs/JSGlobalObject.cpp: (JSC::JSGlobalObject::reset): (JSC::JSGlobalObject::mark): (JSC::JSGlobalObject::copyGlobalsFrom): (JSC::JSGlobalObject::copyGlobalsTo):
  • kjs/JSGlobalObject.h: (JSC::JSGlobalObject::addStaticGlobals):

Updated static scope object to use the new interfaces required by the
change to JSActivation above:

  • kjs/JSStaticScopeObject.cpp: (JSC::JSStaticScopeObject::mark): (JSC::JSStaticScopeObject::~JSStaticScopeObject):
  • kjs/JSStaticScopeObject.h: (JSC::JSStaticScopeObject::JSStaticScopeObject): (JSC::JSStaticScopeObject::d):

Updated variable object to use the new interfaces required by the
change to JSActivation above:

  • kjs/JSVariableObject.cpp: (JSC::JSVariableObject::copyRegisterArray): (JSC::JSVariableObject::setRegisters):
  • kjs/JSVariableObject.h:

Changed the bit twiddling in symbol table not to assume that all indices
are negative, since they can be positive now:

  • kjs/SymbolTable.h: (JSC::SymbolTableEntry::SymbolTableEntry): (JSC::SymbolTableEntry::isNull): (JSC::SymbolTableEntry::getIndex): (JSC::SymbolTableEntry::getAttributes): (JSC::SymbolTableEntry::setAttributes): (JSC::SymbolTableEntry::isReadOnly): (JSC::SymbolTableEntry::pack): (JSC::SymbolTableEntry::isValidIndex):

Changed call and construct nodes to ref their functions and/or bases,
so that emitCall/emitConstruct doesn't overwrite them with parameters.
Also, updated for rename to registerFor:

  • kjs/nodes.cpp: (JSC::ResolveNode::emitCode): (JSC::NewExprNode::emitCode): (JSC::EvalFunctionCallNode::emitCode): (JSC::FunctionCallValueNode::emitCode): (JSC::FunctionCallResolveNode::emitCode): (JSC::FunctionCallBracketNode::emitCode): (JSC::FunctionCallDotNode::emitCode): (JSC::PostfixResolveNode::emitCode): (JSC::DeleteResolveNode::emitCode): (JSC::TypeOfResolveNode::emitCode): (JSC::PrefixResolveNode::emitCode): (JSC::ReadModifyResolveNode::emitCode): (JSC::AssignResolveNode::emitCode): (JSC::ConstDeclNode::emitCodeSingle): (JSC::ForInNode::emitCode):

Added abstraction for getting exception info out of a call through a
register:

  • masm/X86Assembler.h: (JSC::X86Assembler::emitCall):


Removed duplicate #if:

  • wtf/Platform.h:
  • Property svn:eol-style set to native
File size: 8.9 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 "Arguments.h"
27
28#include "JSActivation.h"
29#include "JSFunction.h"
30#include "JSGlobalObject.h"
31
32using namespace std;
33
34namespace JSC {
35
36ASSERT_CLASS_FITS_IN_CELL(Arguments);
37
38const ClassInfo Arguments::info = { "Arguments", 0, 0, 0 };
39
40struct ArgumentsData : Noncopyable {
41 ArgumentsData(JSActivation* activation, unsigned numParameters, int firstParameterIndex, unsigned numArguments, JSFunction* callee)
42 : activation(activation)
43 , numParameters(numParameters)
44 , firstParameterIndex(firstParameterIndex)
45 , numArguments(numArguments)
46 , extraArguments(0)
47 , callee(callee)
48 , overrodeLength(false)
49 , overrodeCallee(false)
50 {
51 }
52
53 JSActivation* activation;
54
55 unsigned numParameters;
56 int firstParameterIndex;
57 unsigned numArguments;
58 Register* extraArguments;
59 OwnArrayPtr<bool> deletedArguments;
60 Register extraArgumentsFixedBuffer[4];
61
62 JSFunction* callee;
63 bool overrodeLength : 1;
64 bool overrodeCallee : 1;
65};
66
67// ECMA 10.1.8
68Arguments::Arguments(ExecState* exec, JSFunction* function, JSActivation* activation, int firstParameterIndex, Register* argv, int argc)
69 : JSObject(exec->lexicalGlobalObject()->argumentsStructure())
70 , d(new ArgumentsData(activation, function->numParameters(), firstParameterIndex, argc, function))
71{
72 ASSERT(activation);
73
74 if (d->numArguments > d->numParameters) {
75 unsigned numExtraArguments = d->numArguments - d->numParameters;
76 Register* extraArguments;
77 if (numExtraArguments > sizeof(d->extraArgumentsFixedBuffer) / sizeof(Register))
78 extraArguments = new Register[numExtraArguments];
79 else
80 extraArguments = d->extraArgumentsFixedBuffer;
81 for (unsigned i = 0; i < numExtraArguments; ++i)
82 extraArguments[i] = argv[d->numParameters + i];
83 d->extraArguments = extraArguments;
84 }
85}
86
87Arguments::~Arguments()
88{
89 if (d->extraArguments != d->extraArgumentsFixedBuffer)
90 delete [] d->extraArguments;
91}
92
93void Arguments::mark()
94{
95 JSObject::mark();
96
97 if (d->extraArguments) {
98 unsigned numExtraArguments = d->numArguments - d->numParameters;
99 for (unsigned i = 0; i < numExtraArguments; ++i) {
100 if (!d->extraArguments[i].marked())
101 d->extraArguments[i].mark();
102 }
103 }
104
105 if (!d->callee->marked())
106 d->callee->mark();
107
108 if (!d->activation->marked())
109 d->activation->mark();
110}
111
112void Arguments::fillArgList(ExecState* exec, ArgList& args)
113{
114 if (LIKELY(!d->deletedArguments)) {
115 if (LIKELY(!d->numParameters)) {
116 args.initialize(d->extraArguments, d->numArguments);
117 return;
118 }
119
120 if (d->numParameters == d->numArguments) {
121 args.initialize(&d->activation->registerAt(d->firstParameterIndex), d->numArguments);
122 return;
123 }
124
125 unsigned parametersLength = min(d->numParameters, d->numArguments);
126 unsigned i = 0;
127 for (; i < parametersLength; ++i)
128 args.append(d->activation->uncheckedSymbolTableGetValue(d->firstParameterIndex + i));
129 for (; i < d->numArguments; ++i)
130 args.append(d->extraArguments[i - d->numParameters].getJSValue());
131 return;
132 }
133
134 unsigned parametersLength = min(d->numParameters, d->numArguments);
135 unsigned i = 0;
136 for (; i < parametersLength; ++i) {
137 if (!d->deletedArguments[i])
138 args.append(d->activation->uncheckedSymbolTableGetValue(d->firstParameterIndex + i));
139 else
140 args.append(get(exec, i));
141 }
142 for (; i < d->numArguments; ++i) {
143 if (!d->deletedArguments[i])
144 args.append(d->extraArguments[i - d->numParameters].getJSValue());
145 else
146 args.append(get(exec, i));
147 }
148}
149
150bool Arguments::getOwnPropertySlot(ExecState* exec, unsigned i, PropertySlot& slot)
151{
152 if (i < d->numArguments && (!d->deletedArguments || !d->deletedArguments[i])) {
153 if (i < d->numParameters)
154 d->activation->uncheckedSymbolTableGet(d->firstParameterIndex + i, slot);
155 else
156 slot.setValue(d->extraArguments[i - d->numParameters].getJSValue());
157 return true;
158 }
159
160 return JSObject::getOwnPropertySlot(exec, Identifier(exec, UString::from(i)), slot);
161}
162
163bool Arguments::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
164{
165 bool isArrayIndex;
166 unsigned i = propertyName.toArrayIndex(&isArrayIndex);
167 if (isArrayIndex && i < d->numArguments && (!d->deletedArguments || !d->deletedArguments[i])) {
168 if (i < d->numParameters)
169 d->activation->uncheckedSymbolTableGet(d->firstParameterIndex + i, slot);
170 else
171 slot.setValue(d->extraArguments[i - d->numParameters].getJSValue());
172 return true;
173 }
174
175 if (propertyName == exec->propertyNames().length && LIKELY(!d->overrodeLength)) {
176 slot.setValue(jsNumber(exec, d->numArguments));
177 return true;
178 }
179
180 if (propertyName == exec->propertyNames().callee && LIKELY(!d->overrodeCallee)) {
181 slot.setValue(d->callee);
182 return true;
183 }
184
185 return JSObject::getOwnPropertySlot(exec, propertyName, slot);
186}
187
188void Arguments::put(ExecState* exec, unsigned i, JSValue* value, PutPropertySlot& slot)
189{
190 if (i < d->numArguments && (!d->deletedArguments || !d->deletedArguments[i])) {
191 if (i < d->numParameters)
192 d->activation->uncheckedSymbolTablePut(d->firstParameterIndex + i, value);
193 else
194 d->extraArguments[i - d->numParameters] = value;
195 return;
196 }
197
198 JSObject::put(exec, Identifier(exec, UString::from(i)), value, slot);
199}
200
201void Arguments::put(ExecState* exec, const Identifier& propertyName, JSValue* value, PutPropertySlot& slot)
202{
203 bool isArrayIndex;
204 unsigned i = propertyName.toArrayIndex(&isArrayIndex);
205 if (isArrayIndex && i < d->numArguments && (!d->deletedArguments || !d->deletedArguments[i])) {
206 if (i < d->numParameters)
207 d->activation->uncheckedSymbolTablePut(d->firstParameterIndex + i, value);
208 else
209 d->extraArguments[i - d->numParameters] = value;
210 return;
211 }
212
213 if (propertyName == exec->propertyNames().length && !d->overrodeLength) {
214 d->overrodeLength = true;
215 putDirect(propertyName, value, DontEnum);
216 return;
217 }
218
219 if (propertyName == exec->propertyNames().callee && !d->overrodeCallee) {
220 d->overrodeCallee = true;
221 putDirect(propertyName, value, DontEnum);
222 return;
223 }
224
225 JSObject::put(exec, propertyName, value, slot);
226}
227
228bool Arguments::deleteProperty(ExecState* exec, unsigned i)
229{
230 if (i < d->numArguments) {
231 if (!d->deletedArguments) {
232 d->deletedArguments.set(new bool[d->numArguments]);
233 memset(d->deletedArguments.get(), 0, sizeof(bool) * d->numArguments);
234 }
235 if (!d->deletedArguments[i]) {
236 d->deletedArguments[i] = true;
237 return true;
238 }
239 }
240
241 return JSObject::deleteProperty(exec, Identifier(exec, UString::from(i)));
242}
243
244bool Arguments::deleteProperty(ExecState* exec, const Identifier& propertyName)
245{
246 bool isArrayIndex;
247 unsigned i = propertyName.toArrayIndex(&isArrayIndex);
248 if (isArrayIndex && i < d->numArguments) {
249 if (!d->deletedArguments) {
250 d->deletedArguments.set(new bool[d->numArguments]);
251 memset(d->deletedArguments.get(), 0, sizeof(bool) * d->numArguments);
252 }
253 if (!d->deletedArguments[i]) {
254 d->deletedArguments[i] = true;
255 return true;
256 }
257 }
258
259 if (propertyName == exec->propertyNames().length && !d->overrodeLength) {
260 d->overrodeLength = true;
261 return true;
262 }
263
264 if (propertyName == exec->propertyNames().callee && !d->overrodeCallee) {
265 d->overrodeCallee = true;
266 return true;
267 }
268
269 return JSObject::deleteProperty(exec, propertyName);
270}
271
272} // namespace JSC
Note: See TracBrowser for help on using the repository browser.