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