source: webkit/trunk/JavaScriptCore/VM/CodeBlock.h@ 37160

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

2008-10-01 Cameron Zwarich <[email protected]>

Reviewed by Darin Adler.

Bug 21123: using "arguments" in a function should not force creation of an activation object
<https://bugs.webkit.org/show_bug.cgi?id=21123>

Make the 'arguments' object not require a JSActivation. We store the
'arguments' object in the OptionalCalleeArguments call frame slot. We
need to be able to get the original 'arguments' object to tear it off
when returning from a function, but 'arguments' may be assigned to in a
number of ways.

Therefore, we use the OptionalCalleeArguments slot when we want to get
the original activation or we know that 'arguments' was not assigned a
different value. When 'arguments' may have been assigned a new value,
we use a new local variable that is initialized with 'arguments'. Since
a function parameter named 'arguments' may overwrite the value of
'arguments', we also need to be careful to look up 'arguments' in the
symbol table, so we get the parameter named 'arguments' instead of the
local variable that we have added for holding the 'arguments' object.

This is a 19.1% win on the V8 Raytrace benchmark using the SunSpider
harness, and a 20.7% win using the V8 harness. This amounts to a 6.5%
total speedup on the V8 benchmark suite using the V8 harness.

JavaScriptCore:

  • VM/CTI.cpp: (JSC::CTI::privateCompileMainPass):
  • VM/CodeBlock.h:
  • VM/CodeGenerator.cpp: (JSC::CodeGenerator::CodeGenerator):
  • VM/Machine.cpp: (JSC::Machine::unwindCallFrame): (JSC::Machine::privateExecute): (JSC::Machine::retrieveArguments): (JSC::Machine::cti_op_init_arguments): (JSC::Machine::cti_op_ret_activation_arguments):
  • VM/Machine.h:
  • VM/RegisterFile.h: (JSC::RegisterFile::):
  • kjs/Arguments.cpp: (JSC::Arguments::mark): (JSC::Arguments::fillArgList): (JSC::Arguments::getOwnPropertySlot): (JSC::Arguments::put):
  • kjs/Arguments.h: (JSC::Arguments::setRegisters): (JSC::Arguments::init): (JSC::Arguments::Arguments): (JSC::Arguments::copyRegisters): (JSC::JSActivation::copyRegisters):
  • kjs/JSActivation.cpp: (JSC::JSActivation::argumentsGetter):
  • kjs/JSActivation.h: (JSC::JSActivation::JSActivationData::JSActivationData):
  • kjs/grammar.y:
  • kjs/nodes.h: (JSC::ScopeNode::setUsesArguments):
  • masm/X86Assembler.h: (JSC::X86Assembler::): (JSC::X86Assembler::orl_mr):

LayoutTests:

  • fast/js/arguments-expected.txt:
  • fast/js/function-dot-arguments-expected.txt:
  • fast/js/resources/arguments.js:
  • fast/js/resources/function-dot-arguments.js:
