/*
 * Copyright (C) 2008, 2009, 2010, 2011, 2012 Apple Inc. All rights reserved.
 * Copyright (C) 2008 Cameron Zwarich <cwzwarich@uwaterloo.ca>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1.  Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 * 2.  Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
 *     its contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef CodeBlock_h
#define CodeBlock_h

#include "ArrayProfile.h"
#include "ByValInfo.h"
#include "BytecodeConventions.h"
#include "BytecodeLivenessAnalysis.h"
#include "CallLinkInfo.h"
#include "CallReturnOffsetToBytecodeOffset.h"
#include "CodeBlockSet.h"
#include "CodeOrigin.h"
#include "CodeType.h"
#include "ConstructAbility.h"
#include "CompactJITCodeMap.h"
#include "DFGCommon.h"
#include "DFGCommonData.h"
#include "DFGExitProfile.h"
#include "DeferredCompilationCallback.h"
#include "EvalCodeCache.h"
#include "ExecutableInfo.h"
#include "ExecutionCounter.h"
#include "ExpressionRangeInfo.h"
#include "HandlerInfo.h"
#include "ObjectAllocationProfile.h"
#include "PutPropertySlot.h"
#include "Instruction.h"
#include "JITCode.h"
#include "JITWriteBarrier.h"
#include "JSGlobalObject.h"
#include "JumpTable.h"
#include "LLIntCallLinkInfo.h"
#include "LazyOperandValueProfile.h"
#include "LineInfo.h"
#include "RegExpObject.h"
#include "StructureStubInfo.h"
#include "UnconditionalFinalizer.h"
#include "VariableEnvironment.h"
#include "ValueProfile.h"
#include "VirtualRegister.h"
#include "Watchpoint.h"
#include <wtf/Bag.h>
#include <wtf/CurrentTime.h>
#include <wtf/FastBitVector.h>
#include <wtf/RefCountedArray.h>
#include <wtf/FastAllocBase.h>
#include <wtf/PassOwnPtr.h>
#include <wtf/Platform.h>
#include <wtf/RefPtr.h>
#include <wtf/SegmentedVector.h>
#include <wtf/StringPrintStream.h>
#include <wtf/Vector.h>
#include <wtf/text/WTFString.h>

namespace JSC {

class ExecState;
class LLIntOffsetsExtractor;
class JSModuleEnvironment;

typedef unsigned UnlinkedValueProfile;
typedef unsigned UnlinkedArrayAllocationProfile;
typedef unsigned UnlinkedObjectAllocationProfile;

static ALWAYS_INLINE int missingThisObjectMarker() { return std::numeric_limits<int>::max(); }

enum ReoptimizationMode { DontCountReoptimization, CountReoptimization };

class CodeBlock : public RefCounted<CodeBlock>, public UnconditionalFinalizer, public WeakReferenceHarvester {
    friend class BytecodeLivenessAnalysis;
	friend class JIT;
	friend class LLIntOffsetsExtractor;
public:
	enum CopyParsedBlockTag { CopyParsedBlock };
protected:
	CodeBlock(CopyParsedBlockTag, CodeBlock& other);

	CodeBlock(ScriptExecutable* ownerExecutable, CodeType, const ExecutableInfo&, JSGlobalObject*, PassRefPtr<SourceProvider>, unsigned sourceOffset, unsigned firstLineColumnOffset);

	WriteBarrier<JSGlobalObject> m_globalObject;

public:
	JS_EXPORT_PRIVATE virtual ~CodeBlock();

    CString inferredName() const;

    CString sourceCodeForTools() const; // Not quite the actual source we parsed; this will do things like prefix the source for a function with a reified signature.
    CString sourceCodeOnOneLine() const; // As sourceCodeForTools(), but replaces all whitespace runs with a single space.
	void dumpAssumingJITType(PrintStream&, JITCode::JITType) const;
	void dump(PrintStream&) const;

    bool usesGlobalObject() const { return m_globalObjectRegister != (int)InvalidVirtualRegister; }
    void setGlobalObjectRegister(int globalObjectRegister) { m_globalObjectRegister = globalObjectRegister; }
    int globalObjectRegister() const { return m_globalObjectRegister; }

	int numParameters() const { return m_numParameters; }
	void setNumParameters(int newValue);
	void addParameter();

    int numCalleeLocals() const { return m_numCalleeLocals; }

	int* addressOfNumParameters() { return &m_numParameters; }
	static ptrdiff_t offsetOfNumParameters() { return OBJECT_OFFSETOF(CodeBlock, m_numParameters); }

	CodeBlock* alternative() { return m_alternative.get(); }
	PassRefPtr<CodeBlock> releaseAlternative() { return m_alternative.release(); }
	void setAlternative(PassRefPtr<CodeBlock> alternative) { m_alternative = alternative; }

	CodeSpecializationKind specializationKind()
	{
		if (m_isConstructor)
			return CodeForConstruct;
		return CodeForCall;
	}

    CodeBlock* baselineAlternative();

    // FIXME: Get rid of this.
    // https://bugs.webkit.org/show_bug.cgi?id=123677
	CodeBlock* baselineVersion();

	void visitAggregate(SlotVisitor&);

	static void dumpStatistics();

    void dumpBytecode(PrintStream& = WTF::dataFile());
    void dumpBytecode(
		PrintStream&, unsigned bytecodeOffset,
		const StubInfoMap& = StubInfoMap(), const CallLinkInfoMap& = CallLinkInfoMap());
    void printStructures(PrintStream&, const Instruction*);
    void printStructure(PrintStream&, const char* name, const Instruction*, int operand);

	bool isStrictMode() const { return m_isStrictMode; }
	ECMAMode ecmaMode() const { return isStrictMode() ? StrictMode : NotStrictMode; }

	bool isConstructor() { return m_isConstructor; }
	ConstructorKind constructorKind() const { return static_cast<ConstructorKind>(m_constructorKind); }
	SuperBinding superBinding() const { return static_cast<SuperBinding>(m_superBinding); }

	inline bool isKnownNotImmediate(int index)
	{
		if (index == m_thisRegister && !m_isStrictMode)
			return true;

		if (isConstantRegisterIndex(index))
			return getConstant(index).isCell();

		return false;
	}

	ALWAYS_INLINE bool isTemporaryRegisterIndex(int index)
	{
		return index >= m_numVars;
	}

#if ENABLE(BYTECODE_COMMENTS)
    const char* commentForBytecodeOffset(PrintStream&, unsigned bytecodeOffset);
    void dumpBytecodeComments(PrintStream&);
#endif

    enum class RequiredHandler {
        CatchHandler,
        AnyHandler
    };
    HandlerInfo* handlerForBytecodeOffset(unsigned bytecodeOffset, RequiredHandler = RequiredHandler::AnyHandler);
    HandlerInfo* handlerForIndex(unsigned, RequiredHandler = RequiredHandler::AnyHandler);
	unsigned lineNumberForBytecodeOffset(unsigned bytecodeOffset);
    unsigned columnNumberForBytecodeOffset(unsigned bytecodeOffset);
    void expressionRangeForBytecodeOffset(unsigned bytecodeOffset, int& divot,
        int& startOffset, int& endOffset, unsigned& line, unsigned& column) const;

    void getCallLinkInfoMap(CallLinkInfoMap& result);

    // This is a slow function call used primarily for compiling OSR exits in the case
    // that there had been inlining. Chances are if you want to use this, you're really
    // looking for a CallLinkInfoMap to amortize the cost of calling this.
    CallLinkInfo* getCallLinkInfoForBytecodeIndex(unsigned bytecodeIndex);

    void getStubInfoMap(StubInfoMap& result);

#if ENABLE(JIT)
    StructureStubInfo* addStubInfo();
    Bag<StructureStubInfo>::iterator stubInfoBegin() { return m_stubInfos.begin(); }
    Bag<StructureStubInfo>::iterator stubInfoEnd() { return m_stubInfos.end(); }

    // O(n) operation. Use getStubInfoMap() unless you really only intend to get one
    // stub info.
    StructureStubInfo* findStubInfo(CodeOrigin);

    void resetStub(StructureStubInfo&);

	ByValInfo* getByValInfo(unsigned bytecodeIndex)
	{
		return binarySearch<ByValInfo, unsigned>(m_byValInfos, m_byValInfos.size(), bytecodeIndex, getByValInfoBytecodeIndex);
	}

    CallLinkInfo* addCallLinkInfo();
    Bag<CallLinkInfo>::iterator callLinkInfosBegin() { return m_callLinkInfos.begin(); }
    Bag<CallLinkInfo>::iterator callLinkInfosEnd() { return m_callLinkInfos.end(); }
#endif // ENABLE(JIT)

	void unlinkIncomingCalls();

#if ENABLE(JIT)
    void linkIncomingCall(ExecState* callerFrame, CallLinkInfo*);
    void linkIncomingPolymorphicCall(ExecState* callerFrame, PolymorphicCallNode*);
#endif // ENABLE(JIT)

#if ENABLE(LLINT)
    void linkIncomingCall(ExecState* callerFrame, LLIntCallLinkInfo*);
#endif // ENABLE(LLINT)

#if ENABLE(JIT) || ENABLE(LLINT)
	void setJITCodeMap(PassOwnPtr<CompactJITCodeMap> jitCodeMap)
	{
		m_jitCodeMap = jitCodeMap;
	}
	CompactJITCodeMap* jitCodeMap()
	{
		return m_jitCodeMap.get();
	}
#endif

	unsigned bytecodeOffset(Instruction* returnAddress)
	{
		ASSERT(returnAddress >= instructions().begin() && returnAddress < instructions().end());
		return static_cast<Instruction*>(returnAddress) - instructions().begin();
	}

    bool isBuiltinFunction() const { return m_isBuiltinFunction; }

	unsigned numberOfInstructions() const { return m_instructions.size(); }
	RefCountedArray<Instruction>& instructions() { return m_instructions; }
	const RefCountedArray<Instruction>& instructions() const { return m_instructions; }

	size_t predictedMachineCodeSize();

	bool usesOpcode(OpcodeID);

	unsigned instructionCount() const { return m_instructions.size(); }

    // Exactly equivalent to codeBlock->ownerExecutable()->newReplacementCodeBlockFor(codeBlock->specializationKind())
    PassRefPtr<CodeBlock> newReplacement();

	void setJITCode(PassRefPtr<JITCode> code)
	{
        ASSERT(m_vm->heap.isDeferred());
        if(code)
        	m_vm->heap.reportExtraMemoryAllocated(code->size());
		m_jitCode = code;
	}
	PassRefPtr<JITCode> jitCode() { return m_jitCode; }
	PassRefPtr<JITCode> getJITCode() { return m_jitCode; }
	JITCode::JITType jitType() const { return JITCode::jitTypeFor(m_jitCode); }
	JITCode::JITType getJITType() const { return jitType(); }
    bool hasBaselineJITProfiling() const
    {
        return jitType() == JITCode::BaselineJIT;
    }
	virtual CodeBlock* replacement() = 0;

    virtual DFG::CapabilityLevel capabilityLevelInternal() = 0;
    DFG::CapabilityLevel capabilityLevel()
    {
        DFG::CapabilityLevel result = capabilityLevelInternal();
        m_capabilityLevelState = result;
        return result;
    }
    DFG::CapabilityLevel capabilityLevelState() { return m_capabilityLevelState; }

    bool hasOptimizedReplacement(JITCode::JITType typeToReplace)
	{
		return JITCode::isHigherTier(replacement()->getJITType(), typeToReplace);
	}

    bool hasOptimizedReplacement() // the typeToReplace is my JITType
    {
        return hasOptimizedReplacement(jitType());
    }

    void jettison(ReoptimizationMode = DontCountReoptimization);

	ScriptExecutable* ownerExecutable() const { return m_ownerExecutable.get(); }

	JSGlobalData* globalData() { return m_vm; }
	JSGlobalData* vm() { return m_vm; }

	void setThisRegister(int thisRegister) { m_thisRegister = thisRegister; }
	int thisRegister() const { return m_thisRegister; }

	void setUsesEval(bool usesEval) { m_usesEval = usesEval; }
	bool usesEval() const { return m_usesEval; }
    SourceParseMode parseMode() const { return m_parseMode; };
	bool isArrowFunction() const { return m_parseMode == SourceParseMode::ArrowFunctionMode; }
	DerivedContextType derivedContextType() const { return static_cast<DerivedContextType>(m_derivedContextType); }
	EvalContextType evalContextType() const { return static_cast<EvalContextType>(m_evalContextType); }
    bool isArrowFunctionContext() const { return m_isArrowFunctionContext; }
    bool isClassContext() const { return m_isClassContext; }

    void setScopeRegister(VirtualRegister_ scopeRegister)
    {
        ASSERT(scopeRegister.isLocal() || !scopeRegister.isValid());
        m_scopeRegister = scopeRegister;
    }

    VirtualRegister_ scopeRegister() const
    {
        return m_scopeRegister;
    }

    unsigned numberOfArrayAllocationProfiles() { return m_arrayAllocationProfiles.size(); }
    unsigned numberOfValueProfiles() { return m_valueProfiles.size(); }

    unsigned numberOfObjectAllocationProfiles() { return m_objectAllocationProfiles.size(); }

	CodeType codeType() const { return m_codeType; }
	PutPropertySlot::Context putByIdContext() const
	{
		if (codeType() == EvalCode)
			return PutPropertySlot::PutByIdEval;
		return PutPropertySlot::PutById;
	}

	SourceProvider* source() const { return m_source.get(); }
	unsigned sourceOffset() const { return m_sourceOffset; }
    unsigned firstLineColumnOffset() const { return m_firstLineColumnOffset; }

	size_t numberOfJumpTargets() const { return m_jumpTargets.size(); }
	void addJumpTarget(unsigned jumpTarget) { m_jumpTargets.append(jumpTarget); }
	unsigned jumpTarget(int index) const { return m_jumpTargets[index]; }
	unsigned lastJumpTarget() const { return m_jumpTargets.last(); }

	void clearEvalCache();

	String nameForRegister(int registerNumber);

	void addPropertyAccessInstruction(unsigned propertyAccessInstruction)
	{
		m_propertyAccessInstructions.append(propertyAccessInstruction);
	}
#if ENABLE(LLINT)
	LLIntCallLinkInfo* addLLIntCallLinkInfo()
	{
		m_llintCallLinkInfos.append(LLIntCallLinkInfo());
		return &m_llintCallLinkInfos.last();
	}
#endif
	void setNumberOfByValInfos(size_t size) { m_byValInfos.resizeToFit(size); }
	size_t numberOfByValInfos() const { return m_byValInfos.size(); }
	ByValInfo& byValInfo(size_t index) { return m_byValInfos[index]; }

	unsigned numberOfArgumentValueProfiles()
	{
		ASSERT(m_numParameters >= 0);
		ASSERT(m_argumentValueProfiles.size() == static_cast<unsigned>(m_numParameters));
		return m_argumentValueProfiles.size();
	}
	ValueProfile* valueProfileForArgument(unsigned argumentIndex)
	{
		ValueProfile* result = &m_argumentValueProfiles[argumentIndex];
		ASSERT(result->m_bytecodeOffset == -1);
		return result;
	}

	ValueProfile* valueProfile(int index)
	{
		ValueProfile* result = &m_valueProfiles[index];
		ASSERT(result->m_bytecodeOffset != -1);
		return result;
	}
	ValueProfile* valueProfileForBytecodeOffset(int bytecodeOffset);
	SpeculatedType valueProfilePredictionForBytecodeOffset(int bytecodeOffset)
	{
        if (ValueProfile* valueProfile = valueProfileForBytecodeOffset(bytecodeOffset))
            return valueProfile->computeUpdatedPrediction();
        return SpecNone;
	}

	unsigned totalNumberOfValueProfiles()
	{
		return numberOfArgumentValueProfiles() + numberOfValueProfiles();
	}
	ValueProfile* getFromAllValueProfiles(unsigned index)
	{
		if (index < numberOfArgumentValueProfiles())
			return valueProfileForArgument(index);
		return valueProfile(index - numberOfArgumentValueProfiles());
	}

	RareCaseProfile* addRareCaseProfile(int bytecodeOffset)
	{
		m_rareCaseProfiles.append(RareCaseProfile(bytecodeOffset));
		return &m_rareCaseProfiles.last();
	}
	unsigned numberOfRareCaseProfiles() { return m_rareCaseProfiles.size(); }
	RareCaseProfile* rareCaseProfile(int index) { return &m_rareCaseProfiles[index]; }
	RareCaseProfile* rareCaseProfileForBytecodeOffset(int bytecodeOffset)
	{
        return binarySearch<RareCaseProfile, int>(
            m_rareCaseProfiles, m_rareCaseProfiles.size(), bytecodeOffset,
            getRareCaseProfileBytecodeOffset);
    }

	bool likelyToTakeSlowCase(int bytecodeOffset)
	{
		if (!hasBaselineJITProfiling())
			return false;
		unsigned value = rareCaseProfileForBytecodeOffset(bytecodeOffset)->m_counter;
		return value >= Options::likelyToTakeSlowCaseMinimumCount();
	}

	bool couldTakeSlowCase(int bytecodeOffset)
	{
		if (!hasBaselineJITProfiling())
			return false;
		unsigned value = rareCaseProfileForBytecodeOffset(bytecodeOffset)->m_counter;
		return value >= Options::couldTakeSlowCaseMinimumCount();
	}

	RareCaseProfile* addSpecialFastCaseProfile(int bytecodeOffset)
	{
		m_specialFastCaseProfiles.append(RareCaseProfile(bytecodeOffset));
		return &m_specialFastCaseProfiles.last();
	}
	unsigned numberOfSpecialFastCaseProfiles() { return m_specialFastCaseProfiles.size(); }
	RareCaseProfile* specialFastCaseProfile(int index) { return &m_specialFastCaseProfiles[index]; }
	RareCaseProfile* specialFastCaseProfileForBytecodeOffset(int bytecodeOffset)
	{
        return binarySearch<RareCaseProfile, int>(
            m_specialFastCaseProfiles, m_specialFastCaseProfiles.size(), bytecodeOffset,
            getRareCaseProfileBytecodeOffset);
    }
    unsigned specialFastCaseProfileCountForBytecodeOffset(int bytecodeOffset)
    {
        RareCaseProfile* profile = specialFastCaseProfileForBytecodeOffset(bytecodeOffset);
        if (!profile)
            return 0;
        return profile->m_counter;
    }

	bool couldTakeSpecialFastCase(int bytecodeOffset)
	{
		if (!hasBaselineJITProfiling())
			return false;
		unsigned specialFastCaseCount = specialFastCaseProfileCountForBytecodeOffset(bytecodeOffset);
		return specialFastCaseCount >= Options::couldTakeSlowCaseMinimumCount();
	}

	bool likelyToTakeDeepestSlowCase(int bytecodeOffset)
	{
		if (!hasBaselineJITProfiling())
			return false;
		unsigned slowCaseCount = rareCaseProfileForBytecodeOffset(bytecodeOffset)->m_counter;
		unsigned specialFastCaseCount = specialFastCaseProfileCountForBytecodeOffset(bytecodeOffset);
		unsigned value = slowCaseCount - specialFastCaseCount;
		return value >= Options::likelyToTakeSlowCaseMinimumCount();
	}

	ArrayProfile* addArrayProfile(unsigned bytecodeOffset)
	{
		m_arrayProfiles.append(ArrayProfile(bytecodeOffset));
		return &m_arrayProfiles.last();
	}
	ArrayProfile* getArrayProfile(unsigned bytecodeOffset);
	ArrayProfile* getOrAddArrayProfile(unsigned bytecodeOffset);

	// Exception handling support

	size_t numberOfExceptionHandlers() const { return m_rareData ? m_rareData->m_exceptionHandlers.size() : 0; }
	void addExceptionHandler(const HandlerInfo& hanler) { createRareDataIfNecessary(); return m_rareData->m_exceptionHandlers.append(hanler); }
	HandlerInfo& exceptionHandler(int index) { ASSERT(m_rareData); return m_rareData->m_exceptionHandlers[index]; }

    void addExpressionInfo(unsigned instructionOffset, int divot,
        int startOffset, int endOffset, unsigned line, unsigned column);

	bool hasExpressionInfo() { return m_expressionInfo.size(); }

#if ENABLE(DFG_JIT)
	Vector<CodeOrigin>& codeOrigins()
	{
        return m_jitCode->dfgCommon()->codeOrigins;
	}

	// Having code origins implies that there has been some inlining.
	bool hasCodeOrigins()
	{
        return JITCode::isOptimizingJIT(jitType());
	}

    bool canGetCodeOrigin(CallSiteIndex index)
    {
        if (!hasCodeOrigins())
            return false;
        return index.bits() < codeOrigins().size();
    }

    CodeOrigin codeOrigin(CallSiteIndex index)
    {
        return codeOrigins()[index.bits()];
    }

	bool addFrequentExitSite(const DFG::FrequentExitSite& site)
	{
		ASSERT(JITCode::isBaselineCode(getJITType()));
		return m_exitProfile.add(site);
	}

    bool hasExitSite(const DFG::FrequentExitSite& site) const
    {
    	return m_exitProfile.hasExitSite(site);
    }

	DFG::ExitProfile& exitProfile() { return m_exitProfile; }

	CompressedLazyOperandValueProfileHolder& lazyOperandValueProfiles()
	{
		return m_lazyOperandValueProfiles;
	}
#endif

	// Constant Pool

	size_t numberOfIdentifiers() const { return m_identifiers.size(); }
	void addIdentifier(const Identifier& i) { return m_identifiers.append(i); }
	Identifier& identifier(int index) { return m_identifiers[index]; }

    Vector<WriteBarrier<Unknown> >& constants() { return m_constantRegisters; }
    Vector<SourceCodeRepresentation>& constantsSourceCodeRepresentation() { return m_constantsSourceCodeRepresentation; }
	size_t numberOfConstantRegisters() const { return m_constantRegisters.size(); }
	unsigned addConstant(JSValue v, SourceCodeRepresentation sourceCodeRepresentation = SourceCodeRepresentation::Other)
	{
		unsigned result = m_constantRegisters.size();
		m_constantRegisters.append(WriteBarrier<Unknown>());
		m_constantRegisters.last().set(m_globalObject->vm(), m_ownerExecutable.get(), v);
		m_constantsSourceCodeRepresentation.append(sourceCodeRepresentation);
		return result;
	}
    unsigned addConstantLazily()
    {
        unsigned result = m_constantRegisters.size();
        m_constantRegisters.append(WriteBarrier<Unknown>());
        m_constantsSourceCodeRepresentation.append(SourceCodeRepresentation::Other);
		return result;
    }
    unsigned addConstant(LinkTimeConstant type)
    {
        unsigned result = m_constantRegisters.size();
        ASSERT(result);
        unsigned index = static_cast<unsigned>(type);
        ASSERT(index < LinkTimeConstantCount);
        m_linkTimeConstants[index] = result;
        m_constantRegisters.append(WriteBarrier<Unknown>());
        m_constantsSourceCodeRepresentation.append(SourceCodeRepresentation::Other);
        return result;
    }
    unsigned registerIndexForLinkTimeConstant(LinkTimeConstant type)
    {
        unsigned index = static_cast<unsigned>(type);
        ASSERT(index < LinkTimeConstantCount);
        return m_linkTimeConstants[index];
    }
    bool findConstant(JSValue, unsigned& result);
	unsigned addOrFindConstant(JSValue);
	WriteBarrier<Unknown>& constantRegister(int index) { return m_constantRegisters[index - FirstConstantRegisterIndex]; }
	ALWAYS_INLINE bool isConstantRegisterIndex(int index) const { return index >= FirstConstantRegisterIndex; }
	ALWAYS_INLINE JSValue getConstant(int index) const { return m_constantRegisters[index - FirstConstantRegisterIndex].get(); }
	ALWAYS_INLINE SourceCodeRepresentation constantSourceCodeRepresentation(int index) const { return m_constantsSourceCodeRepresentation[index - FirstConstantRegisterIndex]; }

	unsigned addFunctionDecl(FunctionExecutable* n)
	{
		unsigned size = m_functionDecls.size();
		m_functionDecls.append(WriteBarrier<FunctionExecutable>());
		m_functionDecls.last().set(m_globalObject->vm(), m_ownerExecutable.get(), n);
		return size;
	}
	FunctionExecutable* functionDecl(int index) { return m_functionDecls[index].get(); }
	int numberOfFunctionDecls() { return m_functionDecls.size(); }
	unsigned addFunctionExpr(FunctionExecutable* n)
	{
		unsigned size = m_functionExprs.size();
		m_functionExprs.append(WriteBarrier<FunctionExecutable>());
		m_functionExprs.last().set(m_globalObject->vm(), m_ownerExecutable.get(), n);
		return size;
	}
	FunctionExecutable* functionExpr(int index) { return m_functionExprs[index].get(); }

    void jettisonFunctionDeclsAndExprs();

	unsigned numberOfConstantBuffers() const
	{
		if (!m_rareData)
			return 0;
		return m_rareData->m_constantBuffers.size();
	}
	unsigned addConstantBuffer(const Vector<JSValue>& buffer)
	{
		createRareDataIfNecessary();
		unsigned size = m_rareData->m_constantBuffers.size();
		m_rareData->m_constantBuffers.append(buffer);
		return size;
	}
	unsigned addConstantBuffer(unsigned length)
	{
		return addConstantBuffer(Vector<JSValue>(length));
	}

	Vector<JSValue>& constantBufferAsVector(unsigned index)
	{
		ASSERT(m_rareData);
		return m_rareData->m_constantBuffers[index];
	}
	JSValue* constantBuffer(unsigned index)
	{
		return constantBufferAsVector(index).data();
	}

	JSGlobalObject* globalObject() { return m_globalObject.get(); }

	JSGlobalObject* globalObjectFor(CodeOrigin);

    BytecodeLivenessAnalysis& livenessAnalysis()
    {
        if (!m_livenessAnalysis)
            m_livenessAnalysis = adoptPtr(new BytecodeLivenessAnalysis(this));
        return *m_livenessAnalysis;
    }

    void validate();

	// Jump Tables

    size_t numberOfSwitchJumpTables() const { return m_rareData ? m_rareData->m_switchJumpTables.size() : 0; }
    SimpleJumpTable& addSwitchJumpTable() { createRareDataIfNecessary(); m_rareData->m_switchJumpTables.append(SimpleJumpTable()); return m_rareData->m_switchJumpTables.last(); }
    SimpleJumpTable& switchJumpTable(int tableIndex) { RELEASE_ASSERT(m_rareData); return m_rareData->m_switchJumpTables[tableIndex]; }
    void clearSwitchJumpTables()
    {
        if (!m_rareData)
            return;
        m_rareData->m_switchJumpTables.clear();
    }

	size_t numberOfStringSwitchJumpTables() const { return m_rareData ? m_rareData->m_stringSwitchJumpTables.size() : 0; }
	StringJumpTable& addStringSwitchJumpTable() { createRareDataIfNecessary(); m_rareData->m_stringSwitchJumpTables.append(StringJumpTable()); return m_rareData->m_stringSwitchJumpTables.last(); }
	StringJumpTable& stringSwitchJumpTable(int tableIndex) { ASSERT(m_rareData); return m_rareData->m_stringSwitchJumpTables[tableIndex]; }

    // Live callee registers at yield points.
    const FastBitVector& liveCalleeLocalsAtYield(unsigned index) const
    {
        RELEASE_ASSERT(m_rareData);
        return m_rareData->m_liveCalleeLocalsAtYield[index];
    }
    FastBitVector& liveCalleeLocalsAtYield(unsigned index)
    {
        RELEASE_ASSERT(m_rareData);
        return m_rareData->m_liveCalleeLocalsAtYield[index];
    }

	EvalCodeCache& evalCodeCache() { createRareDataIfNecessary(); return m_rareData->m_evalCodeCache; }

	enum ShrinkMode {
		// Shrink prior to generating machine code that may point directly into vectors.
		EarlyShrink,

		// Shrink after generating machine code, and after possibly creating new vectors
		// and appending to others. At this time it is not safe to shrink certain vectors
		// because we would have generated machine code that references them directly.
		LateShrink
	};
	void shrinkToFit(ShrinkMode);

	void handlePostGenerate(JSScope*, unsigned arrayAllocationProfileCount, unsigned objectAllocationProfileCount, unsigned valueProfileCount);

	// Functions for controlling when JITting kicks in, in a mixed mode
	// execution world.

	bool checkIfJITThresholdReached()
	{
		return m_llintExecuteCounter.checkIfThresholdCrossedAndSet(this);
	}

	void dontJITAnytimeSoon()
	{
		m_llintExecuteCounter.deferIndefinitely();
	}

	void jitAfterWarmUp()
	{
		m_llintExecuteCounter.setNewThreshold(Options::thresholdForJITAfterWarmUp(), this);
	}

	void jitSoon()
	{
		m_llintExecuteCounter.setNewThreshold(Options::thresholdForJITSoon(), this);
	}

	const ExecutionCounter& llintExecuteCounter() const
	{
		return m_llintExecuteCounter;
	}

	// Functions for controlling when tiered compilation kicks in. This
	// controls both when the optimizing compiler is invoked and when OSR
	// entry happens. Two triggers exist: the loop trigger and the return
	// trigger. In either case, when an addition to m_jitExecuteCounter
	// causes it to become non-negative, the optimizing compiler is
	// invoked. This includes a fast check to see if this CodeBlock has
	// already been optimized (i.e. replacement() returns a CodeBlock
	// that was optimized with a higher tier JIT than this one). In the
	// case of the loop trigger, if the optimized compilation succeeds
	// (or has already succeeded in the past) then OSR is attempted to
	// redirect program flow into the optimized code.

	// These functions are called from within the optimization triggers,
	// and are used as a single point at which we define the heuristics
	// for how much warm-up is mandated before the next optimization
	// trigger files. All CodeBlocks start out with optimizeAfterWarmUp(),
	// as this is called from the CodeBlock constructor.

	// When we observe a lot of speculation failures, we trigger a
	// reoptimization. But each time, we increase the optimization trigger
	// to avoid thrashing.
	unsigned reoptimizationRetryCounter() const;
	void countReoptimization();

    unsigned numberOfDFGCompiles();

	int32_t codeTypeThresholdMultiplier() const;

    int32_t adjustedCounterValue(int32_t desiredThreshold);

	int32_t* addressOfJITExecuteCounter()
	{
		return &m_jitExecuteCounter.m_counter;
	}

	static ptrdiff_t offsetOfJITExecuteCounter() { return OBJECT_OFFSETOF(CodeBlock, m_jitExecuteCounter) + OBJECT_OFFSETOF(ExecutionCounter, m_counter); }
	static ptrdiff_t offsetOfJITExecutionActiveThreshold() { return OBJECT_OFFSETOF(CodeBlock, m_jitExecuteCounter) + OBJECT_OFFSETOF(ExecutionCounter, m_activeThreshold); }
	static ptrdiff_t offsetOfJITExecutionTotalCount() { return OBJECT_OFFSETOF(CodeBlock, m_jitExecuteCounter) + OBJECT_OFFSETOF(ExecutionCounter, m_totalCount); }

	const ExecutionCounter& jitExecuteCounter() const { return m_jitExecuteCounter; }

	unsigned optimizationDelayCounter() const { return m_optimizationDelayCounter; }

	// Check if the optimization threshold has been reached, and if not,
	// adjust the heuristics accordingly. Returns true if the threshold has
	// been reached.
	bool checkIfOptimizationThresholdReached();

	// Call this to force the next optimization trigger to fire. This is
	// rarely wise, since optimization triggers are typically more
	// expensive than executing baseline code.
	void optimizeNextInvocation();

	// Call this to prevent optimization from happening again. Note that
	// optimization will still happen after roughly 2^29 invocations,
	// so this is really meant to delay that as much as possible. This
	// is called if optimization failed, and we expect it to fail in
	// the future as well.
	void dontOptimizeAnytimeSoon();

	// Call this to reinitialize the counter to its starting state,
	// forcing a warm-up to happen before the next optimization trigger
	// fires. This is called in the CodeBlock constructor. It also
	// makes sense to call this if an OSR exit occurred. Note that
	// OSR exit code is code generated, so the value of the execute
	// counter that this corresponds to is also available directly.
	void optimizeAfterWarmUp();

	// Call this to force an optimization trigger to fire only after
	// a lot of warm-up.
	void optimizeAfterLongWarmUp();

	// Call this to cause an optimization trigger to fire soon, but
	// not necessarily the next one. This makes sense if optimization
	// succeeds. Successfuly optimization means that all calls are
	// relinked to the optimized code, so this only affects call
	// frames that are still executing this CodeBlock. The value here
	// is tuned to strike a balance between the cost of OSR entry
	// (which is too high to warrant making every loop back edge to
	// trigger OSR immediately) and the cost of executing baseline
	// code (which is high enough that we don't necessarily want to
	// have a full warm-up). The intuition for calling this instead of
	// optimizeNextInvocation() is for the case of recursive functions
	// with loops. Consider that there may be N call frames of some
	// recursive function, for a reasonably large value of N. The top
	// one triggers optimization, and then returns, and then all of
	// the others return. We don't want optimization to be triggered on
	// each return, as that would be superfluous. It only makes sense
	// to trigger optimization if one of those functions becomes hot
	// in the baseline code.
	void optimizeSoon();

	uint32_t osrExitCounter() const { return m_osrExitCounter; }

	void countOSRExit() { m_osrExitCounter++; }

	uint32_t* addressOfOSRExitCounter() { return &m_osrExitCounter; }

	static ptrdiff_t offsetOfOSRExitCounter() { return OBJECT_OFFSETOF(CodeBlock, m_osrExitCounter); }

#if ENABLE(JIT)
	uint32_t adjustedExitCountThreshold(uint32_t desiredThreshold);
	uint32_t exitCountThresholdForReoptimization();
	uint32_t exitCountThresholdForReoptimizationFromLoop();
	bool shouldReoptimizeNow();
	bool shouldReoptimizeFromLoopNow();
#endif

	bool shouldOptimizeNow();
	void updateAllValueProfilePredictions();
	void updateAllArrayPredictions();
	void updateAllPredictions();

    void setInstallTime(double installTime) { m_installTime = installTime; }

    unsigned frameRegisterCount();

	// FIXME: Make these remaining members private.

	int m_numCalleeLocals;
	int m_numVars;
	unsigned m_shouldAlwaysBeInlined;
	unsigned m_allTransitionsHaveBeenMarked : 1; // Initialized and used on every GC.

    void clearExceptionHandlers()
    {
        if (m_rareData)
            m_rareData->m_exceptionHandlers.clear();
    }

    void appendExceptionHandler(const HandlerInfo& handler)
    {
        createRareDataIfNecessary(); // We may be handling the exception of an inlined call frame.
        m_rareData->m_exceptionHandlers.append(handler);
    }

protected:
	virtual void visitWeakReferences(SlotVisitor&);
	virtual void finalizeUnconditionally(JSGlobalData&);

#if ENABLE(DFG_JIT)
	void tallyFrequentExitSites();
#else
	void tallyFrequentExitSites() { }
#endif

private:
	friend class CodeBlockSet;

    void noticeIncomingCall(ExecState* callerFrame);

	double optimizationThresholdScalingFactor();

	void updateAllPredictionsAndCountLiveness(unsigned& numberOfLiveNonArgumentValueProfiles, unsigned& numberOfSamplesInProfiles);

    void replaceConstant(int index, JSValue value)
    {
        ASSERT(isConstantRegisterIndex(index) && static_cast<size_t>(index - FirstConstantRegisterIndex) < m_constantRegisters.size());
        m_constantRegisters[index - FirstConstantRegisterIndex].set(m_globalObject->vm(), m_ownerExecutable.get(), value);
    }

    void dumpBytecode(
        PrintStream&, ExecState*, const Instruction* begin, const Instruction*&,
        const StubInfoMap& = StubInfoMap(), const CallLinkInfoMap& = CallLinkInfoMap());

    CString registerName(int r) const;
    CString constantName(int index) const;
    void printUnaryOp(PrintStream&, ExecState*, int location, const Instruction*&, const char* op);
    void printBinaryOp(PrintStream&, ExecState*, int location, const Instruction*&, const char* op);
    void printConditionalJump(PrintStream&, ExecState*, const Instruction*, const Instruction*&, int location, const char* op);
    void printGetByIdOp(PrintStream&, ExecState*, int location, const Instruction*&);
    void printGetByIdCacheStatus(PrintStream&, ExecState*, int location, const StubInfoMap&);
    enum CacheDumpMode { DumpCaches, DontDumpCaches };
    void printCallOp(PrintStream&, int location, const Instruction*&, const char* op, CacheDumpMode, bool& hasPrintedProfiling, const CallLinkInfoMap&);
    void printPutByIdOp(PrintStream&, int location, const Instruction*&, const char* op);
    void printLocationAndOp(PrintStream& out, int location, const Instruction*&, const char* op);
    void printLocationOpAndRegisterOperand(PrintStream& out, int location, const Instruction*& it, const char* op, int operand);

    bool shouldVisitStrongly();

    void propagateTransitions(SlotVisitor&);
    void determineLiveness(SlotVisitor&);

	void stronglyVisitStrongReferences(SlotVisitor&);
	void stronglyVisitWeakReferences(SlotVisitor&);

    double timeSinceInstall()
    {
        return WTF::monotonicallyIncreasingTime() - m_installTime;
    }

	void createRareDataIfNecessary()
	{
		if (!m_rareData)
			m_rareData = adoptPtr(new RareData);
	}

#if ENABLE(JIT)
	void resetStubInternal(StructureStubInfo&);
    void resetStubDuringGCInternal(StructureStubInfo&);
#endif

	int m_numParameters;

	WriteBarrier<ScriptExecutable> m_ownerExecutable;
	JSGlobalData* m_vm;

	RefCountedArray<Instruction> m_instructions;

	int m_thisRegister;
    VirtualRegister_ m_scopeRegister;
    int m_globalObjectRegister;

    unsigned m_usesEval : 1;
    unsigned m_isStrictMode : 1;
	unsigned m_isConstructor : 1;
	unsigned m_isBuiltinFunction : 1;
    unsigned m_constructorKind : 2;
    unsigned m_superBinding : 1;
    unsigned m_derivedContextType : 2;
    unsigned m_evalContextType : 2;
    unsigned m_isArrowFunctionContext : 1;
    unsigned m_isClassContext : 1;

    SourceParseMode m_parseMode;

	CodeType m_codeType;

#if ENABLE(PARALLEL_GC)
    uint8_t m_visitAggregateHasBeenCalled;
#endif

    unsigned m_mayBeExecuting : 1;

	RefPtr<SourceProvider> m_source;
	unsigned m_sourceOffset;
    unsigned m_firstLineColumnOffset;

	Vector<unsigned> m_propertyAccessInstructions;
#if ENABLE(LLINT)
	SegmentedVector<LLIntCallLinkInfo, 8> m_llintCallLinkInfos;
	SentinelLinkedList<LLIntCallLinkInfo, BasicRawSentinelNode<LLIntCallLinkInfo> > m_incomingLLIntCalls;
#endif
    RefPtr<JITCode> m_jitCode;
    Bag<StructureStubInfo> m_stubInfos;
	Vector<ByValInfo> m_byValInfos;
	Bag<CallLinkInfo> m_callLinkInfos;
	SentinelLinkedList<CallLinkInfo, BasicRawSentinelNode<CallLinkInfo> > m_incomingCalls;
    SentinelLinkedList<PolymorphicCallNode, BasicRawSentinelNode<PolymorphicCallNode>> m_incomingPolymorphicCalls;
#if ENABLE(JIT) || ENABLE(LLINT)
	OwnPtr<CompactJITCodeMap> m_jitCodeMap;
#endif
#if ENABLE(DFG_JIT)
	// This is relevant to non-DFG code blocks that serve as the profiled code block
	// for DFG code blocks.
	DFG::ExitProfile m_exitProfile;
	CompressedLazyOperandValueProfileHolder m_lazyOperandValueProfiles;
#endif
	Vector<ValueProfile> m_argumentValueProfiles;
	Vector<ValueProfile> m_valueProfiles;
	SegmentedVector<RareCaseProfile, 4> m_rareCaseProfiles;
	SegmentedVector<RareCaseProfile, 4> m_specialFastCaseProfiles;
	Vector<ArrayAllocationProfile> m_arrayAllocationProfiles;
	ArrayProfileVector m_arrayProfiles;
    Vector<ObjectAllocationProfile> m_objectAllocationProfiles;

	Vector<unsigned> m_jumpTargets;
	Vector<unsigned> m_loopTargets;

	// Constant Pool
	Vector<Identifier> m_identifiers;
	COMPILE_ASSERT(sizeof(Register) == sizeof(WriteBarrier<Unknown>), Register_must_be_same_size_as_WriteBarrier_Unknown);
	Vector<WriteBarrier<Unknown> > m_constantRegisters;
    Vector<SourceCodeRepresentation> m_constantsSourceCodeRepresentation;
    FixedArray<unsigned, LinkTimeConstantCount> m_linkTimeConstants;
	Vector<WriteBarrier<FunctionExecutable> > m_functionDecls;
	Vector<WriteBarrier<FunctionExecutable> > m_functionExprs;

	RefPtr<CodeBlock> m_alternative;

	ExecutionCounter m_llintExecuteCounter;

	ExecutionCounter m_jitExecuteCounter;
	int32_t m_totalJITExecutions;
	uint32_t m_osrExitCounter;
	uint16_t m_optimizationDelayCounter;
	uint16_t m_reoptimizationRetryCounter;

    double m_installTime;

    OwnPtr<BytecodeLivenessAnalysis> m_livenessAnalysis;

	struct RareData {
	   WTF_MAKE_FAST_ALLOCATED;
	public:
		Vector<HandlerInfo> m_exceptionHandlers;

		// Buffers used for large array literals
		Vector<Vector<JSValue> > m_constantBuffers;

		// Jump Tables
		Vector<SimpleJumpTable> m_switchJumpTables;
		Vector<StringJumpTable> m_stringSwitchJumpTables;

        Vector<FastBitVector> m_liveCalleeLocalsAtYield;

		EvalCodeCache m_evalCodeCache;

        Vector<ExpressionRangeInfo::FatPosition> m_expressionInfoFatPositions;
	};

#if COMPILER(MSVC)
	friend void WTF::deleteOwnedPtr<RareData>(RareData*);
#endif
	OwnPtr<RareData> m_rareData;

	// Expression info - present if debugging.
	Vector<ExpressionRangeInfo> m_expressionInfo;
	// Line info - present if profiling or debugging.

#if ENABLE(JIT)
	DFG::CapabilityLevel m_capabilityLevelState;
#endif
};

// Program code is not marked by any function, so we make the global object
// responsible for marking it.

class GlobalCodeBlock : public CodeBlock {
protected:
	GlobalCodeBlock(CopyParsedBlockTag, GlobalCodeBlock& other)
		: CodeBlock(CopyParsedBlock, other)
	{
	}

	GlobalCodeBlock(ScriptExecutable* ownerExecutable, CodeType codeType, const ExecutableInfo& info, JSGlobalObject* globalObject, PassRefPtr<SourceProvider> sourceProvider, unsigned sourceOffset, unsigned firstLineColumnOffset)
		: CodeBlock(ownerExecutable, codeType, info, globalObject, sourceProvider, sourceOffset, firstLineColumnOffset)
	{
	}
};

class ProgramCodeBlock : public GlobalCodeBlock {
public:
	ProgramCodeBlock(CopyParsedBlockTag, ProgramCodeBlock& other)
		: GlobalCodeBlock(CopyParsedBlock, other)
	{
	}

	ProgramCodeBlock(ProgramExecutable* ownerExecutable, CodeType codeType, const ExecutableInfo& info, JSGlobalObject* globalObject, PassRefPtr<SourceProvider> sourceProvider, unsigned firstLineColumnOffset)
		: GlobalCodeBlock(ownerExecutable, codeType, info, globalObject, sourceProvider, 0, firstLineColumnOffset)
	{
	}

#if ENABLE(JIT)
protected:
	virtual CodeBlock* replacement();
	virtual DFG::CapabilityLevel capabilityLevelInternal();
#endif
};

class ModuleProgramCodeBlock : public GlobalCodeBlock {
public:
    ModuleProgramCodeBlock(CopyParsedBlockTag, ModuleProgramCodeBlock& other)
        : GlobalCodeBlock(CopyParsedBlock, other)
		, m_moduleEnvironmentSymbolTableConstantRegisterOffset(0)
    {
    }

    ModuleProgramCodeBlock(ModuleProgramExecutable* ownerExecutable, const ExecutableInfo& info, JSGlobalObject* globalObject, PassRefPtr<SourceProvider> sourceProvider, unsigned firstLineColumnOffset)
        : GlobalCodeBlock(ownerExecutable, ModuleCode, info, globalObject, sourceProvider, 0, firstLineColumnOffset)
		, m_moduleEnvironmentSymbolTableConstantRegisterOffset(0)
    {
    }

    // This offset represents the constant register offset to the stored symbol table that represents the layout of the
    // module environment. This symbol table is created by the byte code generator since the module environment includes
    // the top-most lexical captured variables inside the module code. This means that, once the module environment is
    // allocated and instantiated from this symbol table, it is titely coupled with the specific unlinked module program
    // code block and the stored symbol table. So before executing the module code, we should not clear the unlinked module
    // program code block in the module executable. This requirement is met because the garbage collector only clears
    // unlinked code in (1) unmarked executables and (2) function executables.
    //
    // Since the function code may be executed repeatedly and the environment of each function execution is different,
    // the function code need to allocate and instantiate the environment in the prologue of the function code. On the
    // other hand, the module code is executed only once. So we can instantiate the module environment outside the module
    // code. At that time, we construct the module environment by using the symbol table that is held by the module executable.
    // The symbol table held by the executable is the cloned one from one in the unlinked code block. Instantiating the module
    // environment before executing and linking the module code is required to link the imported bindings between the modules.
    //
    // The unlinked module program code block only holds the pre-cloned symbol table in its constant register pool. It does
    // not hold the instantiated module environment. So while the module environment requires the specific unlinked module
    // program code block, the unlinked module code block can be used for the module environment instantiated from this
    // unlinked code block. There is 1:N relation between the unlinked module code block and the module environments. So the
    // unlinked module program code block can be cached.
    //
    // On the other hand, the linked code block for the module environment includes the resolved references to the imported
    // bindings. The imported binding references the other module environment, so the linked code block is titly coupled
    // with the specific set of the module environments. Thus, the linked code block should not be cached.
    int moduleEnvironmentSymbolTableConstantRegisterOffset() { return m_moduleEnvironmentSymbolTableConstantRegisterOffset; }
    void setModuleEnvironmentSymbolTableConstantRegisterOffset(int offset)
    {
        m_moduleEnvironmentSymbolTableConstantRegisterOffset = offset;
    }

#if ENABLE(JIT)
protected:
    virtual CodeBlock* replacement() OVERRIDE;
    virtual DFG::CapabilityLevel capabilityLevelInternal() OVERRIDE;
#endif

private:
    int m_moduleEnvironmentSymbolTableConstantRegisterOffset;
};

class EvalCodeBlock : public GlobalCodeBlock {
public:
	EvalCodeBlock(CopyParsedBlockTag, EvalCodeBlock& other)
		: GlobalCodeBlock(CopyParsedBlock, other)
		, m_variables(other.m_variables)
	{
	}

	EvalCodeBlock(EvalExecutable* ownerExecutable, const ExecutableInfo& info, JSGlobalObject* globalObject, PassRefPtr<SourceProvider> sourceProvider)
		: GlobalCodeBlock(ownerExecutable, EvalCode, info, globalObject, sourceProvider, 0, 1)
	{
	}

	const Identifier& variable(unsigned index) { return m_variables[index]; }
	unsigned numVariables() { return m_variables.size(); }
	void adoptVariables(Vector<Identifier>& variables)
	{
		ASSERT(m_variables.isEmpty());
		m_variables.swap(variables);
	}

#if ENABLE(JIT)
protected:
	virtual CodeBlock* replacement();
	virtual DFG::CapabilityLevel capabilityLevelInternal();
#endif

private:
	Vector<Identifier> m_variables;
};

class FunctionCodeBlock : public CodeBlock {
public:
	FunctionCodeBlock(CopyParsedBlockTag, FunctionCodeBlock& other)
		: CodeBlock(CopyParsedBlock, other)
	{
	}

	FunctionCodeBlock(FunctionExecutable* ownerExecutable, CodeType codeType, const ExecutableInfo& info, JSGlobalObject* globalObject, PassRefPtr<SourceProvider> sourceProvider, unsigned sourceOffset, unsigned firstLineColumnOffset)
		: CodeBlock(ownerExecutable, codeType, info, globalObject, sourceProvider, sourceOffset, firstLineColumnOffset)
	{
	}

#if ENABLE(JIT)
protected:
	virtual CodeBlock* replacement();
	virtual DFG::CapabilityLevel capabilityLevelInternal();
#endif
};

inline CodeBlock* baselineCodeBlockForInlineCallFrame(InlineCallFrame* inlineCallFrame)
{
	ASSERT(inlineCallFrame);
	ExecutableBase* executable = inlineCallFrame->executable.get();
	ASSERT(executable->structure()->classInfo() == FunctionExecutable::info());
	return static_cast<FunctionExecutable*>(executable)->baselineCodeBlockFor(inlineCallFrame->specializationKind());
}

inline CodeBlock* baselineCodeBlockForOriginAndBaselineCodeBlock(const CodeOrigin& codeOrigin, CodeBlock* baselineCodeBlock)
{
	if (codeOrigin.inlineCallFrame)
		return baselineCodeBlockForInlineCallFrame(codeOrigin.inlineCallFrame);
	return baselineCodeBlock;
}

inline Register& ExecState::r(int index)
{
	CodeBlock* codeBlock = this->codeBlock();
	if (codeBlock->isConstantRegisterIndex(index))
		return *reinterpret_cast<Register*>(&codeBlock->constantRegister(index));
	return this[index];
}

inline Register& ExecState::r(VirtualRegister_ reg)
{
    return r(reg.offset());
}

inline Register& ExecState::uncheckedR(int index)
{
	ASSERT(index < FirstConstantRegisterIndex);
	return this[index];
}

inline Register& ExecState::uncheckedR(VirtualRegister_ reg)
{
    return uncheckedR(reg.offset());
}

inline void CodeBlockSet::mark(void* candidateCodeBlock)
{
	// We have to check for 0 and -1 because those are used by the HashMap as markers.
	uintptr_t value = reinterpret_cast<uintptr_t>(candidateCodeBlock);

	// This checks for both of those nasty cases in one go.
	// 0 + 1 = 1
	// -1 + 1 = 0
	if (value + 1 <= 1)
		return;

	HashSet<CodeBlock*>::iterator iter = m_set.find(static_cast<CodeBlock*>(candidateCodeBlock));
	if (iter == m_set.end())
		return;

    mark(*iter);
}

inline void CodeBlockSet::mark(CodeBlock* codeBlock)
{
    if (!codeBlock)
        return;

    if (codeBlock->m_mayBeExecuting)
        return;

    codeBlock->m_mayBeExecuting = true;
#if ENABLE(GGC)
    m_currentlyExecuting.append(codeBlock);
#endif
}

} // namespace JSC

#endif // CodeBlock_h
