author | Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com> |
Tue, 06 Jul 2010 15:10:48 +0300 | |
changeset 30 | 5dc02b23752f |
parent 0 | 1918ee327afb |
permissions | -rw-r--r-- |
0 | 1 |
/* |
2 |
* Copyright (C) 2008, 2009 Apple Inc. All rights reserved. |
|
3 |
* Copyright (C) 2008 Cameron Zwarich <cwzwarich@uwaterloo.ca> |
|
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 "EvalCodeCache.h" |
|
34 |
#include "Instruction.h" |
|
35 |
#include "JITCode.h" |
|
36 |
#include "JSGlobalObject.h" |
|
37 |
#include "JumpTable.h" |
|
38 |
#include "Nodes.h" |
|
39 |
#include "RegExp.h" |
|
40 |
#include "UString.h" |
|
41 |
#include <wtf/FastAllocBase.h> |
|
42 |
#include <wtf/RefPtr.h> |
|
43 |
#include <wtf/Vector.h> |
|
44 |
||
45 |
#if ENABLE(JIT) |
|
46 |
#include "StructureStubInfo.h" |
|
47 |
#endif |
|
48 |
||
49 |
// Register numbers used in bytecode operations have different meaning accoring to their ranges: |
|
50 |
// 0x80000000-0xFFFFFFFF Negative indicies from the CallFrame pointer are entries in the call frame, see RegisterFile.h. |
|
51 |
// 0x00000000-0x3FFFFFFF Forwards indices from the CallFrame pointer are local vars and temporaries with the function's callframe. |
|
52 |
// 0x40000000-0x7FFFFFFF Positive indices from 0x40000000 specify entries in the constant pool on the CodeBlock. |
|
53 |
static const int FirstConstantRegisterIndex = 0x40000000; |
|
54 |
||
55 |
namespace JSC { |
|
56 |
||
57 |
enum HasSeenShouldRepatch { |
|
58 |
hasSeenShouldRepatch |
|
59 |
}; |
|
60 |
||
61 |
class ExecState; |
|
62 |
||
63 |
enum CodeType { GlobalCode, EvalCode, FunctionCode }; |
|
64 |
||
65 |
static ALWAYS_INLINE int missingThisObjectMarker() { return std::numeric_limits<int>::max(); } |
|
66 |
||
67 |
struct HandlerInfo { |
|
68 |
uint32_t start; |
|
69 |
uint32_t end; |
|
70 |
uint32_t target; |
|
71 |
uint32_t scopeDepth; |
|
72 |
#if ENABLE(JIT) |
|
73 |
CodeLocationLabel nativeCode; |
|
74 |
#endif |
|
75 |
}; |
|
76 |
||
77 |
struct ExpressionRangeInfo { |
|
78 |
enum { |
|
79 |
MaxOffset = (1 << 7) - 1, |
|
80 |
MaxDivot = (1 << 25) - 1 |
|
81 |
}; |
|
82 |
uint32_t instructionOffset : 25; |
|
83 |
uint32_t divotPoint : 25; |
|
84 |
uint32_t startOffset : 7; |
|
85 |
uint32_t endOffset : 7; |
|
86 |
}; |
|
87 |
||
88 |
struct LineInfo { |
|
89 |
uint32_t instructionOffset; |
|
90 |
int32_t lineNumber; |
|
91 |
}; |
|
92 |
||
93 |
// Both op_construct and op_instanceof require a use of op_get_by_id to get |
|
94 |
// the prototype property from an object. The exception messages for exceptions |
|
95 |
// thrown by these instances op_get_by_id need to reflect this. |
|
96 |
struct GetByIdExceptionInfo { |
|
97 |
unsigned bytecodeOffset : 31; |
|
98 |
bool isOpConstruct : 1; |
|
99 |
}; |
|
100 |
||
101 |
#if ENABLE(JIT) |
|
102 |
struct CallLinkInfo { |
|
103 |
CallLinkInfo() |
|
104 |
: callee(0) |
|
105 |
{ |
|
106 |
} |
|
107 |
||
108 |
unsigned bytecodeIndex; |
|
109 |
CodeLocationNearCall callReturnLocation; |
|
110 |
CodeLocationDataLabelPtr hotPathBegin; |
|
111 |
CodeLocationNearCall hotPathOther; |
|
30
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
112 |
CodeBlock* ownerCodeBlock; |
0 | 113 |
CodeBlock* callee; |
30
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
114 |
unsigned position : 31; |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
115 |
unsigned hasSeenShouldRepatch : 1; |
0 | 116 |
|
117 |
void setUnlinked() { callee = 0; } |
|
118 |
bool isLinked() { return callee; } |
|
119 |
||
120 |
bool seenOnce() |
|
121 |
{ |
|
30
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
122 |
return hasSeenShouldRepatch; |
0 | 123 |
} |
124 |
||
125 |
void setSeen() |
|
126 |
{ |
|
30
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
127 |
hasSeenShouldRepatch = true; |
0 | 128 |
} |
129 |
}; |
|
130 |
||
131 |
struct MethodCallLinkInfo { |
|
132 |
MethodCallLinkInfo() |
|
133 |
: cachedStructure(0) |
|
30
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
134 |
, cachedPrototypeStructure(0) |
0 | 135 |
{ |
136 |
} |
|
137 |
||
138 |
bool seenOnce() |
|
139 |
{ |
|
30
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
140 |
ASSERT(!cachedStructure); |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
141 |
return cachedPrototypeStructure; |
0 | 142 |
} |
143 |
||
144 |
void setSeen() |
|
145 |
{ |
|
30
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
146 |
ASSERT(!cachedStructure && !cachedPrototypeStructure); |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
147 |
// We use the values of cachedStructure & cachedPrototypeStructure to indicate the |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
148 |
// current state. |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
149 |
// - In the initial state, both are null. |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
150 |
// - Once this transition has been taken once, cachedStructure is |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
151 |
// null and cachedPrototypeStructure is set to a nun-null value. |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
152 |
// - Once the call is linked both structures are set to non-null values. |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
153 |
cachedPrototypeStructure = (Structure*)1; |
0 | 154 |
} |
155 |
||
156 |
CodeLocationCall callReturnLocation; |
|
157 |
CodeLocationDataLabelPtr structureLabel; |
|
158 |
Structure* cachedStructure; |
|
30
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
159 |
Structure* cachedPrototypeStructure; |
0 | 160 |
}; |
161 |
||
162 |
struct FunctionRegisterInfo { |
|
163 |
FunctionRegisterInfo(unsigned bytecodeOffset, int functionRegisterIndex) |
|
164 |
: bytecodeOffset(bytecodeOffset) |
|
165 |
, functionRegisterIndex(functionRegisterIndex) |
|
166 |
{ |
|
167 |
} |
|
168 |
||
169 |
unsigned bytecodeOffset; |
|
170 |
int functionRegisterIndex; |
|
171 |
}; |
|
172 |
||
173 |
struct GlobalResolveInfo { |
|
174 |
GlobalResolveInfo(unsigned bytecodeOffset) |
|
175 |
: structure(0) |
|
176 |
, offset(0) |
|
177 |
, bytecodeOffset(bytecodeOffset) |
|
178 |
{ |
|
179 |
} |
|
180 |
||
181 |
Structure* structure; |
|
182 |
unsigned offset; |
|
183 |
unsigned bytecodeOffset; |
|
184 |
}; |
|
185 |
||
186 |
// This structure is used to map from a call return location |
|
187 |
// (given as an offset in bytes into the JIT code) back to |
|
188 |
// the bytecode index of the corresponding bytecode operation. |
|
189 |
// This is then used to look up the corresponding handler. |
|
190 |
struct CallReturnOffsetToBytecodeIndex { |
|
191 |
CallReturnOffsetToBytecodeIndex(unsigned callReturnOffset, unsigned bytecodeIndex) |
|
192 |
: callReturnOffset(callReturnOffset) |
|
193 |
, bytecodeIndex(bytecodeIndex) |
|
194 |
{ |
|
195 |
} |
|
196 |
||
197 |
unsigned callReturnOffset; |
|
198 |
unsigned bytecodeIndex; |
|
199 |
}; |
|
200 |
||
201 |
// valueAtPosition helpers for the binaryChop algorithm below. |
|
202 |
||
203 |
inline void* getStructureStubInfoReturnLocation(StructureStubInfo* structureStubInfo) |
|
204 |
{ |
|
205 |
return structureStubInfo->callReturnLocation.executableAddress(); |
|
206 |
} |
|
207 |
||
208 |
inline void* getCallLinkInfoReturnLocation(CallLinkInfo* callLinkInfo) |
|
209 |
{ |
|
210 |
return callLinkInfo->callReturnLocation.executableAddress(); |
|
211 |
} |
|
212 |
||
213 |
inline void* getMethodCallLinkInfoReturnLocation(MethodCallLinkInfo* methodCallLinkInfo) |
|
214 |
{ |
|
215 |
return methodCallLinkInfo->callReturnLocation.executableAddress(); |
|
216 |
} |
|
217 |
||
218 |
inline unsigned getCallReturnOffset(CallReturnOffsetToBytecodeIndex* pc) |
|
219 |
{ |
|
220 |
return pc->callReturnOffset; |
|
221 |
} |
|
222 |
||
223 |
// Binary chop algorithm, calls valueAtPosition on pre-sorted elements in array, |
|
224 |
// compares result with key (KeyTypes should be comparable with '--', '<', '>'). |
|
225 |
// Optimized for cases where the array contains the key, checked by assertions. |
|
226 |
template<typename ArrayType, typename KeyType, KeyType(*valueAtPosition)(ArrayType*)> |
|
227 |
inline ArrayType* binaryChop(ArrayType* array, size_t size, KeyType key) |
|
228 |
{ |
|
229 |
// The array must contain at least one element (pre-condition, array does conatin key). |
|
230 |
// If the array only contains one element, no need to do the comparison. |
|
231 |
while (size > 1) { |
|
232 |
// Pick an element to check, half way through the array, and read the value. |
|
233 |
int pos = (size - 1) >> 1; |
|
234 |
KeyType val = valueAtPosition(&array[pos]); |
|
235 |
||
236 |
// If the key matches, success! |
|
237 |
if (val == key) |
|
238 |
return &array[pos]; |
|
239 |
// The item we are looking for is smaller than the item being check; reduce the value of 'size', |
|
240 |
// chopping off the right hand half of the array. |
|
241 |
else if (key < val) |
|
242 |
size = pos; |
|
243 |
// Discard all values in the left hand half of the array, up to and including the item at pos. |
|
244 |
else { |
|
245 |
size -= (pos + 1); |
|
246 |
array += (pos + 1); |
|
247 |
} |
|
248 |
||
249 |
// 'size' should never reach zero. |
|
250 |
ASSERT(size); |
|
251 |
} |
|
252 |
||
253 |
// If we reach this point we've chopped down to one element, no need to check it matches |
|
254 |
ASSERT(size == 1); |
|
255 |
ASSERT(key == valueAtPosition(&array[0])); |
|
256 |
return &array[0]; |
|
257 |
} |
|
258 |
#endif |
|
259 |
||
260 |
struct ExceptionInfo : FastAllocBase { |
|
261 |
Vector<ExpressionRangeInfo> m_expressionInfo; |
|
262 |
Vector<LineInfo> m_lineInfo; |
|
263 |
Vector<GetByIdExceptionInfo> m_getByIdExceptionInfo; |
|
264 |
||
265 |
#if ENABLE(JIT) |
|
266 |
Vector<CallReturnOffsetToBytecodeIndex> m_callReturnIndexVector; |
|
267 |
#endif |
|
268 |
}; |
|
269 |
||
270 |
class CodeBlock : public FastAllocBase { |
|
271 |
friend class JIT; |
|
272 |
protected: |
|
273 |
CodeBlock(ScriptExecutable* ownerExecutable, CodeType, PassRefPtr<SourceProvider>, unsigned sourceOffset, SymbolTable* symbolTable); |
|
274 |
public: |
|
275 |
virtual ~CodeBlock(); |
|
276 |
||
277 |
void markAggregate(MarkStack&); |
|
278 |
void refStructures(Instruction* vPC) const; |
|
279 |
void derefStructures(Instruction* vPC) const; |
|
280 |
#if ENABLE(JIT_OPTIMIZE_CALL) |
|
281 |
void unlinkCallers(); |
|
282 |
#endif |
|
283 |
||
284 |
static void dumpStatistics(); |
|
285 |
||
286 |
#if !defined(NDEBUG) || ENABLE_OPCODE_SAMPLING |
|
287 |
void dump(ExecState*) const; |
|
288 |
void printStructures(const Instruction*) const; |
|
289 |
void printStructure(const char* name, const Instruction*, int operand) const; |
|
290 |
#endif |
|
291 |
||
292 |
inline bool isKnownNotImmediate(int index) |
|
293 |
{ |
|
294 |
if (index == m_thisRegister) |
|
295 |
return true; |
|
296 |
||
297 |
if (isConstantRegisterIndex(index)) |
|
298 |
return getConstant(index).isCell(); |
|
299 |
||
300 |
return false; |
|
301 |
} |
|
302 |
||
303 |
ALWAYS_INLINE bool isTemporaryRegisterIndex(int index) |
|
304 |
{ |
|
305 |
return index >= m_numVars; |
|
306 |
} |
|
307 |
||
308 |
HandlerInfo* handlerForBytecodeOffset(unsigned bytecodeOffset); |
|
309 |
int lineNumberForBytecodeOffset(CallFrame*, unsigned bytecodeOffset); |
|
310 |
int expressionRangeForBytecodeOffset(CallFrame*, unsigned bytecodeOffset, int& divot, int& startOffset, int& endOffset); |
|
311 |
bool getByIdExceptionInfoForBytecodeOffset(CallFrame*, unsigned bytecodeOffset, OpcodeID&); |
|
312 |
||
313 |
#if ENABLE(JIT) |
|
314 |
void addCaller(CallLinkInfo* caller) |
|
315 |
{ |
|
316 |
caller->callee = this; |
|
317 |
caller->position = m_linkedCallerList.size(); |
|
318 |
m_linkedCallerList.append(caller); |
|
319 |
} |
|
320 |
||
321 |
void removeCaller(CallLinkInfo* caller) |
|
322 |
{ |
|
323 |
unsigned pos = caller->position; |
|
324 |
unsigned lastPos = m_linkedCallerList.size() - 1; |
|
325 |
||
326 |
if (pos != lastPos) { |
|
327 |
m_linkedCallerList[pos] = m_linkedCallerList[lastPos]; |
|
328 |
m_linkedCallerList[pos]->position = pos; |
|
329 |
} |
|
330 |
m_linkedCallerList.shrink(lastPos); |
|
331 |
} |
|
332 |
||
333 |
StructureStubInfo& getStubInfo(ReturnAddressPtr returnAddress) |
|
334 |
{ |
|
335 |
return *(binaryChop<StructureStubInfo, void*, getStructureStubInfoReturnLocation>(m_structureStubInfos.begin(), m_structureStubInfos.size(), returnAddress.value())); |
|
336 |
} |
|
337 |
||
338 |
CallLinkInfo& getCallLinkInfo(ReturnAddressPtr returnAddress) |
|
339 |
{ |
|
340 |
return *(binaryChop<CallLinkInfo, void*, getCallLinkInfoReturnLocation>(m_callLinkInfos.begin(), m_callLinkInfos.size(), returnAddress.value())); |
|
341 |
} |
|
342 |
||
343 |
MethodCallLinkInfo& getMethodCallLinkInfo(ReturnAddressPtr returnAddress) |
|
344 |
{ |
|
345 |
return *(binaryChop<MethodCallLinkInfo, void*, getMethodCallLinkInfoReturnLocation>(m_methodCallLinkInfos.begin(), m_methodCallLinkInfos.size(), returnAddress.value())); |
|
346 |
} |
|
347 |
||
348 |
unsigned getBytecodeIndex(CallFrame* callFrame, ReturnAddressPtr returnAddress) |
|
349 |
{ |
|
350 |
reparseForExceptionInfoIfNecessary(callFrame); |
|
351 |
return binaryChop<CallReturnOffsetToBytecodeIndex, unsigned, getCallReturnOffset>(callReturnIndexVector().begin(), callReturnIndexVector().size(), ownerExecutable()->generatedJITCode().offsetOf(returnAddress.value()))->bytecodeIndex; |
|
352 |
} |
|
353 |
||
354 |
bool functionRegisterForBytecodeOffset(unsigned bytecodeOffset, int& functionRegisterIndex); |
|
355 |
#endif |
|
356 |
||
357 |
void setIsNumericCompareFunction(bool isNumericCompareFunction) { m_isNumericCompareFunction = isNumericCompareFunction; } |
|
358 |
bool isNumericCompareFunction() { return m_isNumericCompareFunction; } |
|
359 |
||
360 |
Vector<Instruction>& instructions() { return m_instructions; } |
|
361 |
void discardBytecode() { m_instructions.clear(); } |
|
362 |
||
363 |
#ifndef NDEBUG |
|
364 |
unsigned instructionCount() { return m_instructionCount; } |
|
365 |
void setInstructionCount(unsigned instructionCount) { m_instructionCount = instructionCount; } |
|
366 |
#endif |
|
367 |
||
368 |
#if ENABLE(JIT) |
|
369 |
JITCode& getJITCode() { return ownerExecutable()->generatedJITCode(); } |
|
370 |
ExecutablePool* executablePool() { return ownerExecutable()->getExecutablePool(); } |
|
371 |
#endif |
|
372 |
||
373 |
ScriptExecutable* ownerExecutable() const { return m_ownerExecutable; } |
|
374 |
||
375 |
void setGlobalData(JSGlobalData* globalData) { m_globalData = globalData; } |
|
376 |
||
377 |
void setThisRegister(int thisRegister) { m_thisRegister = thisRegister; } |
|
378 |
int thisRegister() const { return m_thisRegister; } |
|
379 |
||
380 |
void setNeedsFullScopeChain(bool needsFullScopeChain) { m_needsFullScopeChain = needsFullScopeChain; } |
|
381 |
bool needsFullScopeChain() const { return m_needsFullScopeChain; } |
|
382 |
void setUsesEval(bool usesEval) { m_usesEval = usesEval; } |
|
383 |
bool usesEval() const { return m_usesEval; } |
|
384 |
void setUsesArguments(bool usesArguments) { m_usesArguments = usesArguments; } |
|
385 |
bool usesArguments() const { return m_usesArguments; } |
|
386 |
||
387 |
CodeType codeType() const { return m_codeType; } |
|
388 |
||
389 |
SourceProvider* source() const { return m_source.get(); } |
|
390 |
unsigned sourceOffset() const { return m_sourceOffset; } |
|
391 |
||
392 |
size_t numberOfJumpTargets() const { return m_jumpTargets.size(); } |
|
393 |
void addJumpTarget(unsigned jumpTarget) { m_jumpTargets.append(jumpTarget); } |
|
394 |
unsigned jumpTarget(int index) const { return m_jumpTargets[index]; } |
|
395 |
unsigned lastJumpTarget() const { return m_jumpTargets.last(); } |
|
396 |
||
397 |
#if !ENABLE(JIT) |
|
398 |
void addPropertyAccessInstruction(unsigned propertyAccessInstruction) { m_propertyAccessInstructions.append(propertyAccessInstruction); } |
|
399 |
void addGlobalResolveInstruction(unsigned globalResolveInstruction) { m_globalResolveInstructions.append(globalResolveInstruction); } |
|
400 |
bool hasGlobalResolveInstructionAtBytecodeOffset(unsigned bytecodeOffset); |
|
401 |
#else |
|
402 |
size_t numberOfStructureStubInfos() const { return m_structureStubInfos.size(); } |
|
403 |
void addStructureStubInfo(const StructureStubInfo& stubInfo) { m_structureStubInfos.append(stubInfo); } |
|
404 |
StructureStubInfo& structureStubInfo(int index) { return m_structureStubInfos[index]; } |
|
405 |
||
406 |
void addGlobalResolveInfo(unsigned globalResolveInstruction) { m_globalResolveInfos.append(GlobalResolveInfo(globalResolveInstruction)); } |
|
407 |
GlobalResolveInfo& globalResolveInfo(int index) { return m_globalResolveInfos[index]; } |
|
408 |
bool hasGlobalResolveInfoAtBytecodeOffset(unsigned bytecodeOffset); |
|
409 |
||
410 |
size_t numberOfCallLinkInfos() const { return m_callLinkInfos.size(); } |
|
411 |
void addCallLinkInfo() { m_callLinkInfos.append(CallLinkInfo()); } |
|
412 |
CallLinkInfo& callLinkInfo(int index) { return m_callLinkInfos[index]; } |
|
413 |
||
414 |
void addMethodCallLinkInfos(unsigned n) { m_methodCallLinkInfos.grow(n); } |
|
415 |
MethodCallLinkInfo& methodCallLinkInfo(int index) { return m_methodCallLinkInfos[index]; } |
|
416 |
||
417 |
void addFunctionRegisterInfo(unsigned bytecodeOffset, int functionIndex) { createRareDataIfNecessary(); m_rareData->m_functionRegisterInfos.append(FunctionRegisterInfo(bytecodeOffset, functionIndex)); } |
|
418 |
#endif |
|
419 |
||
420 |
// Exception handling support |
|
421 |
||
422 |
size_t numberOfExceptionHandlers() const { return m_rareData ? m_rareData->m_exceptionHandlers.size() : 0; } |
|
423 |
void addExceptionHandler(const HandlerInfo& hanler) { createRareDataIfNecessary(); return m_rareData->m_exceptionHandlers.append(hanler); } |
|
424 |
HandlerInfo& exceptionHandler(int index) { ASSERT(m_rareData); return m_rareData->m_exceptionHandlers[index]; } |
|
425 |
||
426 |
bool hasExceptionInfo() const { return m_exceptionInfo; } |
|
427 |
void clearExceptionInfo() { m_exceptionInfo.clear(); } |
|
428 |
ExceptionInfo* extractExceptionInfo() { ASSERT(m_exceptionInfo); return m_exceptionInfo.release(); } |
|
429 |
||
430 |
void addExpressionInfo(const ExpressionRangeInfo& expressionInfo) { ASSERT(m_exceptionInfo); m_exceptionInfo->m_expressionInfo.append(expressionInfo); } |
|
431 |
void addGetByIdExceptionInfo(const GetByIdExceptionInfo& info) { ASSERT(m_exceptionInfo); m_exceptionInfo->m_getByIdExceptionInfo.append(info); } |
|
432 |
||
433 |
size_t numberOfLineInfos() const { ASSERT(m_exceptionInfo); return m_exceptionInfo->m_lineInfo.size(); } |
|
434 |
void addLineInfo(const LineInfo& lineInfo) { ASSERT(m_exceptionInfo); m_exceptionInfo->m_lineInfo.append(lineInfo); } |
|
435 |
LineInfo& lastLineInfo() { ASSERT(m_exceptionInfo); return m_exceptionInfo->m_lineInfo.last(); } |
|
436 |
||
437 |
#if ENABLE(JIT) |
|
438 |
Vector<CallReturnOffsetToBytecodeIndex>& callReturnIndexVector() { ASSERT(m_exceptionInfo); return m_exceptionInfo->m_callReturnIndexVector; } |
|
439 |
#endif |
|
440 |
||
441 |
// Constant Pool |
|
442 |
||
443 |
size_t numberOfIdentifiers() const { return m_identifiers.size(); } |
|
444 |
void addIdentifier(const Identifier& i) { return m_identifiers.append(i); } |
|
445 |
Identifier& identifier(int index) { return m_identifiers[index]; } |
|
446 |
||
447 |
size_t numberOfConstantRegisters() const { return m_constantRegisters.size(); } |
|
448 |
void addConstantRegister(const Register& r) { return m_constantRegisters.append(r); } |
|
449 |
Register& constantRegister(int index) { return m_constantRegisters[index - FirstConstantRegisterIndex]; } |
|
30
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
450 |
ALWAYS_INLINE bool isConstantRegisterIndex(int index) const { return index >= FirstConstantRegisterIndex; } |
0 | 451 |
ALWAYS_INLINE JSValue getConstant(int index) const { return m_constantRegisters[index - FirstConstantRegisterIndex].jsValue(); } |
452 |
||
453 |
unsigned addFunctionDecl(NonNullPassRefPtr<FunctionExecutable> n) { unsigned size = m_functionDecls.size(); m_functionDecls.append(n); return size; } |
|
454 |
FunctionExecutable* functionDecl(int index) { return m_functionDecls[index].get(); } |
|
455 |
int numberOfFunctionDecls() { return m_functionDecls.size(); } |
|
456 |
unsigned addFunctionExpr(NonNullPassRefPtr<FunctionExecutable> n) { unsigned size = m_functionExprs.size(); m_functionExprs.append(n); return size; } |
|
457 |
FunctionExecutable* functionExpr(int index) { return m_functionExprs[index].get(); } |
|
458 |
||
459 |
unsigned addRegExp(RegExp* r) { createRareDataIfNecessary(); unsigned size = m_rareData->m_regexps.size(); m_rareData->m_regexps.append(r); return size; } |
|
460 |
RegExp* regexp(int index) const { ASSERT(m_rareData); return m_rareData->m_regexps[index].get(); } |
|
461 |
||
462 |
||
463 |
// Jump Tables |
|
464 |
||
465 |
size_t numberOfImmediateSwitchJumpTables() const { return m_rareData ? m_rareData->m_immediateSwitchJumpTables.size() : 0; } |
|
466 |
SimpleJumpTable& addImmediateSwitchJumpTable() { createRareDataIfNecessary(); m_rareData->m_immediateSwitchJumpTables.append(SimpleJumpTable()); return m_rareData->m_immediateSwitchJumpTables.last(); } |
|
467 |
SimpleJumpTable& immediateSwitchJumpTable(int tableIndex) { ASSERT(m_rareData); return m_rareData->m_immediateSwitchJumpTables[tableIndex]; } |
|
468 |
||
469 |
size_t numberOfCharacterSwitchJumpTables() const { return m_rareData ? m_rareData->m_characterSwitchJumpTables.size() : 0; } |
|
470 |
SimpleJumpTable& addCharacterSwitchJumpTable() { createRareDataIfNecessary(); m_rareData->m_characterSwitchJumpTables.append(SimpleJumpTable()); return m_rareData->m_characterSwitchJumpTables.last(); } |
|
471 |
SimpleJumpTable& characterSwitchJumpTable(int tableIndex) { ASSERT(m_rareData); return m_rareData->m_characterSwitchJumpTables[tableIndex]; } |
|
472 |
||
473 |
size_t numberOfStringSwitchJumpTables() const { return m_rareData ? m_rareData->m_stringSwitchJumpTables.size() : 0; } |
|
474 |
StringJumpTable& addStringSwitchJumpTable() { createRareDataIfNecessary(); m_rareData->m_stringSwitchJumpTables.append(StringJumpTable()); return m_rareData->m_stringSwitchJumpTables.last(); } |
|
475 |
StringJumpTable& stringSwitchJumpTable(int tableIndex) { ASSERT(m_rareData); return m_rareData->m_stringSwitchJumpTables[tableIndex]; } |
|
476 |
||
477 |
||
478 |
SymbolTable* symbolTable() { return m_symbolTable; } |
|
479 |
SharedSymbolTable* sharedSymbolTable() { ASSERT(m_codeType == FunctionCode); return static_cast<SharedSymbolTable*>(m_symbolTable); } |
|
480 |
||
481 |
EvalCodeCache& evalCodeCache() { createRareDataIfNecessary(); return m_rareData->m_evalCodeCache; } |
|
482 |
||
483 |
void shrinkToFit(); |
|
484 |
||
485 |
// FIXME: Make these remaining members private. |
|
486 |
||
487 |
int m_numCalleeRegisters; |
|
488 |
int m_numVars; |
|
489 |
int m_numParameters; |
|
490 |
||
491 |
private: |
|
492 |
#if !defined(NDEBUG) || ENABLE(OPCODE_SAMPLING) |
|
493 |
void dump(ExecState*, const Vector<Instruction>::const_iterator& begin, Vector<Instruction>::const_iterator&) const; |
|
30
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
494 |
|
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
495 |
CString registerName(ExecState*, int r) const; |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
496 |
void printUnaryOp(ExecState*, int location, Vector<Instruction>::const_iterator&, const char* op) const; |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
497 |
void printBinaryOp(ExecState*, int location, Vector<Instruction>::const_iterator&, const char* op) const; |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
498 |
void printConditionalJump(ExecState*, const Vector<Instruction>::const_iterator&, Vector<Instruction>::const_iterator&, int location, const char* op) const; |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
499 |
void printGetByIdOp(ExecState*, int location, Vector<Instruction>::const_iterator&, const char* op) const; |
5dc02b23752f
Revision: 201025
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
500 |
void printPutByIdOp(ExecState*, int location, Vector<Instruction>::const_iterator&, const char* op) const; |
0 | 501 |
#endif |
502 |
||
503 |
void reparseForExceptionInfoIfNecessary(CallFrame*); |
|
504 |
||
505 |
void createRareDataIfNecessary() |
|
506 |
{ |
|
507 |
if (!m_rareData) |
|
508 |
m_rareData.set(new RareData); |
|
509 |
} |
|
510 |
||
511 |
ScriptExecutable* m_ownerExecutable; |
|
512 |
JSGlobalData* m_globalData; |
|
513 |
||
514 |
Vector<Instruction> m_instructions; |
|
515 |
#ifndef NDEBUG |
|
516 |
unsigned m_instructionCount; |
|
517 |
#endif |
|
518 |
||
519 |
int m_thisRegister; |
|
520 |
||
521 |
bool m_needsFullScopeChain; |
|
522 |
bool m_usesEval; |
|
523 |
bool m_usesArguments; |
|
524 |
bool m_isNumericCompareFunction; |
|
525 |
||
526 |
CodeType m_codeType; |
|
527 |
||
528 |
RefPtr<SourceProvider> m_source; |
|
529 |
unsigned m_sourceOffset; |
|
530 |
||
531 |
#if !ENABLE(JIT) |
|
532 |
Vector<unsigned> m_propertyAccessInstructions; |
|
533 |
Vector<unsigned> m_globalResolveInstructions; |
|
534 |
#else |
|
535 |
Vector<StructureStubInfo> m_structureStubInfos; |
|
536 |
Vector<GlobalResolveInfo> m_globalResolveInfos; |
|
537 |
Vector<CallLinkInfo> m_callLinkInfos; |
|
538 |
Vector<MethodCallLinkInfo> m_methodCallLinkInfos; |
|
539 |
Vector<CallLinkInfo*> m_linkedCallerList; |
|
540 |
#endif |
|
541 |
||
542 |
Vector<unsigned> m_jumpTargets; |
|
543 |
||
544 |
// Constant Pool |
|
545 |
Vector<Identifier> m_identifiers; |
|
546 |
Vector<Register> m_constantRegisters; |
|
547 |
Vector<RefPtr<FunctionExecutable> > m_functionDecls; |
|
548 |
Vector<RefPtr<FunctionExecutable> > m_functionExprs; |
|
549 |
||
550 |
SymbolTable* m_symbolTable; |
|
551 |
||
552 |
OwnPtr<ExceptionInfo> m_exceptionInfo; |
|
553 |
||
554 |
struct RareData : FastAllocBase { |
|
555 |
Vector<HandlerInfo> m_exceptionHandlers; |
|
556 |
||
557 |
// Rare Constants |
|
558 |
Vector<RefPtr<RegExp> > m_regexps; |
|
559 |
||
560 |
// Jump Tables |
|
561 |
Vector<SimpleJumpTable> m_immediateSwitchJumpTables; |
|
562 |
Vector<SimpleJumpTable> m_characterSwitchJumpTables; |
|
563 |
Vector<StringJumpTable> m_stringSwitchJumpTables; |
|
564 |
||
565 |
EvalCodeCache m_evalCodeCache; |
|
566 |
||
567 |
#if ENABLE(JIT) |
|
568 |
Vector<FunctionRegisterInfo> m_functionRegisterInfos; |
|
569 |
#endif |
|
570 |
}; |
|
571 |
OwnPtr<RareData> m_rareData; |
|
572 |
}; |
|
573 |
||
574 |
// Program code is not marked by any function, so we make the global object |
|
575 |
// responsible for marking it. |
|
576 |
||
577 |
class GlobalCodeBlock : public CodeBlock { |
|
578 |
public: |
|
579 |
GlobalCodeBlock(ScriptExecutable* ownerExecutable, CodeType codeType, PassRefPtr<SourceProvider> sourceProvider, unsigned sourceOffset, JSGlobalObject* globalObject) |
|
580 |
: CodeBlock(ownerExecutable, codeType, sourceProvider, sourceOffset, &m_unsharedSymbolTable) |
|
581 |
, m_globalObject(globalObject) |
|
582 |
{ |
|
583 |
m_globalObject->codeBlocks().add(this); |
|
584 |
} |
|
585 |
||
586 |
~GlobalCodeBlock() |
|
587 |
{ |
|
588 |
if (m_globalObject) |
|
589 |
m_globalObject->codeBlocks().remove(this); |
|
590 |
} |
|
591 |
||
592 |
void clearGlobalObject() { m_globalObject = 0; } |
|
593 |
||
594 |
private: |
|
595 |
JSGlobalObject* m_globalObject; // For program and eval nodes, the global object that marks the constant pool. |
|
596 |
SymbolTable m_unsharedSymbolTable; |
|
597 |
}; |
|
598 |
||
599 |
class ProgramCodeBlock : public GlobalCodeBlock { |
|
600 |
public: |
|
601 |
ProgramCodeBlock(ProgramExecutable* ownerExecutable, CodeType codeType, JSGlobalObject* globalObject, PassRefPtr<SourceProvider> sourceProvider) |
|
602 |
: GlobalCodeBlock(ownerExecutable, codeType, sourceProvider, 0, globalObject) |
|
603 |
{ |
|
604 |
} |
|
605 |
}; |
|
606 |
||
607 |
class EvalCodeBlock : public GlobalCodeBlock { |
|
608 |
public: |
|
609 |
EvalCodeBlock(EvalExecutable* ownerExecutable, JSGlobalObject* globalObject, PassRefPtr<SourceProvider> sourceProvider, int baseScopeDepth) |
|
610 |
: GlobalCodeBlock(ownerExecutable, EvalCode, sourceProvider, 0, globalObject) |
|
611 |
, m_baseScopeDepth(baseScopeDepth) |
|
612 |
{ |
|
613 |
} |
|
614 |
||
615 |
int baseScopeDepth() const { return m_baseScopeDepth; } |
|
616 |
||
617 |
const Identifier& variable(unsigned index) { return m_variables[index]; } |
|
618 |
unsigned numVariables() { return m_variables.size(); } |
|
619 |
void adoptVariables(Vector<Identifier>& variables) |
|
620 |
{ |
|
621 |
ASSERT(m_variables.isEmpty()); |
|
622 |
m_variables.swap(variables); |
|
623 |
} |
|
624 |
||
625 |
private: |
|
626 |
int m_baseScopeDepth; |
|
627 |
Vector<Identifier> m_variables; |
|
628 |
}; |
|
629 |
||
630 |
class FunctionCodeBlock : public CodeBlock { |
|
631 |
public: |
|
632 |
// Rather than using the usual RefCounted::create idiom for SharedSymbolTable we just use new |
|
633 |
// as we need to initialise the CodeBlock before we could initialise any RefPtr to hold the shared |
|
634 |
// symbol table, so we just pass as a raw pointer with a ref count of 1. We then manually deref |
|
635 |
// in the destructor. |
|
636 |
FunctionCodeBlock(FunctionExecutable* ownerExecutable, CodeType codeType, PassRefPtr<SourceProvider> sourceProvider, unsigned sourceOffset) |
|
637 |
: CodeBlock(ownerExecutable, codeType, sourceProvider, sourceOffset, new SharedSymbolTable) |
|
638 |
{ |
|
639 |
} |
|
640 |
~FunctionCodeBlock() |
|
641 |
{ |
|
642 |
sharedSymbolTable()->deref(); |
|
643 |
} |
|
644 |
}; |
|
645 |
||
646 |
inline Register& ExecState::r(int index) |
|
647 |
{ |
|
648 |
CodeBlock* codeBlock = this->codeBlock(); |
|
649 |
if (codeBlock->isConstantRegisterIndex(index)) |
|
650 |
return codeBlock->constantRegister(index); |
|
651 |
return this[index]; |
|
652 |
} |
|
653 |
||
654 |
} // namespace JSC |
|
655 |
||
656 |
#endif // CodeBlock_h |