File size: 10.4 KB
Line 
1/*
2 * Copyright (C) 2008 Apple Inc. All rights reserved.
3 * Copyright (C) 2008 Cameron Zwarich <[email protected]>
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
15 * its contributors may be used to endorse or promote products derived
16 * from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
19 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
22 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30#ifndef CodeBlock_h
31#define CodeBlock_h
32
33#include "Instruction.h"
34#include "JSGlobalObject.h"
35#include "nodes.h"
36#include "Parser.h"
37#include "SourceRange.h"
38#include "ustring.h"
39#include <wtf/RefPtr.h>
40#include <wtf/Vector.h>
41
42namespace JSC {
43
44 class ExecState;
45
46 static ALWAYS_INLINE int missingThisObjectMarker() { return std::numeric_limits<int>::max(); }
47
48 struct HandlerInfo {
49 uint32_t start;
50 uint32_t end;
51 uint32_t target;
52 uint32_t scopeDepth;
53 void* nativeCode;
54 };
55
56 struct ExpressionRangeInfo {
57 enum {
58 MaxOffset = (1 << 7) - 1,
59 MaxDivot = (1 << 25) - 1
60 };
61 uint32_t instructionOffset : 25;
62 uint32_t divotPoint : 25;
63 uint32_t startOffset : 7;
64 uint32_t endOffset : 7;
65 };
66
67 struct LineInfo {
68 uint32_t instructionOffset;
69 int32_t lineNumber;
70 };
71
72 struct OffsetLocation {
73 int32_t branchOffset;
74#if ENABLE(CTI)
75 void* ctiOffset;
76#endif
77 };
78
79 struct StructureStubInfo {
80 StructureStubInfo(unsigned opcodeIndex)
81 : opcodeIndex(opcodeIndex)
82 , stubRoutine(0)
83 , callReturnLocation(0)
84 , hotPathBegin(0)
85 {
86 }
87
88 unsigned opcodeIndex;
89 void* stubRoutine;
90 void* callReturnLocation;
91 void* hotPathBegin;
92 };
93
94 struct StringJumpTable {
95 typedef HashMap<RefPtr<UString::Rep>, OffsetLocation> StringOffsetTable;
96 StringOffsetTable offsetTable;
97#if ENABLE(CTI)
98 void* ctiDefault; // FIXME: it should not be necessary to store this.
99#endif
100
101 inline int32_t offsetForValue(UString::Rep* value, int32_t defaultOffset)
102 {
103 StringOffsetTable::const_iterator end = offsetTable.end();
104 StringOffsetTable::const_iterator loc = offsetTable.find(value);
105 if (loc == end)
106 return defaultOffset;
107 return loc->second.branchOffset;
108 }
109
110#if ENABLE(CTI)
111 inline void* ctiForValue(UString::Rep* value)
112 {
113 StringOffsetTable::const_iterator end = offsetTable.end();
114 StringOffsetTable::const_iterator loc = offsetTable.find(value);
115 if (loc == end)
116 return ctiDefault;
117 return loc->second.ctiOffset;
118 }
119#endif
120 };
121
122 struct SimpleJumpTable {
123 // FIXME: The two Vectors can be combind into one Vector<OffsetLocation>
124 Vector<int32_t> branchOffsets;
125 int32_t min;
126#if ENABLE(CTI)
127 Vector<void*> ctiOffsets;
128 void* ctiDefault;
129#endif
130
131 int32_t offsetForValue(int32_t value, int32_t defaultOffset);
132 void add(int32_t key, int32_t offset)
133 {
134 if (!branchOffsets[key])
135 branchOffsets[key] = offset;
136 }
137
138#if ENABLE(CTI)
139 inline void* ctiForValue(int32_t value)
140 {
141 if (value >= min && static_cast<uint32_t>(value - min) < ctiOffsets.size())
142 return ctiOffsets[value - min];
143 return ctiDefault;
144 }
145#endif
146 };
147
148 class EvalCodeCache {
149 public:
150 PassRefPtr<EvalNode> get(ExecState* exec, const UString& evalSource, ScopeChainNode* scopeChain, JSValue*& exceptionValue)
151 {
152 RefPtr<EvalNode> evalNode;
153
154 if (evalSource.size() < maxCacheableSourceLength && (*scopeChain->begin())->isVariableObject())
155 evalNode = cacheMap.get(evalSource.rep());
156
157 if (!evalNode) {
158 int sourceId;
159 int errLine;
160 UString errMsg;
161
162 evalNode = exec->parser()->parse<EvalNode>(exec, UString(), 1, UStringSourceProvider::create(evalSource), &sourceId, &errLine, &errMsg);
163 if (evalNode) {
164 if (evalSource.size() < maxCacheableSourceLength && (*scopeChain->begin())->isVariableObject() && cacheMap.size() < maxCacheEntries)
165 cacheMap.set(evalSource.rep(), evalNode);
166 } else {
167 exceptionValue = Error::create(exec, SyntaxError, errMsg, errLine, sourceId, NULL);
168 return 0;
169 }
170 }
171
172 return evalNode.release();
173 }
174
175 private:
176 static const int maxCacheableSourceLength = 256;
177 static const int maxCacheEntries = 64;
178
179 HashMap<RefPtr<UString::Rep>, RefPtr<EvalNode> > cacheMap;
180 };
181
182 struct CodeBlock {
183 CodeBlock(ScopeNode* ownerNode_, CodeType codeType_, PassRefPtr<SourceProvider> source_, unsigned sourceOffset_)
184 : ownerNode(ownerNode_)
185 , globalData(0)
186#if ENABLE(CTI)
187 , ctiCode(0)
188#endif
189 , numCalleeRegisters(0)
190 , numConstants(0)
191 , numVars(0)
192 , numParameters(0)
193 , needsFullScopeChain(ownerNode_->usesEval() || ownerNode_->needsClosure())
194 , usesEval(ownerNode_->usesEval())
195 , codeType(codeType_)
196 , source(source_)
197 , sourceOffset(sourceOffset_)
198 {
199 }
200
201 ~CodeBlock();
202
203#if !defined(NDEBUG) || ENABLE_SAMPLING_TOOL
204 void dump(ExecState*) const;
205 void printStructureIDs(const Instruction*) const;
206 void printStructureID(const char* name, const Instruction*, int operand) const;
207#endif
208 int expressionRangeForVPC(const Instruction*, int& divot, int& startOffset, int& endOffset);
209 int lineNumberForVPC(const Instruction* vPC);
210 bool getHandlerForVPC(const Instruction* vPC, Instruction*& target, int& scopeDepth);
211 void* nativeExceptionCodeForHandlerVPC(const Instruction* handlerVPC);
212
213 void mark();
214 void refStructureIDs(Instruction* vPC) const;
215 void derefStructureIDs(Instruction* vPC) const;
216
217 StructureStubInfo& getStubInfo(void* returnAddress)
218 {
219 // FIXME: would a binary chop be faster here?
220 for (unsigned i = 0; ; ++i) {
221 if (structureIDInstructions[i].callReturnLocation == returnAddress)
222 return structureIDInstructions[i];
223 }
224 }
225
226 ScopeNode* ownerNode;
227 JSGlobalData* globalData;
228#if ENABLE(CTI)
229 void* ctiCode;
230#endif
231
232 int numCalleeRegisters;
233
234 // NOTE: numConstants holds the number of constant registers allocated
235 // by the code generator, not the number of constant registers used.
236 // (Duplicate constants are uniqued during code generation, and spare
237 // constant registers may be allocated.)
238 int numConstants;
239 int numVars;
240 int numParameters;
241 int thisRegister;
242 bool needsFullScopeChain;
243 bool usesEval;
244 bool usesArguments;
245 CodeType codeType;
246 RefPtr<SourceProvider> source;
247 unsigned sourceOffset;
248
249 Vector<Instruction> instructions;
250 Vector<StructureStubInfo> structureIDInstructions;
251
252 // Constant pool
253 Vector<Identifier> identifiers;
254 Vector<RefPtr<FuncDeclNode> > functions;
255 Vector<RefPtr<FuncExprNode> > functionExpressions;
256 Vector<Register> constantRegisters;
257 Vector<JSValue*> unexpectedConstants;
258 Vector<RefPtr<RegExp> > regexps;
259 Vector<HandlerInfo> exceptionHandlers;
260 Vector<ExpressionRangeInfo> expressionInfo;
261 Vector<LineInfo> lineInfo;
262
263 Vector<SimpleJumpTable> immediateSwitchJumpTables;
264 Vector<SimpleJumpTable> characterSwitchJumpTables;
265 Vector<StringJumpTable> stringSwitchJumpTables;
266
267 HashSet<unsigned, DefaultHash<unsigned>::Hash, WTF::UnsignedWithZeroKeyHashTraits<unsigned> > labels;
268
269#if ENABLE(CTI)
270 HashMap<void*, unsigned> ctiReturnAddressVPCMap;
271#endif
272
273 EvalCodeCache evalCodeCache;
274
275 private:
276#if !defined(NDEBUG) || ENABLE(SAMPLING_TOOL)
277 void dump(ExecState*, const Vector<Instruction>::const_iterator& begin, Vector<Instruction>::const_iterator&) const;
278#endif
279
280 };
281
282 // Program code is not marked by any function, so we make the global object
283 // responsible for marking it.
284
285 struct ProgramCodeBlock : public CodeBlock {
286 ProgramCodeBlock(ScopeNode* ownerNode_, CodeType codeType_, JSGlobalObject* globalObject_, PassRefPtr<SourceProvider> source_)
287 : CodeBlock(ownerNode_, codeType_, source_, 0)
288 , globalObject(globalObject_)
289 {
290 globalObject->codeBlocks().add(this);
291 }
292
293 ~ProgramCodeBlock()
294 {
295 if (globalObject)
296 globalObject->codeBlocks().remove(this);
297 }
298
299 JSGlobalObject* globalObject; // For program and eval nodes, the global object that marks the constant pool.
300 };
301
302 struct EvalCodeBlock : public ProgramCodeBlock {
303 EvalCodeBlock(ScopeNode* ownerNode_, JSGlobalObject* globalObject_, PassRefPtr<SourceProvider> source_)
304 : ProgramCodeBlock(ownerNode_, EvalCode, globalObject_, source_)
305 {
306 }
307 };
308
309} // namespace JSC
310
311#endif // CodeBlock_h
Note: See TracBrowser for help on using the repository browser.