]>
Commit | Line | Data |
---|---|---|
9dae56ea A |
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" | |
ba379fdc | 35 | #include "JITCode.h" |
9dae56ea A |
36 | #include "JSGlobalObject.h" |
37 | #include "JumpTable.h" | |
38 | #include "Nodes.h" | |
39 | #include "RegExp.h" | |
40 | #include "UString.h" | |
ba379fdc | 41 | #include <wtf/FastAllocBase.h> |
9dae56ea A |
42 | #include <wtf/RefPtr.h> |
43 | #include <wtf/Vector.h> | |
44 | ||
45 | #if ENABLE(JIT) | |
46 | #include "StructureStubInfo.h" | |
47 | #endif | |
48 | ||
ba379fdc A |
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 | ||
9dae56ea A |
55 | namespace JSC { |
56 | ||
57 | class ExecState; | |
58 | ||
ba379fdc | 59 | enum CodeType { GlobalCode, EvalCode, FunctionCode, NativeCode }; |
9dae56ea A |
60 | |
61 | static ALWAYS_INLINE int missingThisObjectMarker() { return std::numeric_limits<int>::max(); } | |
62 | ||
63 | struct HandlerInfo { | |
64 | uint32_t start; | |
65 | uint32_t end; | |
66 | uint32_t target; | |
67 | uint32_t scopeDepth; | |
68 | #if ENABLE(JIT) | |
ba379fdc | 69 | CodeLocationLabel nativeCode; |
9dae56ea A |
70 | #endif |
71 | }; | |
72 | ||
9dae56ea A |
73 | struct ExpressionRangeInfo { |
74 | enum { | |
75 | MaxOffset = (1 << 7) - 1, | |
76 | MaxDivot = (1 << 25) - 1 | |
77 | }; | |
78 | uint32_t instructionOffset : 25; | |
79 | uint32_t divotPoint : 25; | |
80 | uint32_t startOffset : 7; | |
81 | uint32_t endOffset : 7; | |
82 | }; | |
83 | ||
84 | struct LineInfo { | |
85 | uint32_t instructionOffset; | |
86 | int32_t lineNumber; | |
87 | }; | |
88 | ||
89 | // Both op_construct and op_instanceof require a use of op_get_by_id to get | |
90 | // the prototype property from an object. The exception messages for exceptions | |
91 | // thrown by these instances op_get_by_id need to reflect this. | |
92 | struct GetByIdExceptionInfo { | |
93 | unsigned bytecodeOffset : 31; | |
94 | bool isOpConstruct : 1; | |
95 | }; | |
96 | ||
97 | #if ENABLE(JIT) | |
98 | struct CallLinkInfo { | |
99 | CallLinkInfo() | |
ba379fdc | 100 | : callee(0) |
9dae56ea A |
101 | { |
102 | } | |
103 | ||
104 | unsigned bytecodeIndex; | |
ba379fdc A |
105 | CodeLocationNearCall callReturnLocation; |
106 | CodeLocationDataLabelPtr hotPathBegin; | |
107 | CodeLocationNearCall hotPathOther; | |
108 | CodeBlock* ownerCodeBlock; | |
9dae56ea A |
109 | CodeBlock* callee; |
110 | unsigned position; | |
111 | ||
112 | void setUnlinked() { callee = 0; } | |
113 | bool isLinked() { return callee; } | |
114 | }; | |
115 | ||
ba379fdc A |
116 | struct MethodCallLinkInfo { |
117 | MethodCallLinkInfo() | |
118 | : cachedStructure(0) | |
119 | , cachedPrototypeStructure(0) | |
120 | { | |
121 | } | |
122 | ||
123 | CodeLocationCall callReturnLocation; | |
124 | CodeLocationDataLabelPtr structureLabel; | |
125 | Structure* cachedStructure; | |
126 | Structure* cachedPrototypeStructure; | |
127 | }; | |
128 | ||
9dae56ea A |
129 | struct FunctionRegisterInfo { |
130 | FunctionRegisterInfo(unsigned bytecodeOffset, int functionRegisterIndex) | |
131 | : bytecodeOffset(bytecodeOffset) | |
132 | , functionRegisterIndex(functionRegisterIndex) | |
133 | { | |
134 | } | |
135 | ||
136 | unsigned bytecodeOffset; | |
137 | int functionRegisterIndex; | |
138 | }; | |
139 | ||
140 | struct GlobalResolveInfo { | |
141 | GlobalResolveInfo(unsigned bytecodeOffset) | |
142 | : structure(0) | |
143 | , offset(0) | |
144 | , bytecodeOffset(bytecodeOffset) | |
145 | { | |
146 | } | |
147 | ||
148 | Structure* structure; | |
149 | unsigned offset; | |
150 | unsigned bytecodeOffset; | |
151 | }; | |
152 | ||
ba379fdc A |
153 | // This structure is used to map from a call return location |
154 | // (given as an offset in bytes into the JIT code) back to | |
155 | // the bytecode index of the corresponding bytecode operation. | |
156 | // This is then used to look up the corresponding handler. | |
157 | struct CallReturnOffsetToBytecodeIndex { | |
158 | CallReturnOffsetToBytecodeIndex(unsigned callReturnOffset, unsigned bytecodeIndex) | |
159 | : callReturnOffset(callReturnOffset) | |
9dae56ea A |
160 | , bytecodeIndex(bytecodeIndex) |
161 | { | |
162 | } | |
163 | ||
ba379fdc | 164 | unsigned callReturnOffset; |
9dae56ea A |
165 | unsigned bytecodeIndex; |
166 | }; | |
167 | ||
168 | // valueAtPosition helpers for the binaryChop algorithm below. | |
169 | ||
170 | inline void* getStructureStubInfoReturnLocation(StructureStubInfo* structureStubInfo) | |
171 | { | |
ba379fdc | 172 | return structureStubInfo->callReturnLocation.executableAddress(); |
9dae56ea A |
173 | } |
174 | ||
175 | inline void* getCallLinkInfoReturnLocation(CallLinkInfo* callLinkInfo) | |
176 | { | |
ba379fdc A |
177 | return callLinkInfo->callReturnLocation.executableAddress(); |
178 | } | |
179 | ||
180 | inline void* getMethodCallLinkInfoReturnLocation(MethodCallLinkInfo* methodCallLinkInfo) | |
181 | { | |
182 | return methodCallLinkInfo->callReturnLocation.executableAddress(); | |
9dae56ea A |
183 | } |
184 | ||
ba379fdc | 185 | inline unsigned getCallReturnOffset(CallReturnOffsetToBytecodeIndex* pc) |
9dae56ea | 186 | { |
ba379fdc | 187 | return pc->callReturnOffset; |
9dae56ea A |
188 | } |
189 | ||
190 | // Binary chop algorithm, calls valueAtPosition on pre-sorted elements in array, | |
191 | // compares result with key (KeyTypes should be comparable with '--', '<', '>'). | |
192 | // Optimized for cases where the array contains the key, checked by assertions. | |
193 | template<typename ArrayType, typename KeyType, KeyType(*valueAtPosition)(ArrayType*)> | |
194 | inline ArrayType* binaryChop(ArrayType* array, size_t size, KeyType key) | |
195 | { | |
196 | // The array must contain at least one element (pre-condition, array does conatin key). | |
197 | // If the array only contains one element, no need to do the comparison. | |
198 | while (size > 1) { | |
199 | // Pick an element to check, half way through the array, and read the value. | |
200 | int pos = (size - 1) >> 1; | |
201 | KeyType val = valueAtPosition(&array[pos]); | |
202 | ||
203 | // If the key matches, success! | |
204 | if (val == key) | |
205 | return &array[pos]; | |
206 | // The item we are looking for is smaller than the item being check; reduce the value of 'size', | |
207 | // chopping off the right hand half of the array. | |
208 | else if (key < val) | |
209 | size = pos; | |
210 | // Discard all values in the left hand half of the array, up to and including the item at pos. | |
211 | else { | |
212 | size -= (pos + 1); | |
213 | array += (pos + 1); | |
214 | } | |
215 | ||
216 | // 'size' should never reach zero. | |
217 | ASSERT(size); | |
218 | } | |
219 | ||
220 | // If we reach this point we've chopped down to one element, no need to check it matches | |
221 | ASSERT(size == 1); | |
222 | ASSERT(key == valueAtPosition(&array[0])); | |
223 | return &array[0]; | |
224 | } | |
225 | #endif | |
226 | ||
ba379fdc | 227 | class CodeBlock : public WTF::FastAllocBase { |
9dae56ea A |
228 | friend class JIT; |
229 | public: | |
ba379fdc | 230 | CodeBlock(ScopeNode* ownerNode); |
9dae56ea A |
231 | CodeBlock(ScopeNode* ownerNode, CodeType, PassRefPtr<SourceProvider>, unsigned sourceOffset); |
232 | ~CodeBlock(); | |
233 | ||
234 | void mark(); | |
235 | void refStructures(Instruction* vPC) const; | |
236 | void derefStructures(Instruction* vPC) const; | |
ba379fdc | 237 | #if ENABLE(JIT_OPTIMIZE_CALL) |
9dae56ea A |
238 | void unlinkCallers(); |
239 | #endif | |
240 | ||
241 | static void dumpStatistics(); | |
242 | ||
243 | #if !defined(NDEBUG) || ENABLE_OPCODE_SAMPLING | |
244 | void dump(ExecState*) const; | |
245 | void printStructures(const Instruction*) const; | |
246 | void printStructure(const char* name, const Instruction*, int operand) const; | |
247 | #endif | |
248 | ||
249 | inline bool isKnownNotImmediate(int index) | |
250 | { | |
251 | if (index == m_thisRegister) | |
252 | return true; | |
253 | ||
254 | if (isConstantRegisterIndex(index)) | |
255 | return getConstant(index).isCell(); | |
256 | ||
257 | return false; | |
258 | } | |
259 | ||
9dae56ea A |
260 | ALWAYS_INLINE bool isTemporaryRegisterIndex(int index) |
261 | { | |
ba379fdc | 262 | return index >= m_numVars; |
9dae56ea A |
263 | } |
264 | ||
265 | HandlerInfo* handlerForBytecodeOffset(unsigned bytecodeOffset); | |
266 | int lineNumberForBytecodeOffset(CallFrame*, unsigned bytecodeOffset); | |
267 | int expressionRangeForBytecodeOffset(CallFrame*, unsigned bytecodeOffset, int& divot, int& startOffset, int& endOffset); | |
268 | bool getByIdExceptionInfoForBytecodeOffset(CallFrame*, unsigned bytecodeOffset, OpcodeID&); | |
269 | ||
270 | #if ENABLE(JIT) | |
271 | void addCaller(CallLinkInfo* caller) | |
272 | { | |
273 | caller->callee = this; | |
274 | caller->position = m_linkedCallerList.size(); | |
275 | m_linkedCallerList.append(caller); | |
276 | } | |
277 | ||
278 | void removeCaller(CallLinkInfo* caller) | |
279 | { | |
280 | unsigned pos = caller->position; | |
281 | unsigned lastPos = m_linkedCallerList.size() - 1; | |
282 | ||
283 | if (pos != lastPos) { | |
284 | m_linkedCallerList[pos] = m_linkedCallerList[lastPos]; | |
285 | m_linkedCallerList[pos]->position = pos; | |
286 | } | |
287 | m_linkedCallerList.shrink(lastPos); | |
288 | } | |
289 | ||
ba379fdc | 290 | StructureStubInfo& getStubInfo(ReturnAddressPtr returnAddress) |
9dae56ea | 291 | { |
ba379fdc | 292 | return *(binaryChop<StructureStubInfo, void*, getStructureStubInfoReturnLocation>(m_structureStubInfos.begin(), m_structureStubInfos.size(), returnAddress.value())); |
9dae56ea A |
293 | } |
294 | ||
ba379fdc | 295 | CallLinkInfo& getCallLinkInfo(ReturnAddressPtr returnAddress) |
9dae56ea | 296 | { |
ba379fdc | 297 | return *(binaryChop<CallLinkInfo, void*, getCallLinkInfoReturnLocation>(m_callLinkInfos.begin(), m_callLinkInfos.size(), returnAddress.value())); |
9dae56ea A |
298 | } |
299 | ||
ba379fdc A |
300 | MethodCallLinkInfo& getMethodCallLinkInfo(ReturnAddressPtr returnAddress) |
301 | { | |
302 | return *(binaryChop<MethodCallLinkInfo, void*, getMethodCallLinkInfoReturnLocation>(m_methodCallLinkInfos.begin(), m_methodCallLinkInfos.size(), returnAddress.value())); | |
303 | } | |
304 | ||
305 | unsigned getBytecodeIndex(CallFrame* callFrame, ReturnAddressPtr returnAddress) | |
9dae56ea A |
306 | { |
307 | reparseForExceptionInfoIfNecessary(callFrame); | |
ba379fdc | 308 | return binaryChop<CallReturnOffsetToBytecodeIndex, unsigned, getCallReturnOffset>(m_exceptionInfo->m_callReturnIndexVector.begin(), m_exceptionInfo->m_callReturnIndexVector.size(), ownerNode()->generatedJITCode().offsetOf(returnAddress.value()))->bytecodeIndex; |
9dae56ea A |
309 | } |
310 | ||
311 | bool functionRegisterForBytecodeOffset(unsigned bytecodeOffset, int& functionRegisterIndex); | |
312 | #endif | |
313 | ||
314 | void setIsNumericCompareFunction(bool isNumericCompareFunction) { m_isNumericCompareFunction = isNumericCompareFunction; } | |
315 | bool isNumericCompareFunction() { return m_isNumericCompareFunction; } | |
316 | ||
317 | Vector<Instruction>& instructions() { return m_instructions; } | |
318 | #ifndef NDEBUG | |
319 | void setInstructionCount(unsigned instructionCount) { m_instructionCount = instructionCount; } | |
320 | #endif | |
321 | ||
322 | #if ENABLE(JIT) | |
ba379fdc A |
323 | JITCode& getJITCode() { return ownerNode()->generatedJITCode(); } |
324 | void setJITCode(JITCode); | |
325 | ExecutablePool* executablePool() { return ownerNode()->getExecutablePool(); } | |
9dae56ea A |
326 | #endif |
327 | ||
328 | ScopeNode* ownerNode() const { return m_ownerNode; } | |
329 | ||
330 | void setGlobalData(JSGlobalData* globalData) { m_globalData = globalData; } | |
331 | ||
332 | void setThisRegister(int thisRegister) { m_thisRegister = thisRegister; } | |
333 | int thisRegister() const { return m_thisRegister; } | |
334 | ||
335 | void setNeedsFullScopeChain(bool needsFullScopeChain) { m_needsFullScopeChain = needsFullScopeChain; } | |
336 | bool needsFullScopeChain() const { return m_needsFullScopeChain; } | |
337 | void setUsesEval(bool usesEval) { m_usesEval = usesEval; } | |
338 | bool usesEval() const { return m_usesEval; } | |
339 | void setUsesArguments(bool usesArguments) { m_usesArguments = usesArguments; } | |
340 | bool usesArguments() const { return m_usesArguments; } | |
341 | ||
342 | CodeType codeType() const { return m_codeType; } | |
343 | ||
ba379fdc A |
344 | SourceProvider* source() const { ASSERT(m_codeType != NativeCode); return m_source.get(); } |
345 | unsigned sourceOffset() const { ASSERT(m_codeType != NativeCode); return m_sourceOffset; } | |
9dae56ea A |
346 | |
347 | size_t numberOfJumpTargets() const { return m_jumpTargets.size(); } | |
348 | void addJumpTarget(unsigned jumpTarget) { m_jumpTargets.append(jumpTarget); } | |
349 | unsigned jumpTarget(int index) const { return m_jumpTargets[index]; } | |
350 | unsigned lastJumpTarget() const { return m_jumpTargets.last(); } | |
351 | ||
352 | #if !ENABLE(JIT) | |
353 | void addPropertyAccessInstruction(unsigned propertyAccessInstruction) { m_propertyAccessInstructions.append(propertyAccessInstruction); } | |
354 | void addGlobalResolveInstruction(unsigned globalResolveInstruction) { m_globalResolveInstructions.append(globalResolveInstruction); } | |
355 | bool hasGlobalResolveInstructionAtBytecodeOffset(unsigned bytecodeOffset); | |
356 | #else | |
357 | size_t numberOfStructureStubInfos() const { return m_structureStubInfos.size(); } | |
358 | void addStructureStubInfo(const StructureStubInfo& stubInfo) { m_structureStubInfos.append(stubInfo); } | |
359 | StructureStubInfo& structureStubInfo(int index) { return m_structureStubInfos[index]; } | |
360 | ||
361 | void addGlobalResolveInfo(unsigned globalResolveInstruction) { m_globalResolveInfos.append(GlobalResolveInfo(globalResolveInstruction)); } | |
362 | GlobalResolveInfo& globalResolveInfo(int index) { return m_globalResolveInfos[index]; } | |
363 | bool hasGlobalResolveInfoAtBytecodeOffset(unsigned bytecodeOffset); | |
364 | ||
365 | size_t numberOfCallLinkInfos() const { return m_callLinkInfos.size(); } | |
366 | void addCallLinkInfo() { m_callLinkInfos.append(CallLinkInfo()); } | |
367 | CallLinkInfo& callLinkInfo(int index) { return m_callLinkInfos[index]; } | |
368 | ||
ba379fdc A |
369 | void addMethodCallLinkInfos(unsigned n) { m_methodCallLinkInfos.grow(n); } |
370 | MethodCallLinkInfo& methodCallLinkInfo(int index) { return m_methodCallLinkInfos[index]; } | |
371 | ||
9dae56ea A |
372 | void addFunctionRegisterInfo(unsigned bytecodeOffset, int functionIndex) { createRareDataIfNecessary(); m_rareData->m_functionRegisterInfos.append(FunctionRegisterInfo(bytecodeOffset, functionIndex)); } |
373 | #endif | |
374 | ||
375 | // Exception handling support | |
376 | ||
377 | size_t numberOfExceptionHandlers() const { return m_rareData ? m_rareData->m_exceptionHandlers.size() : 0; } | |
378 | void addExceptionHandler(const HandlerInfo& hanler) { createRareDataIfNecessary(); return m_rareData->m_exceptionHandlers.append(hanler); } | |
379 | HandlerInfo& exceptionHandler(int index) { ASSERT(m_rareData); return m_rareData->m_exceptionHandlers[index]; } | |
380 | ||
381 | bool hasExceptionInfo() const { return m_exceptionInfo; } | |
382 | void clearExceptionInfo() { m_exceptionInfo.clear(); } | |
383 | ||
384 | void addExpressionInfo(const ExpressionRangeInfo& expressionInfo) { ASSERT(m_exceptionInfo); m_exceptionInfo->m_expressionInfo.append(expressionInfo); } | |
385 | void addGetByIdExceptionInfo(const GetByIdExceptionInfo& info) { ASSERT(m_exceptionInfo); m_exceptionInfo->m_getByIdExceptionInfo.append(info); } | |
386 | ||
387 | size_t numberOfLineInfos() const { ASSERT(m_exceptionInfo); return m_exceptionInfo->m_lineInfo.size(); } | |
388 | void addLineInfo(const LineInfo& lineInfo) { ASSERT(m_exceptionInfo); m_exceptionInfo->m_lineInfo.append(lineInfo); } | |
389 | LineInfo& lastLineInfo() { ASSERT(m_exceptionInfo); return m_exceptionInfo->m_lineInfo.last(); } | |
390 | ||
391 | #if ENABLE(JIT) | |
ba379fdc | 392 | Vector<CallReturnOffsetToBytecodeIndex>& callReturnIndexVector() { ASSERT(m_exceptionInfo); return m_exceptionInfo->m_callReturnIndexVector; } |
9dae56ea A |
393 | #endif |
394 | ||
395 | // Constant Pool | |
396 | ||
397 | size_t numberOfIdentifiers() const { return m_identifiers.size(); } | |
398 | void addIdentifier(const Identifier& i) { return m_identifiers.append(i); } | |
399 | Identifier& identifier(int index) { return m_identifiers[index]; } | |
400 | ||
401 | size_t numberOfConstantRegisters() const { return m_constantRegisters.size(); } | |
402 | void addConstantRegister(const Register& r) { return m_constantRegisters.append(r); } | |
ba379fdc A |
403 | Register& constantRegister(int index) { return m_constantRegisters[index - FirstConstantRegisterIndex]; } |
404 | ALWAYS_INLINE bool isConstantRegisterIndex(int index) { return index >= FirstConstantRegisterIndex; } | |
405 | ALWAYS_INLINE JSValue getConstant(int index) const { return m_constantRegisters[index - FirstConstantRegisterIndex].jsValue(); } | |
9dae56ea A |
406 | |
407 | unsigned addFunctionExpression(FuncExprNode* n) { unsigned size = m_functionExpressions.size(); m_functionExpressions.append(n); return size; } | |
408 | FuncExprNode* functionExpression(int index) const { return m_functionExpressions[index].get(); } | |
409 | ||
410 | unsigned addFunction(FuncDeclNode* n) { createRareDataIfNecessary(); unsigned size = m_rareData->m_functions.size(); m_rareData->m_functions.append(n); return size; } | |
411 | FuncDeclNode* function(int index) const { ASSERT(m_rareData); return m_rareData->m_functions[index].get(); } | |
412 | ||
413 | bool hasFunctions() const { return m_functionExpressions.size() || (m_rareData && m_rareData->m_functions.size()); } | |
414 | ||
9dae56ea A |
415 | unsigned addRegExp(RegExp* r) { createRareDataIfNecessary(); unsigned size = m_rareData->m_regexps.size(); m_rareData->m_regexps.append(r); return size; } |
416 | RegExp* regexp(int index) const { ASSERT(m_rareData); return m_rareData->m_regexps[index].get(); } | |
417 | ||
418 | ||
419 | // Jump Tables | |
420 | ||
421 | size_t numberOfImmediateSwitchJumpTables() const { return m_rareData ? m_rareData->m_immediateSwitchJumpTables.size() : 0; } | |
422 | SimpleJumpTable& addImmediateSwitchJumpTable() { createRareDataIfNecessary(); m_rareData->m_immediateSwitchJumpTables.append(SimpleJumpTable()); return m_rareData->m_immediateSwitchJumpTables.last(); } | |
423 | SimpleJumpTable& immediateSwitchJumpTable(int tableIndex) { ASSERT(m_rareData); return m_rareData->m_immediateSwitchJumpTables[tableIndex]; } | |
424 | ||
425 | size_t numberOfCharacterSwitchJumpTables() const { return m_rareData ? m_rareData->m_characterSwitchJumpTables.size() : 0; } | |
426 | SimpleJumpTable& addCharacterSwitchJumpTable() { createRareDataIfNecessary(); m_rareData->m_characterSwitchJumpTables.append(SimpleJumpTable()); return m_rareData->m_characterSwitchJumpTables.last(); } | |
427 | SimpleJumpTable& characterSwitchJumpTable(int tableIndex) { ASSERT(m_rareData); return m_rareData->m_characterSwitchJumpTables[tableIndex]; } | |
428 | ||
429 | size_t numberOfStringSwitchJumpTables() const { return m_rareData ? m_rareData->m_stringSwitchJumpTables.size() : 0; } | |
430 | StringJumpTable& addStringSwitchJumpTable() { createRareDataIfNecessary(); m_rareData->m_stringSwitchJumpTables.append(StringJumpTable()); return m_rareData->m_stringSwitchJumpTables.last(); } | |
431 | StringJumpTable& stringSwitchJumpTable(int tableIndex) { ASSERT(m_rareData); return m_rareData->m_stringSwitchJumpTables[tableIndex]; } | |
432 | ||
433 | ||
434 | SymbolTable& symbolTable() { return m_symbolTable; } | |
435 | ||
ba379fdc | 436 | EvalCodeCache& evalCodeCache() { ASSERT(m_codeType != NativeCode); createRareDataIfNecessary(); return m_rareData->m_evalCodeCache; } |
9dae56ea A |
437 | |
438 | void shrinkToFit(); | |
439 | ||
440 | // FIXME: Make these remaining members private. | |
441 | ||
442 | int m_numCalleeRegisters; | |
9dae56ea A |
443 | int m_numVars; |
444 | int m_numParameters; | |
445 | ||
446 | private: | |
447 | #if !defined(NDEBUG) || ENABLE(OPCODE_SAMPLING) | |
448 | void dump(ExecState*, const Vector<Instruction>::const_iterator& begin, Vector<Instruction>::const_iterator&) const; | |
449 | #endif | |
450 | ||
451 | void reparseForExceptionInfoIfNecessary(CallFrame*); | |
452 | ||
453 | void createRareDataIfNecessary() | |
454 | { | |
ba379fdc | 455 | ASSERT(m_codeType != NativeCode); |
9dae56ea A |
456 | if (!m_rareData) |
457 | m_rareData.set(new RareData); | |
458 | } | |
459 | ||
460 | ScopeNode* m_ownerNode; | |
461 | JSGlobalData* m_globalData; | |
462 | ||
463 | Vector<Instruction> m_instructions; | |
464 | #ifndef NDEBUG | |
465 | unsigned m_instructionCount; | |
466 | #endif | |
9dae56ea A |
467 | |
468 | int m_thisRegister; | |
469 | ||
470 | bool m_needsFullScopeChain; | |
471 | bool m_usesEval; | |
472 | bool m_usesArguments; | |
473 | bool m_isNumericCompareFunction; | |
474 | ||
475 | CodeType m_codeType; | |
476 | ||
477 | RefPtr<SourceProvider> m_source; | |
478 | unsigned m_sourceOffset; | |
479 | ||
480 | #if !ENABLE(JIT) | |
481 | Vector<unsigned> m_propertyAccessInstructions; | |
482 | Vector<unsigned> m_globalResolveInstructions; | |
483 | #else | |
484 | Vector<StructureStubInfo> m_structureStubInfos; | |
485 | Vector<GlobalResolveInfo> m_globalResolveInfos; | |
486 | Vector<CallLinkInfo> m_callLinkInfos; | |
ba379fdc | 487 | Vector<MethodCallLinkInfo> m_methodCallLinkInfos; |
9dae56ea A |
488 | Vector<CallLinkInfo*> m_linkedCallerList; |
489 | #endif | |
490 | ||
491 | Vector<unsigned> m_jumpTargets; | |
492 | ||
493 | // Constant Pool | |
494 | Vector<Identifier> m_identifiers; | |
495 | Vector<Register> m_constantRegisters; | |
496 | Vector<RefPtr<FuncExprNode> > m_functionExpressions; | |
497 | ||
498 | SymbolTable m_symbolTable; | |
499 | ||
500 | struct ExceptionInfo { | |
501 | Vector<ExpressionRangeInfo> m_expressionInfo; | |
502 | Vector<LineInfo> m_lineInfo; | |
503 | Vector<GetByIdExceptionInfo> m_getByIdExceptionInfo; | |
504 | ||
505 | #if ENABLE(JIT) | |
ba379fdc | 506 | Vector<CallReturnOffsetToBytecodeIndex> m_callReturnIndexVector; |
9dae56ea A |
507 | #endif |
508 | }; | |
509 | OwnPtr<ExceptionInfo> m_exceptionInfo; | |
510 | ||
511 | struct RareData { | |
512 | Vector<HandlerInfo> m_exceptionHandlers; | |
513 | ||
514 | // Rare Constants | |
515 | Vector<RefPtr<FuncDeclNode> > m_functions; | |
9dae56ea A |
516 | Vector<RefPtr<RegExp> > m_regexps; |
517 | ||
518 | // Jump Tables | |
519 | Vector<SimpleJumpTable> m_immediateSwitchJumpTables; | |
520 | Vector<SimpleJumpTable> m_characterSwitchJumpTables; | |
521 | Vector<StringJumpTable> m_stringSwitchJumpTables; | |
522 | ||
523 | EvalCodeCache m_evalCodeCache; | |
524 | ||
525 | #if ENABLE(JIT) | |
526 | Vector<FunctionRegisterInfo> m_functionRegisterInfos; | |
527 | #endif | |
528 | }; | |
529 | OwnPtr<RareData> m_rareData; | |
530 | }; | |
531 | ||
532 | // Program code is not marked by any function, so we make the global object | |
533 | // responsible for marking it. | |
534 | ||
535 | class ProgramCodeBlock : public CodeBlock { | |
536 | public: | |
537 | ProgramCodeBlock(ScopeNode* ownerNode, CodeType codeType, JSGlobalObject* globalObject, PassRefPtr<SourceProvider> sourceProvider) | |
538 | : CodeBlock(ownerNode, codeType, sourceProvider, 0) | |
539 | , m_globalObject(globalObject) | |
540 | { | |
541 | m_globalObject->codeBlocks().add(this); | |
542 | } | |
543 | ||
544 | ~ProgramCodeBlock() | |
545 | { | |
546 | if (m_globalObject) | |
547 | m_globalObject->codeBlocks().remove(this); | |
548 | } | |
549 | ||
550 | void clearGlobalObject() { m_globalObject = 0; } | |
551 | ||
552 | private: | |
553 | JSGlobalObject* m_globalObject; // For program and eval nodes, the global object that marks the constant pool. | |
554 | }; | |
555 | ||
556 | class EvalCodeBlock : public ProgramCodeBlock { | |
557 | public: | |
558 | EvalCodeBlock(ScopeNode* ownerNode, JSGlobalObject* globalObject, PassRefPtr<SourceProvider> sourceProvider, int baseScopeDepth) | |
559 | : ProgramCodeBlock(ownerNode, EvalCode, globalObject, sourceProvider) | |
560 | , m_baseScopeDepth(baseScopeDepth) | |
561 | { | |
562 | } | |
563 | ||
564 | int baseScopeDepth() const { return m_baseScopeDepth; } | |
565 | ||
566 | private: | |
567 | int m_baseScopeDepth; | |
568 | }; | |
569 | ||
ba379fdc A |
570 | inline Register& ExecState::r(int index) |
571 | { | |
572 | CodeBlock* codeBlock = this->codeBlock(); | |
573 | if (codeBlock->isConstantRegisterIndex(index)) | |
574 | return codeBlock->constantRegister(index); | |
575 | return this[index]; | |
576 | } | |
577 | ||
9dae56ea A |
578 | } // namespace JSC |
579 | ||
580 | #endif // CodeBlock_h |