initial import
[vuplus_webkit] / Source / JavaScriptCore / bytecode / CodeBlock.h
1 /*
2  * Copyright (C) 2008, 2009, 2010 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 "CompactJITCodeMap.h"
34 #include "EvalCodeCache.h"
35 #include "Instruction.h"
36 #include "JITCode.h"
37 #include "JITWriteBarrier.h"
38 #include "JSGlobalObject.h"
39 #include "JumpTable.h"
40 #include "Nodes.h"
41 #include "PredictionTracker.h"
42 #include "RegExpObject.h"
43 #include "UString.h"
44 #include "WeakReferenceHarvester.h"
45 #include "ValueProfile.h"
46 #include <wtf/FastAllocBase.h>
47 #include <wtf/PassOwnPtr.h>
48 #include <wtf/RefPtr.h>
49 #include <wtf/SegmentedVector.h>
50 #include <wtf/SentinelLinkedList.h>
51 #include <wtf/Vector.h>
52
53 #if ENABLE(JIT)
54 #include "StructureStubInfo.h"
55 #endif
56
57 // Register numbers used in bytecode operations have different meaning according to their ranges:
58 //      0x80000000-0xFFFFFFFF  Negative indices from the CallFrame pointer are entries in the call frame, see RegisterFile.h.
59 //      0x00000000-0x3FFFFFFF  Forwards indices from the CallFrame pointer are local vars and temporaries with the function's callframe.
60 //      0x40000000-0x7FFFFFFF  Positive indices from 0x40000000 specify entries in the constant pool on the CodeBlock.
61 static const int FirstConstantRegisterIndex = 0x40000000;
62
63 namespace JSC {
64
65     enum HasSeenShouldRepatch {
66         hasSeenShouldRepatch
67     };
68
69     class ExecState;
70
71     enum CodeType { GlobalCode, EvalCode, FunctionCode };
72
73     inline int unmodifiedArgumentsRegister(int argumentsRegister) { return argumentsRegister - 1; }
74
75     static ALWAYS_INLINE int missingThisObjectMarker() { return std::numeric_limits<int>::max(); }
76
77     struct HandlerInfo {
78         uint32_t start;
79         uint32_t end;
80         uint32_t target;
81         uint32_t scopeDepth;
82 #if ENABLE(JIT)
83         CodeLocationLabel nativeCode;
84 #endif
85     };
86
87     struct ExpressionRangeInfo {
88         enum {
89             MaxOffset = (1 << 7) - 1, 
90             MaxDivot = (1 << 25) - 1
91         };
92         uint32_t instructionOffset : 25;
93         uint32_t divotPoint : 25;
94         uint32_t startOffset : 7;
95         uint32_t endOffset : 7;
96     };
97
98     struct LineInfo {
99         uint32_t instructionOffset;
100         int32_t lineNumber;
101     };
102
103 #if ENABLE(JIT)
104     struct CallLinkInfo: public BasicRawSentinelNode<CallLinkInfo> {
105         CallLinkInfo()
106             : hasSeenShouldRepatch(false)
107             , isCall(false)
108             , isDFG(false)
109         {
110         }
111         
112         ~CallLinkInfo()
113         {
114             if (isOnList())
115                 remove();
116         }
117
118         CodeLocationLabel callReturnLocation; // it's a near call in the old JIT, or a normal call in DFG
119         CodeLocationDataLabelPtr hotPathBegin;
120         CodeLocationNearCall hotPathOther;
121         JITWriteBarrier<JSFunction> callee;
122         bool hasSeenShouldRepatch : 1;
123         bool isCall : 1;
124         bool isDFG : 1;
125
126         bool isLinked() { return callee; }
127         void unlink(JSGlobalData&, RepatchBuffer&);
128
129         bool seenOnce()
130         {
131             return hasSeenShouldRepatch;
132         }
133
134         void setSeen()
135         {
136             hasSeenShouldRepatch = true;
137         }
138     };
139
140     struct MethodCallLinkInfo {
141         MethodCallLinkInfo()
142             : seen(false)
143         {
144         }
145
146         bool seenOnce()
147         {
148             return seen;
149         }
150
151         void setSeen()
152         {
153             seen = true;
154         }
155
156         CodeLocationCall callReturnLocation;
157         JITWriteBarrier<Structure> cachedStructure;
158         JITWriteBarrier<Structure> cachedPrototypeStructure;
159         // We'd like this to actually be JSFunction, but InternalFunction and JSFunction
160         // don't have a common parent class and we allow specialisation on both
161         JITWriteBarrier<JSObject> cachedFunction;
162         JITWriteBarrier<JSObject> cachedPrototype;
163         bool seen;
164     };
165
166     struct GlobalResolveInfo {
167         GlobalResolveInfo(unsigned bytecodeOffset)
168             : offset(0)
169             , bytecodeOffset(bytecodeOffset)
170         {
171         }
172
173         WriteBarrier<Structure> structure;
174         unsigned offset;
175         unsigned bytecodeOffset;
176     };
177
178     // This structure is used to map from a call return location
179     // (given as an offset in bytes into the JIT code) back to
180     // the bytecode index of the corresponding bytecode operation.
181     // This is then used to look up the corresponding handler.
182     struct CallReturnOffsetToBytecodeOffset {
183         CallReturnOffsetToBytecodeOffset(unsigned callReturnOffset, unsigned bytecodeOffset)
184             : callReturnOffset(callReturnOffset)
185             , bytecodeOffset(bytecodeOffset)
186         {
187         }
188
189         unsigned callReturnOffset;
190         unsigned bytecodeOffset;
191     };
192
193     // valueAtPosition helpers for the binarySearch algorithm.
194
195     inline void* getStructureStubInfoReturnLocation(StructureStubInfo* structureStubInfo)
196     {
197         return structureStubInfo->callReturnLocation.executableAddress();
198     }
199
200     inline void* getCallLinkInfoReturnLocation(CallLinkInfo* callLinkInfo)
201     {
202         return callLinkInfo->callReturnLocation.executableAddress();
203     }
204
205     inline void* getMethodCallLinkInfoReturnLocation(MethodCallLinkInfo* methodCallLinkInfo)
206     {
207         return methodCallLinkInfo->callReturnLocation.executableAddress();
208     }
209
210     inline unsigned getCallReturnOffset(CallReturnOffsetToBytecodeOffset* pc)
211     {
212         return pc->callReturnOffset;
213     }
214 #endif
215
216     class CodeBlock: public WeakReferenceHarvester {
217         WTF_MAKE_FAST_ALLOCATED;
218         friend class JIT;
219     protected:
220         CodeBlock(ScriptExecutable* ownerExecutable, CodeType, JSGlobalObject*, PassRefPtr<SourceProvider>, unsigned sourceOffset, SymbolTable*, bool isConstructor, PassOwnPtr<CodeBlock> alternative);
221
222         WriteBarrier<JSGlobalObject> m_globalObject;
223         Heap* m_heap;
224
225     public:
226         virtual ~CodeBlock();
227         
228         CodeBlock* alternative() { return m_alternative.get(); }
229         PassOwnPtr<CodeBlock> releaseAlternative() { return m_alternative.release(); }
230         
231         void setPredictions(PassOwnPtr<PredictionTracker> predictions) { m_predictions = predictions; }
232         PredictionTracker* predictions() const { return m_predictions.get(); }
233
234         void visitAggregate(SlotVisitor&);
235         void visitWeakReferences(SlotVisitor&);
236
237         static void dumpStatistics();
238
239 #if !defined(NDEBUG) || ENABLE_OPCODE_SAMPLING
240         void dump(ExecState*) const;
241         void printStructures(const Instruction*) const;
242         void printStructure(const char* name, const Instruction*, int operand) const;
243 #endif
244
245         bool isStrictMode() const { return m_isStrictMode; }
246
247         inline bool isKnownNotImmediate(int index)
248         {
249             if (index == m_thisRegister && !m_isStrictMode)
250                 return true;
251
252             if (isConstantRegisterIndex(index))
253                 return getConstant(index).isCell();
254
255             return false;
256         }
257
258         ALWAYS_INLINE bool isTemporaryRegisterIndex(int index)
259         {
260             return index >= m_numVars;
261         }
262
263         HandlerInfo* handlerForBytecodeOffset(unsigned bytecodeOffset);
264         int lineNumberForBytecodeOffset(unsigned bytecodeOffset);
265         void expressionRangeForBytecodeOffset(unsigned bytecodeOffset, int& divot, int& startOffset, int& endOffset);
266
267 #if ENABLE(JIT)
268
269         StructureStubInfo& getStubInfo(ReturnAddressPtr returnAddress)
270         {
271             return *(binarySearch<StructureStubInfo, void*, getStructureStubInfoReturnLocation>(m_structureStubInfos.begin(), m_structureStubInfos.size(), returnAddress.value()));
272         }
273
274         CallLinkInfo& getCallLinkInfo(ReturnAddressPtr returnAddress)
275         {
276             return *(binarySearch<CallLinkInfo, void*, getCallLinkInfoReturnLocation>(m_callLinkInfos.begin(), m_callLinkInfos.size(), returnAddress.value()));
277         }
278
279         MethodCallLinkInfo& getMethodCallLinkInfo(ReturnAddressPtr returnAddress)
280         {
281             return *(binarySearch<MethodCallLinkInfo, void*, getMethodCallLinkInfoReturnLocation>(m_methodCallLinkInfos.begin(), m_methodCallLinkInfos.size(), returnAddress.value()));
282         }
283
284         unsigned bytecodeOffset(ReturnAddressPtr returnAddress)
285         {
286             if (!m_rareData)
287                 return 1;
288             Vector<CallReturnOffsetToBytecodeOffset>& callIndices = m_rareData->m_callReturnIndexVector;
289             if (!callIndices.size())
290                 return 1;
291             return binarySearch<CallReturnOffsetToBytecodeOffset, unsigned, getCallReturnOffset>(callIndices.begin(), callIndices.size(), getJITCode().offsetOf(returnAddress.value()))->bytecodeOffset;
292         }
293
294         void unlinkCalls();
295         
296         bool hasIncomingCalls() { return m_incomingCalls.begin() != m_incomingCalls.end(); }
297         
298         void linkIncomingCall(CallLinkInfo* incoming)
299         {
300             m_incomingCalls.push(incoming);
301         }
302         
303         void unlinkIncomingCalls();
304 #endif
305
306 #if ENABLE(TIERED_COMPILATION)
307         void setJITCodeMap(PassOwnPtr<CompactJITCodeMap> jitCodeMap)
308         {
309             m_jitCodeMap = jitCodeMap;
310         }
311         CompactJITCodeMap* jitCodeMap()
312         {
313             return m_jitCodeMap.get();
314         }
315 #endif
316
317 #if ENABLE(INTERPRETER)
318         unsigned bytecodeOffset(Instruction* returnAddress)
319         {
320             return static_cast<Instruction*>(returnAddress) - instructions().begin();
321         }
322 #endif
323
324         void setIsNumericCompareFunction(bool isNumericCompareFunction) { m_isNumericCompareFunction = isNumericCompareFunction; }
325         bool isNumericCompareFunction() { return m_isNumericCompareFunction; }
326
327         Vector<Instruction>& instructions() { return m_instructions; }
328         void discardBytecode() { m_instructions.clear(); }
329
330 #ifndef NDEBUG
331         unsigned instructionCount() { return m_instructionCount; }
332         void setInstructionCount(unsigned instructionCount) { m_instructionCount = instructionCount; }
333 #endif
334
335 #if ENABLE(JIT)
336         void setJITCode(const JITCode& code, MacroAssemblerCodePtr codeWithArityCheck)
337         {
338             m_jitCode = code;
339             m_jitCodeWithArityCheck = codeWithArityCheck;
340         }
341         JITCode& getJITCode() { return m_jitCode; }
342         JITCode::JITType getJITType() { return m_jitCode.jitType(); }
343         ExecutableMemoryHandle* executableMemory() { return getJITCode().getExecutableMemory(); }
344         virtual JSObject* compileOptimized(ExecState*, ScopeChainNode*) = 0;
345         virtual CodeBlock* replacement() = 0;
346         virtual bool canCompileWithDFG() = 0;
347         bool hasOptimizedReplacement()
348         {
349             ASSERT(getJITType() == JITCode::BaselineJIT);
350             bool result = replacement()->getJITType() > getJITType();
351 #if !ASSERT_DISABLED
352             if (result)
353                 ASSERT(replacement()->getJITType() == JITCode::DFGJIT);
354             else {
355                 ASSERT(replacement()->getJITType() == JITCode::BaselineJIT);
356                 ASSERT(replacement() == this);
357             }
358 #endif
359             return result;
360         }
361 #else
362         JITCode::JITType getJITType() { return JITCode::BaselineJIT; }
363 #endif
364
365         ScriptExecutable* ownerExecutable() const { return m_ownerExecutable.get(); }
366
367         void setGlobalData(JSGlobalData* globalData) { m_globalData = globalData; }
368         JSGlobalData* globalData() { return m_globalData; }
369
370         void setThisRegister(int thisRegister) { m_thisRegister = thisRegister; }
371         int thisRegister() const { return m_thisRegister; }
372
373         void setNeedsFullScopeChain(bool needsFullScopeChain) { m_needsFullScopeChain = needsFullScopeChain; }
374         bool needsFullScopeChain() const { return m_needsFullScopeChain; }
375         void setUsesEval(bool usesEval) { m_usesEval = usesEval; }
376         bool usesEval() const { return m_usesEval; }
377         
378         void setArgumentsRegister(int argumentsRegister)
379         {
380             ASSERT(argumentsRegister != -1);
381             m_argumentsRegister = argumentsRegister;
382             ASSERT(usesArguments());
383         }
384         int argumentsRegister()
385         {
386             ASSERT(usesArguments());
387             return m_argumentsRegister;
388         }
389         void setActivationRegister(int activationRegister)
390         {
391             m_activationRegister = activationRegister;
392         }
393         int activationRegister()
394         {
395             ASSERT(needsFullScopeChain());
396             return m_activationRegister;
397         }
398         bool usesArguments() const { return m_argumentsRegister != -1; }
399
400         CodeType codeType() const { return m_codeType; }
401
402         SourceProvider* source() const { return m_source.get(); }
403         unsigned sourceOffset() const { return m_sourceOffset; }
404
405         size_t numberOfJumpTargets() const { return m_jumpTargets.size(); }
406         void addJumpTarget(unsigned jumpTarget) { m_jumpTargets.append(jumpTarget); }
407         unsigned jumpTarget(int index) const { return m_jumpTargets[index]; }
408         unsigned lastJumpTarget() const { return m_jumpTargets.last(); }
409
410         void createActivation(CallFrame*);
411
412         void clearEvalCache();
413
414 #if ENABLE(INTERPRETER)
415         void addPropertyAccessInstruction(unsigned propertyAccessInstruction)
416         {
417             if (!m_globalData->canUseJIT())
418                 m_propertyAccessInstructions.append(propertyAccessInstruction);
419         }
420         void addGlobalResolveInstruction(unsigned globalResolveInstruction)
421         {
422             if (!m_globalData->canUseJIT())
423                 m_globalResolveInstructions.append(globalResolveInstruction);
424         }
425         bool hasGlobalResolveInstructionAtBytecodeOffset(unsigned bytecodeOffset);
426 #endif
427 #if ENABLE(JIT)
428         void setNumberOfStructureStubInfos(size_t size) { m_structureStubInfos.grow(size); }
429         size_t numberOfStructureStubInfos() const { return m_structureStubInfos.size(); }
430         StructureStubInfo& structureStubInfo(int index) { return m_structureStubInfos[index]; }
431
432         void addGlobalResolveInfo(unsigned globalResolveInstruction)
433         {
434             if (m_globalData->canUseJIT())
435                 m_globalResolveInfos.append(GlobalResolveInfo(globalResolveInstruction));
436         }
437         GlobalResolveInfo& globalResolveInfo(int index) { return m_globalResolveInfos[index]; }
438         bool hasGlobalResolveInfoAtBytecodeOffset(unsigned bytecodeOffset);
439
440         void setNumberOfCallLinkInfos(size_t size) { m_callLinkInfos.grow(size); }
441         size_t numberOfCallLinkInfos() const { return m_callLinkInfos.size(); }
442         CallLinkInfo& callLinkInfo(int index) { return m_callLinkInfos[index]; }
443
444         void addMethodCallLinkInfos(unsigned n) { ASSERT(m_globalData->canUseJIT()); m_methodCallLinkInfos.grow(n); }
445         MethodCallLinkInfo& methodCallLinkInfo(int index) { return m_methodCallLinkInfos[index]; }
446 #endif
447         
448 #if ENABLE(VALUE_PROFILER)
449         ValueProfile* addValueProfile(int bytecodeOffset)
450         {
451             m_valueProfiles.append(ValueProfile(bytecodeOffset));
452             return &m_valueProfiles.last();
453         }
454         unsigned numberOfValueProfiles() { return m_valueProfiles.size(); }
455         ValueProfile* valueProfile(int index) { return &m_valueProfiles[index]; }
456         ValueProfile* valueProfileForBytecodeOffset(int bytecodeOffset)
457         {
458             return WTF::genericBinarySearch<ValueProfile, int, getValueProfileBytecodeOffset>(m_valueProfiles, m_valueProfiles.size(), bytecodeOffset);
459         }
460         ValueProfile* valueProfileForArgument(int argumentIndex)
461         {
462             int index = argumentIndex - 1;
463             if (static_cast<unsigned>(index) >= m_valueProfiles.size())
464                 return 0;
465             ValueProfile* result = valueProfile(argumentIndex - 1);
466             if (result->m_bytecodeOffset != -1)
467                 return 0;
468             return result;
469         }
470 #endif
471
472         unsigned globalResolveInfoCount() const
473         {
474 #if ENABLE(JIT)    
475             if (m_globalData->canUseJIT())
476                 return m_globalResolveInfos.size();
477 #endif
478             return 0;
479         }
480
481         // Exception handling support
482
483         size_t numberOfExceptionHandlers() const { return m_rareData ? m_rareData->m_exceptionHandlers.size() : 0; }
484         void addExceptionHandler(const HandlerInfo& hanler) { createRareDataIfNecessary(); return m_rareData->m_exceptionHandlers.append(hanler); }
485         HandlerInfo& exceptionHandler(int index) { ASSERT(m_rareData); return m_rareData->m_exceptionHandlers[index]; }
486
487         void addExpressionInfo(const ExpressionRangeInfo& expressionInfo)
488         {
489             createRareDataIfNecessary();
490             m_rareData->m_expressionInfo.append(expressionInfo);
491         }
492
493         void addLineInfo(unsigned bytecodeOffset, int lineNo)
494         {
495             createRareDataIfNecessary();
496             Vector<LineInfo>& lineInfo = m_rareData->m_lineInfo;
497             if (!lineInfo.size() || lineInfo.last().lineNumber != lineNo) {
498                 LineInfo info = { bytecodeOffset, lineNo };
499                 lineInfo.append(info);
500             }
501         }
502
503         bool hasExpressionInfo() { return m_rareData && m_rareData->m_expressionInfo.size(); }
504         bool hasLineInfo() { return m_rareData && m_rareData->m_lineInfo.size(); }
505         //  We only generate exception handling info if the user is debugging
506         // (and may want line number info), or if the function contains exception handler.
507         bool needsCallReturnIndices()
508         {
509             return m_rareData &&
510                 (m_rareData->m_expressionInfo.size() || m_rareData->m_lineInfo.size() || m_rareData->m_exceptionHandlers.size());
511         }
512
513 #if ENABLE(JIT)
514         Vector<CallReturnOffsetToBytecodeOffset>& callReturnIndexVector()
515         {
516             createRareDataIfNecessary();
517             return m_rareData->m_callReturnIndexVector;
518         }
519 #endif
520
521         // Constant Pool
522
523         size_t numberOfIdentifiers() const { return m_identifiers.size(); }
524         void addIdentifier(const Identifier& i) { return m_identifiers.append(i); }
525         Identifier& identifier(int index) { return m_identifiers[index]; }
526
527         size_t numberOfConstantRegisters() const { return m_constantRegisters.size(); }
528         void addConstant(JSValue v)
529         {
530             m_constantRegisters.append(WriteBarrier<Unknown>());
531             m_constantRegisters.last().set(m_globalObject->globalData(), m_ownerExecutable.get(), v);
532         }
533         WriteBarrier<Unknown>& constantRegister(int index) { return m_constantRegisters[index - FirstConstantRegisterIndex]; }
534         ALWAYS_INLINE bool isConstantRegisterIndex(int index) const { return index >= FirstConstantRegisterIndex; }
535         ALWAYS_INLINE JSValue getConstant(int index) const { return m_constantRegisters[index - FirstConstantRegisterIndex].get(); }
536
537         unsigned addFunctionDecl(FunctionExecutable* n)
538         {
539             unsigned size = m_functionDecls.size();
540             m_functionDecls.append(WriteBarrier<FunctionExecutable>());
541             m_functionDecls.last().set(m_globalObject->globalData(), m_ownerExecutable.get(), n);
542             return size;
543         }
544         FunctionExecutable* functionDecl(int index) { return m_functionDecls[index].get(); }
545         int numberOfFunctionDecls() { return m_functionDecls.size(); }
546         unsigned addFunctionExpr(FunctionExecutable* n)
547         {
548             unsigned size = m_functionExprs.size();
549             m_functionExprs.append(WriteBarrier<FunctionExecutable>());
550             m_functionExprs.last().set(m_globalObject->globalData(), m_ownerExecutable.get(), n);
551             return size;
552         }
553         FunctionExecutable* functionExpr(int index) { return m_functionExprs[index].get(); }
554
555         unsigned addRegExp(RegExp* r)
556         {
557             createRareDataIfNecessary();
558             unsigned size = m_rareData->m_regexps.size();
559             m_rareData->m_regexps.append(WriteBarrier<RegExp>(*m_globalData, ownerExecutable(), r));
560             return size;
561         }
562         unsigned numberOfRegExps() const
563         {
564             if (!m_rareData)
565                 return 0;
566             return m_rareData->m_regexps.size();
567         }
568         RegExp* regexp(int index) const { ASSERT(m_rareData); return m_rareData->m_regexps[index].get(); }
569
570         unsigned addConstantBuffer(unsigned length)
571         {
572             createRareDataIfNecessary();
573             unsigned size = m_rareData->m_constantBuffers.size();
574             m_rareData->m_constantBuffers.append(Vector<JSValue>(length));
575             return size;
576         }
577
578         JSValue* constantBuffer(unsigned index)
579         {
580             ASSERT(m_rareData);
581             return m_rareData->m_constantBuffers[index].data();
582         }
583
584         JSGlobalObject* globalObject() { return m_globalObject.get(); }
585
586         // Jump Tables
587
588         size_t numberOfImmediateSwitchJumpTables() const { return m_rareData ? m_rareData->m_immediateSwitchJumpTables.size() : 0; }
589         SimpleJumpTable& addImmediateSwitchJumpTable() { createRareDataIfNecessary(); m_rareData->m_immediateSwitchJumpTables.append(SimpleJumpTable()); return m_rareData->m_immediateSwitchJumpTables.last(); }
590         SimpleJumpTable& immediateSwitchJumpTable(int tableIndex) { ASSERT(m_rareData); return m_rareData->m_immediateSwitchJumpTables[tableIndex]; }
591
592         size_t numberOfCharacterSwitchJumpTables() const { return m_rareData ? m_rareData->m_characterSwitchJumpTables.size() : 0; }
593         SimpleJumpTable& addCharacterSwitchJumpTable() { createRareDataIfNecessary(); m_rareData->m_characterSwitchJumpTables.append(SimpleJumpTable()); return m_rareData->m_characterSwitchJumpTables.last(); }
594         SimpleJumpTable& characterSwitchJumpTable(int tableIndex) { ASSERT(m_rareData); return m_rareData->m_characterSwitchJumpTables[tableIndex]; }
595
596         size_t numberOfStringSwitchJumpTables() const { return m_rareData ? m_rareData->m_stringSwitchJumpTables.size() : 0; }
597         StringJumpTable& addStringSwitchJumpTable() { createRareDataIfNecessary(); m_rareData->m_stringSwitchJumpTables.append(StringJumpTable()); return m_rareData->m_stringSwitchJumpTables.last(); }
598         StringJumpTable& stringSwitchJumpTable(int tableIndex) { ASSERT(m_rareData); return m_rareData->m_stringSwitchJumpTables[tableIndex]; }
599
600
601         SymbolTable* symbolTable() { return m_symbolTable; }
602         SharedSymbolTable* sharedSymbolTable() { ASSERT(m_codeType == FunctionCode); return static_cast<SharedSymbolTable*>(m_symbolTable); }
603
604         EvalCodeCache& evalCodeCache() { createRareDataIfNecessary(); return m_rareData->m_evalCodeCache; }
605
606         void shrinkToFit();
607         
608         void copyDataFromAlternative();
609         
610         // Functions for controlling when tiered compilation kicks in. This
611         // controls both when the optimizing compiler is invoked and when OSR
612         // entry happens. Two triggers exist: the loop trigger and the return
613         // trigger. In either case, when an addition to m_executeCounter
614         // causes it to become non-negative, the optimizing compiler is
615         // invoked. This includes a fast check to see if this CodeBlock has
616         // already been optimized (i.e. replacement() returns a CodeBlock
617         // that was optimized with a higher tier JIT than this one). In the
618         // case of the loop trigger, if the optimized compilation succeeds
619         // (or has already succeeded in the past) then OSR is attempted to
620         // redirect program flow into the optimized code.
621         
622         // These functions are called from within the optimization triggers,
623         // and are used as a single point at which we define the heuristics
624         // for how much warm-up is mandated before the next optimization
625         // trigger files. All CodeBlocks start out with optimizeAfterWarmUp(),
626         // as this is called from the CodeBlock constructor.
627         
628         // These functions are provided to support calling
629         // optimizeAfterWarmUp() from JIT-generated code.
630         int32_t counterValueForOptimizeAfterWarmUp()
631         {
632             return -1000;
633         }
634         
635         int32_t* addressOfExecuteCounter()
636         {
637             return &m_executeCounter;
638         }
639         
640         // Call this to force the next optimization trigger to fire. This is
641         // rarely wise, since optimization triggers are typically more
642         // expensive than executing baseline code.
643         void optimizeNextInvocation()
644         {
645             m_executeCounter = 0;
646         }
647         
648         // Call this to prevent optimization from happening again. Note that
649         // optimization will still happen after roughly 2^29 invocations,
650         // so this is really meant to delay that as much as possible. This
651         // is called if optimization failed, and we expect it to fail in
652         // the future as well.
653         void dontOptimizeAnytimeSoon()
654         {
655             m_executeCounter = std::numeric_limits<int32_t>::min();
656         }
657         
658         // Call this to reinitialize the counter to its starting state,
659         // forcing a warm-up to happen before the next optimization trigger
660         // fires. This is called in the CodeBlock constructor. It also
661         // makes sense to call this if an OSR exit occurred. Note that
662         // OSR exit code is code generated, so the value of the execute
663         // counter that this corresponds to is also available directly.
664         void optimizeAfterWarmUp()
665         {
666             m_executeCounter = counterValueForOptimizeAfterWarmUp();
667         }
668         
669         // Call this to cause an optimization trigger to fire soon, but
670         // not necessarily the next one. This makes sense if optimization
671         // succeeds. Successfuly optimization means that all calls are
672         // relinked to the optimized code, so this only affects call
673         // frames that are still executing this CodeBlock. The value here
674         // is tuned to strike a balance between the cost of OSR entry
675         // (which is too high to warrant making every loop back edge to
676         // trigger OSR immediately) and the cost of executing baseline
677         // code (which is high enough that we don't necessarily want to
678         // have a full warm-up). The intuition for calling this instead of
679         // optimizeNextInvocation() is for the case of recursive functions
680         // with loops. Consider that there may be N call frames of some
681         // recursive function, for a reasonably large value of N. The top
682         // one triggers optimization, and then returns, and then all of
683         // the others return. We don't want optimization to be triggered on
684         // each return, as that would be superfluous. It only makes sense
685         // to trigger optimization if one of those functions becomes hot
686         // in the baseline code.
687         void optimizeSoon()
688         {
689             m_executeCounter = -100;
690         }
691         
692         // The amount by which the JIT will increment m_executeCounter.
693         static const unsigned executeCounterIncrementForLoop = 1;
694         static const unsigned executeCounterIncrementForReturn = 15;
695         
696 #if ENABLE(VALUE_PROFILER)
697         bool shouldOptimizeNow();
698 #else
699         bool shouldOptimizeNow() { return false; }
700 #endif
701
702 #if ENABLE(VERBOSE_VALUE_PROFILE)
703         void dumpValueProfiles();
704 #endif
705         
706         // FIXME: Make these remaining members private.
707
708         int m_numCalleeRegisters;
709         int m_numVars;
710         int m_numCapturedVars;
711         int m_numParameters;
712         bool m_isConstructor;
713
714     private:
715 #if !defined(NDEBUG) || ENABLE(OPCODE_SAMPLING)
716         void dump(ExecState*, const Vector<Instruction>::const_iterator& begin, Vector<Instruction>::const_iterator&) const;
717
718         CString registerName(ExecState*, int r) const;
719         void printUnaryOp(ExecState*, int location, Vector<Instruction>::const_iterator&, const char* op) const;
720         void printBinaryOp(ExecState*, int location, Vector<Instruction>::const_iterator&, const char* op) const;
721         void printConditionalJump(ExecState*, const Vector<Instruction>::const_iterator&, Vector<Instruction>::const_iterator&, int location, const char* op) const;
722         void printGetByIdOp(ExecState*, int location, Vector<Instruction>::const_iterator&, const char* op) const;
723         void printPutByIdOp(ExecState*, int location, Vector<Instruction>::const_iterator&, const char* op) const;
724 #endif
725         void visitStructures(SlotVisitor&, Instruction* vPC) const;
726
727         void createRareDataIfNecessary()
728         {
729             if (!m_rareData)
730                 m_rareData = adoptPtr(new RareData);
731         }
732
733         WriteBarrier<ScriptExecutable> m_ownerExecutable;
734         JSGlobalData* m_globalData;
735
736         Vector<Instruction> m_instructions;
737 #ifndef NDEBUG
738         unsigned m_instructionCount;
739 #endif
740
741         int m_thisRegister;
742         int m_argumentsRegister;
743         int m_activationRegister;
744
745         bool m_needsFullScopeChain;
746         bool m_usesEval;
747         bool m_isNumericCompareFunction;
748         bool m_isStrictMode;
749
750         CodeType m_codeType;
751
752         RefPtr<SourceProvider> m_source;
753         unsigned m_sourceOffset;
754
755 #if ENABLE(INTERPRETER)
756         Vector<unsigned> m_propertyAccessInstructions;
757         Vector<unsigned> m_globalResolveInstructions;
758 #endif
759 #if ENABLE(JIT)
760         Vector<StructureStubInfo> m_structureStubInfos;
761         Vector<GlobalResolveInfo> m_globalResolveInfos;
762         Vector<CallLinkInfo> m_callLinkInfos;
763         Vector<MethodCallLinkInfo> m_methodCallLinkInfos;
764         JITCode m_jitCode;
765         MacroAssemblerCodePtr m_jitCodeWithArityCheck;
766         SentinelLinkedList<CallLinkInfo, BasicRawSentinelNode<CallLinkInfo> > m_incomingCalls;
767 #endif
768 #if ENABLE(TIERED_COMPILATION)
769         OwnPtr<CompactJITCodeMap> m_jitCodeMap;
770 #endif
771 #if ENABLE(VALUE_PROFILER)
772         SegmentedVector<ValueProfile, 8> m_valueProfiles;
773 #endif
774
775         Vector<unsigned> m_jumpTargets;
776         Vector<unsigned> m_loopTargets;
777
778         // Constant Pool
779         Vector<Identifier> m_identifiers;
780         COMPILE_ASSERT(sizeof(Register) == sizeof(WriteBarrier<Unknown>), Register_must_be_same_size_as_WriteBarrier_Unknown);
781         Vector<WriteBarrier<Unknown> > m_constantRegisters;
782         Vector<WriteBarrier<FunctionExecutable> > m_functionDecls;
783         Vector<WriteBarrier<FunctionExecutable> > m_functionExprs;
784
785         SymbolTable* m_symbolTable;
786
787         OwnPtr<CodeBlock> m_alternative;
788         
789         OwnPtr<PredictionTracker> m_predictions;
790
791         int32_t m_executeCounter;
792         uint8_t m_optimizationDelayCounter;
793
794         struct RareData {
795            WTF_MAKE_FAST_ALLOCATED;
796         public:
797             Vector<HandlerInfo> m_exceptionHandlers;
798
799             // Rare Constants
800             Vector<WriteBarrier<RegExp> > m_regexps;
801
802             // Buffers used for large array literals
803             Vector<Vector<JSValue> > m_constantBuffers;
804             
805             // Jump Tables
806             Vector<SimpleJumpTable> m_immediateSwitchJumpTables;
807             Vector<SimpleJumpTable> m_characterSwitchJumpTables;
808             Vector<StringJumpTable> m_stringSwitchJumpTables;
809
810             EvalCodeCache m_evalCodeCache;
811
812             // Expression info - present if debugging.
813             Vector<ExpressionRangeInfo> m_expressionInfo;
814             // Line info - present if profiling or debugging.
815             Vector<LineInfo> m_lineInfo;
816 #if ENABLE(JIT)
817             Vector<CallReturnOffsetToBytecodeOffset> m_callReturnIndexVector;
818 #endif
819         };
820 #if COMPILER(MSVC)
821         friend void WTF::deleteOwnedPtr<RareData>(RareData*);
822 #endif
823         OwnPtr<RareData> m_rareData;
824     };
825
826     // Program code is not marked by any function, so we make the global object
827     // responsible for marking it.
828
829     class GlobalCodeBlock : public CodeBlock {
830     protected:
831         GlobalCodeBlock(ScriptExecutable* ownerExecutable, CodeType codeType, JSGlobalObject* globalObject, PassRefPtr<SourceProvider> sourceProvider, unsigned sourceOffset, PassOwnPtr<CodeBlock> alternative)
832             : CodeBlock(ownerExecutable, codeType, globalObject, sourceProvider, sourceOffset, &m_unsharedSymbolTable, false, alternative)
833         {
834         }
835
836     private:
837         SymbolTable m_unsharedSymbolTable;
838     };
839
840     class ProgramCodeBlock : public GlobalCodeBlock {
841     public:
842         ProgramCodeBlock(ProgramExecutable* ownerExecutable, CodeType codeType, JSGlobalObject* globalObject, PassRefPtr<SourceProvider> sourceProvider, PassOwnPtr<CodeBlock> alternative)
843             : GlobalCodeBlock(ownerExecutable, codeType, globalObject, sourceProvider, 0, alternative)
844         {
845         }
846         
847 #if ENABLE(JIT)
848     protected:
849         virtual JSObject* compileOptimized(ExecState*, ScopeChainNode*);
850         virtual CodeBlock* replacement();
851         virtual bool canCompileWithDFG();
852 #endif
853     };
854
855     class EvalCodeBlock : public GlobalCodeBlock {
856     public:
857         EvalCodeBlock(EvalExecutable* ownerExecutable, JSGlobalObject* globalObject, PassRefPtr<SourceProvider> sourceProvider, int baseScopeDepth, PassOwnPtr<CodeBlock> alternative)
858             : GlobalCodeBlock(ownerExecutable, EvalCode, globalObject, sourceProvider, 0, alternative)
859             , m_baseScopeDepth(baseScopeDepth)
860         {
861         }
862
863         int baseScopeDepth() const { return m_baseScopeDepth; }
864
865         const Identifier& variable(unsigned index) { return m_variables[index]; }
866         unsigned numVariables() { return m_variables.size(); }
867         void adoptVariables(Vector<Identifier>& variables)
868         {
869             ASSERT(m_variables.isEmpty());
870             m_variables.swap(variables);
871         }
872         
873 #if ENABLE(JIT)
874     protected:
875         virtual JSObject* compileOptimized(ExecState*, ScopeChainNode*);
876         virtual CodeBlock* replacement();
877         virtual bool canCompileWithDFG();
878 #endif
879
880     private:
881         int m_baseScopeDepth;
882         Vector<Identifier> m_variables;
883     };
884
885     class FunctionCodeBlock : public CodeBlock {
886     public:
887         // Rather than using the usual RefCounted::create idiom for SharedSymbolTable we just use new
888         // as we need to initialise the CodeBlock before we could initialise any RefPtr to hold the shared
889         // symbol table, so we just pass as a raw pointer with a ref count of 1.  We then manually deref
890         // in the destructor.
891         FunctionCodeBlock(FunctionExecutable* ownerExecutable, CodeType codeType, JSGlobalObject* globalObject, PassRefPtr<SourceProvider> sourceProvider, unsigned sourceOffset, bool isConstructor, PassOwnPtr<CodeBlock> alternative)
892             : CodeBlock(ownerExecutable, codeType, globalObject, sourceProvider, sourceOffset, SharedSymbolTable::create().leakRef(), isConstructor, alternative)
893         {
894         }
895         ~FunctionCodeBlock()
896         {
897             sharedSymbolTable()->deref();
898         }
899         
900 #if ENABLE(JIT)
901     protected:
902         virtual JSObject* compileOptimized(ExecState*, ScopeChainNode*);
903         virtual CodeBlock* replacement();
904         virtual bool canCompileWithDFG();
905 #endif
906     };
907
908     inline Register& ExecState::r(int index)
909     {
910         CodeBlock* codeBlock = this->codeBlock();
911         if (codeBlock->isConstantRegisterIndex(index))
912             return *reinterpret_cast<Register*>(&codeBlock->constantRegister(index));
913         return this[index];
914     }
915
916     inline Register& ExecState::uncheckedR(int index)
917     {
918         ASSERT(index < FirstConstantRegisterIndex);
919         return this[index];
920     }
921     
922 } // namespace JSC
923
924 #endif // CodeBlock_h