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