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

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

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

Reviewed by Maciej Stachowiak.

Bug 21364: Remove the branch in op_ret for OptionalCalleeActivation and OptionalCalleeArguments
<https://bugs.webkit.org/show_bug.cgi?id=21364>

This patch does not yet remove the branch, but it does a bit of refactoring
so that a CodeGenerator now knows whether the associated CodeBlock will need
a full scope before doing any code generation. This makes it possible to emit
explicit tear-off instructions before every op_ret.

  • VM/CodeBlock.h: (JSC::CodeBlock::CodeBlock):
  • VM/CodeGenerator.cpp: (JSC::CodeGenerator::generate): (JSC::CodeGenerator::CodeGenerator): (JSC::CodeGenerator::emitPushScope): (JSC::CodeGenerator::emitPushNewScope):
  • kjs/nodes.h: (JSC::ScopeNode::needsActivation):
File size: 10.5 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 enum CodeType { GlobalCode, EvalCode, FunctionCode };
47
48 static ALWAYS_INLINE int missingThisObjectMarker() { return std::numeric_limits<int>::max(); }
49
50 struct HandlerInfo {
51 uint32_t start;
52 uint32_t end;
53 uint32_t target;
54 uint32_t scopeDepth;
55 void* nativeCode;
56 };
57
58 struct ExpressionRangeInfo {
59 enum {
60 MaxOffset = (1 << 7) - 1,
61 MaxDivot = (1 << 25) - 1
62 };
63 uint32_t instructionOffset : 25;
64 uint32_t divotPoint : 25;
65 uint32_t startOffset : 7;
66 uint32_t endOffset : 7;
67 };
68
69 struct LineInfo {
70 uint32_t instructionOffset;
71 int32_t lineNumber;
72 };
73
74 struct OffsetLocation {
75 int32_t branchOffset;
76#if ENABLE(CTI)
77 void* ctiOffset;
78#endif
79 };
80
81 struct StructureStubInfo {
82 StructureStubInfo(unsigned opcodeIndex)
83 : opcodeIndex(opcodeIndex)
84 , stubRoutine(0)
85 , callReturnLocation(0)
86 , hotPathBegin(0)
87 {
88 }
89
90 unsigned opcodeIndex;
91 void* stubRoutine;
92 void* callReturnLocation;
93 void* hotPathBegin;
94 };
95
96 struct StringJumpTable {
97 typedef HashMap<RefPtr<UString::Rep>, OffsetLocation> StringOffsetTable;
98 StringOffsetTable offsetTable;
99#if ENABLE(CTI)
100 void* ctiDefault; // FIXME: it should not be necessary to store this.
101#endif
102
103 inline int32_t offsetForValue(UString::Rep* value, int32_t defaultOffset)
104 {
105 StringOffsetTable::const_iterator end = offsetTable.end();
106 StringOffsetTable::const_iterator loc = offsetTable.find(value);
107 if (loc == end)
108 return defaultOffset;
109 return loc->second.branchOffset;
110 }
111
112#if ENABLE(CTI)
113 inline void* ctiForValue(UString::Rep* value)
114 {
115 StringOffsetTable::const_iterator end = offsetTable.end();
116 StringOffsetTable::const_iterator loc = offsetTable.find(value);
117 if (loc == end)
118 return ctiDefault;
119 return loc->second.ctiOffset;
120 }
121#endif
122 };
123
124 struct SimpleJumpTable {
125 // FIXME: The two Vectors can be combind into one Vector<OffsetLocation>
126 Vector<int32_t> branchOffsets;
127 int32_t min;
128#if ENABLE(CTI)
129 Vector<void*> ctiOffsets;
130 void* ctiDefault;
131#endif
132
133 int32_t offsetForValue(int32_t value, int32_t defaultOffset);
134 void add(int32_t key, int32_t offset)
135 {
136 if (!branchOffsets[key])
137 branchOffsets[key] = offset;
138 }
139
140#if ENABLE(CTI)
141 inline void* ctiForValue(int32_t value)
142 {
143 if (value >= min && static_cast<uint32_t>(value - min) < ctiOffsets.size())
144 return ctiOffsets[value - min];
145 return ctiDefault;
146 }
147#endif
148 };
149
150 class EvalCodeCache {
151 public:
152 PassRefPtr<EvalNode> get(ExecState* exec, const UString& evalSource, ScopeChainNode* scopeChain, JSValue*& exceptionValue)
153 {
154 RefPtr<EvalNode> evalNode;
155
156 if (evalSource.size() < maxCacheableSourceLength && (*scopeChain->begin())->isVariableObject())
157 evalNode = cacheMap.get(evalSource.rep());
158
159 if (!evalNode) {
160 int errLine;
161 UString errMsg;
162
163 SourceCode source = makeSource(evalSource);
164 evalNode = exec->parser()->parse<EvalNode>(exec, source, &errLine, &errMsg);
165 if (evalNode) {
166 if (evalSource.size() < maxCacheableSourceLength && (*scopeChain->begin())->isVariableObject() && cacheMap.size() < maxCacheEntries)
167 cacheMap.set(evalSource.rep(), evalNode);
168 } else {
169 exceptionValue = Error::create(exec, SyntaxError, errMsg, errLine, source.provider()->asID(), NULL);
170 return 0;
171 }
172 }
173
174 return evalNode.release();
175 }
176
177 private:
178 static const int maxCacheableSourceLength = 256;
179 static const int maxCacheEntries = 64;
180
181 HashMap<RefPtr<UString::Rep>, RefPtr<EvalNode> > cacheMap;
182 };
183
184 struct CodeBlock {
185 CodeBlock(ScopeNode* ownerNode_, CodeType codeType_, PassRefPtr<SourceProvider> source_, unsigned sourceOffset_)
186 : ownerNode(ownerNode_)
187 , globalData(0)
188#if ENABLE(CTI)
189 , ctiCode(0)
190#endif
191 , numCalleeRegisters(0)
192 , numConstants(0)
193 , numVars(0)
194 , numParameters(0)
195 , needsFullScopeChain(ownerNode_->needsActivation())
196 , usesEval(ownerNode_->usesEval())
197 , codeType(codeType_)
198 , source(source_)
199 , sourceOffset(sourceOffset_)
200 {
201 ASSERT(source);
202 }
203
204 ~CodeBlock();
205
206#if !defined(NDEBUG) || ENABLE_SAMPLING_TOOL
207 void dump(ExecState*) const;
208 void printStructureIDs(const Instruction*) const;
209 void printStructureID(const char* name, const Instruction*, int operand) const;
210#endif
211 int expressionRangeForVPC(const Instruction*, int& divot, int& startOffset, int& endOffset);
212 int lineNumberForVPC(const Instruction* vPC);
213 bool getHandlerForVPC(const Instruction* vPC, Instruction*& target, int& scopeDepth);
214 void* nativeExceptionCodeForHandlerVPC(const Instruction* handlerVPC);
215
216 void mark();
217 void refStructureIDs(Instruction* vPC) const;
218 void derefStructureIDs(Instruction* vPC) const;
219
220 StructureStubInfo& getStubInfo(void* returnAddress)
221 {
222 // FIXME: would a binary chop be faster here?
223 for (unsigned i = 0; ; ++i) {
224 if (structureIDInstructions[i].callReturnLocation == returnAddress)
225 return structureIDInstructions[i];
226 }
227 }
228
229 ScopeNode* ownerNode;
230 JSGlobalData* globalData;
231#if ENABLE(CTI)
232 void* ctiCode;
233#endif
234
235 int numCalleeRegisters;
236
237 // NOTE: numConstants holds the number of constant registers allocated
238 // by the code generator, not the number of constant registers used.
239 // (Duplicate constants are uniqued during code generation, and spare
240 // constant registers may be allocated.)
241 int numConstants;
242 int numVars;
243 int numParameters;
244 int thisRegister;
245 bool needsFullScopeChain;
246 bool usesEval;
247 bool usesArguments;
248 CodeType codeType;
249 RefPtr<SourceProvider> source;
250 unsigned sourceOffset;
251
252 Vector<Instruction> instructions;
253 Vector<StructureStubInfo> structureIDInstructions;
254
255 // Constant pool
256 Vector<Identifier> identifiers;
257 Vector<RefPtr<FuncDeclNode> > functions;
258 Vector<RefPtr<FuncExprNode> > functionExpressions;
259 Vector<Register> constantRegisters;
260 Vector<JSValue*> unexpectedConstants;
261 Vector<RefPtr<RegExp> > regexps;
262 Vector<HandlerInfo> exceptionHandlers;
263 Vector<ExpressionRangeInfo> expressionInfo;
264 Vector<LineInfo> lineInfo;
265
266 Vector<SimpleJumpTable> immediateSwitchJumpTables;
267 Vector<SimpleJumpTable> characterSwitchJumpTables;
268 Vector<StringJumpTable> stringSwitchJumpTables;
269
270 HashSet<unsigned, DefaultHash<unsigned>::Hash, WTF::UnsignedWithZeroKeyHashTraits<unsigned> > labels;
271
272#if ENABLE(CTI)
273 HashMap<void*, unsigned> ctiReturnAddressVPCMap;
274#endif
275
276 EvalCodeCache evalCodeCache;
277
278 private:
279#if !defined(NDEBUG) || ENABLE(SAMPLING_TOOL)
280 void dump(ExecState*, const Vector<Instruction>::const_iterator& begin, Vector<Instruction>::const_iterator&) const;
281#endif
282
283 };
284
285 // Program code is not marked by any function, so we make the global object
286 // responsible for marking it.
287
288 struct ProgramCodeBlock : public CodeBlock {
289 ProgramCodeBlock(ScopeNode* ownerNode_, CodeType codeType_, JSGlobalObject* globalObject_, PassRefPtr<SourceProvider> source_)
290 : CodeBlock(ownerNode_, codeType_, source_, 0)
291 , globalObject(globalObject_)
292 {
293 globalObject->codeBlocks().add(this);
294 }
295
296 ~ProgramCodeBlock()
297 {
298 if (globalObject)
299 globalObject->codeBlocks().remove(this);
300 }
301
302 JSGlobalObject* globalObject; // For program and eval nodes, the global object that marks the constant pool.
303 };
304
305 struct EvalCodeBlock : public ProgramCodeBlock {
306 EvalCodeBlock(ScopeNode* ownerNode_, JSGlobalObject* globalObject_, PassRefPtr<SourceProvider> source_)
307 : ProgramCodeBlock(ownerNode_, EvalCode, globalObject_, source_)
308 {
309 }
310 };
311
312} // namespace JSC
313
314#endif // CodeBlock_h
Note: See TracBrowser for help on using the repository browser.