mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-01 14:45:29 +00:00
522 lines
22 KiB
C++
522 lines
22 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
|
*
|
|
* The contents of this file are subject to the Netscape Public License
|
|
* Version 1.0 (the "NPL"); you may not use this file except in
|
|
* compliance with the NPL. You may obtain a copy of the NPL at
|
|
* http://www.mozilla.org/NPL/
|
|
*
|
|
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
|
* for the specific language governing rights and limitations under the
|
|
* NPL.
|
|
*
|
|
* The Initial Developer of this code under the NPL is Netscape
|
|
* Communications Corporation. Portions created by Netscape are
|
|
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
|
* Reserved.
|
|
*/
|
|
#ifndef BYTECODEGRAPH_H
|
|
#define BYTECODEGRAPH_H
|
|
|
|
#include "DoublyLinkedList.h"
|
|
#include "JavaBytecodes.h"
|
|
#include "TranslationEnv.h"
|
|
#include "VerificationEnv.h"
|
|
#include "ControlGraph.h"
|
|
#include "ClassFileSummary.h"
|
|
#include "LogModule.h"
|
|
#include "CheckedUnion.h"
|
|
|
|
//
|
|
// Invariants for a BytecodeGraph:
|
|
//
|
|
// 1. The BytecodeGraph starts with the beginBlock BytecodeBlock.
|
|
//
|
|
// 2. The BytecodeGraph contains exactly one EndBlock.
|
|
// That block has no bytecodes and no successors.
|
|
//
|
|
// 3. Every BytecodeBlock whose subkind is not skForward contains at least one bytecode.
|
|
// A BytecodeBlock's subkind is skNormal unless specified otherwise below.
|
|
// The EndBlock and CatchBlocks contain no bytecodes.
|
|
//
|
|
// 4. The BytecodeGraph contains at most one BytecodeBlock that contains a return instruction
|
|
// (return, ireturn, areturn, etc.). The return instruction must be the only one in that
|
|
// BytecodeBlock. That BytecodeBlock must have exactly one successor, the EndBlock, and
|
|
// no exceptional successors. That BytecodeBlock's subkind must be skReturn.
|
|
//
|
|
// 5. An instruction of kind bckIf can only occur if it is the last one in a BytecodeBlock.
|
|
// That BytecodeBlock must have exactly two successors, the first of which is the false
|
|
// branch and the second the true branch.
|
|
//
|
|
// 6. An instruction of kind bckGoto or bckGoto_W may occur only if it is the last one in a
|
|
// BytecodeBlock. That BytecodeBlock must have exactly one successor.
|
|
//
|
|
// 7. An instruction of kind bckTableSwitch or bckLookupSwitch may occur only if it is the
|
|
// last one in a BytecodeBlock. That BytecodeBlock must have n+1 successors, where n
|
|
// is the number of cases. The first successor is the default, while the remaining ones
|
|
// correspond to the cases in the order they are listed in the tableswitch or lookupswitch
|
|
// instruction.
|
|
//
|
|
// 8. An instruction of kind bckThrow may occur only if it is the last one in a
|
|
// BytecodeBlock. That BytecodeBlock must have no successors.
|
|
//
|
|
// 9. A jsr (or jsr_w) instruction must be the only one in its BytecodeBlock. That BytecodeBlock
|
|
// must have either one or two successors and no exceptional successors. The first successor
|
|
// is the first BytecodeBlock of the subroutine (also called the subroutine's header).
|
|
// The second successor, if present, is the BytecodeBlock containing instructions after the jsr.
|
|
// The second successor is absent if verification determines that the subroutine never returns
|
|
// via a BytecodeBlock of kind skRet. The jsr BytecodeBlock's subkind must be skJsr if it has
|
|
// two successors or skJsrNoRet if it has one successor.
|
|
//
|
|
// 10. A ret (or wide ret) instruction must be the only one in its BytecodeBlock. That BytecodeBlock
|
|
// must have no successors and no exceptional successors. This BytecodeBlock's subkind must be
|
|
// skRet.
|
|
//
|
|
// 11. A BytecodeBlock with subkind skForward must not have any instructions. That BytecodeBlock
|
|
// must have exactly one successor and no exceptional successors and is treated as an
|
|
// unconditional branch to that one successor.
|
|
//
|
|
// 12. No BytecodeBlock may contain an instruction of kind bckIllegal.
|
|
//
|
|
// 13. Every BytecodeBlock that ends with one of the remaining instructions (kinds bckNormal
|
|
// or bckExc) must have exactly one successor.
|
|
//
|
|
// 14. Exceptional successors are only allowed in BytecodeBlocks that do not contain return,
|
|
// ret, or jsr instructions. Every exceptional successor must be either a CatchBlock or the
|
|
// EndBlock.
|
|
//
|
|
// 15. Non-exceptional successors may not refer to a CatchBlock.
|
|
//
|
|
// 16. The one successor of a CatchBlock must be a BytecodeBlock. That BytecodeBlock's catchBlock
|
|
// must point back to that CatchBlock.
|
|
//
|
|
|
|
class BytecodeGraph;
|
|
struct BytecodeBlock;
|
|
struct BasicBlock: DoublyLinkedEntry<BasicBlock> // Links to other BasicBlocks in the same graph
|
|
{
|
|
// Persistent fields
|
|
enum Kind {bbEnd, bbBytecode, bbCatch};
|
|
enum StackNormalization {snNoChange, sn0, sn1, sn2}; // Number of words to leave on the stack when entering a BasicBlock.
|
|
// snNoChange means to leave the stack as is (the normal case);
|
|
// sn0, sn1, and sn2 mean to leave only the *top* 0, 1, or 2 words on the stack.
|
|
// These are needed so we can combine all return bytecodes into one block.
|
|
|
|
const Kind kind ENUM_8; // Kind of this BasicBlock (EndBlock, BytecodeBlock, or CatchBlock)
|
|
const StackNormalization stackNormalization ENUM_8; // Number of words to leave on the stack when entering this BasicBlock
|
|
BasicBlock **successorsBegin; // Array of pointers to successors (nil if this is the end block)
|
|
BasicBlock **successorsEnd; // Last normal successor pointer + 1; (nil if this is the end block)
|
|
// also first exceptional successor pointer
|
|
BasicBlock **handlersEnd; // Last exceptional successor pointer + 1 (nil if this is the end block;
|
|
#ifdef DEBUG // same as successorsEnd if this is a catch block)
|
|
BasicBlock **successorsPhysicalEnd; // End of storage allocated for this successors array
|
|
#endif
|
|
|
|
// Fields computed by depthFirstSearch
|
|
enum {unmarked = -3, unvisited = -2, unnumbered = -1};
|
|
Int32 dfsNum; // Serial number assigned by depth-first search (-3 is unmarked, -2 is unvisited, -1 is unnumbered)
|
|
Uint32 nPredecessors; // Number of BasicBlock successor pointers that refer to this BasicBlock
|
|
// (often different from the number of ControlNodes that jump to this
|
|
// BasicBlock's ControlNodes because some BasicBlocks may be discovered
|
|
// to be dead and hence generate no ControlNodes, while others may generate
|
|
// code that has multiple branches to their successors.)
|
|
// The beginBlock pointer is also considered to be a successor pointer (so
|
|
// nPredecessors of the first block is always at least one).
|
|
// The implicit exception edges going to the EndBlock are not counted
|
|
#ifdef DEBUG // in the end BasicBlock's nPredecessors.
|
|
bool hasIncomingBackEdges; // True if this block has incoming backward edges
|
|
#endif
|
|
|
|
private:
|
|
// Temporary fields for verification
|
|
struct VerificationTemps
|
|
{
|
|
Uint32 generation; // Number of last dataflow pass to have changed verificationEnvIn; 0 if none yet
|
|
VerificationEnv verificationEnvIn; // State of locals and stack at beginning of block
|
|
BytecodeBlock *subroutineHeader; // If this is a ret block, points to the entry point (header) of the subroutine;
|
|
// nil if not known or this is not a ret block.
|
|
BytecodeBlock *subroutineRet; // If this is a subroutine header, points to the ret block of that subroutine;
|
|
// nil if the ret block hasn't been found yet or this is not a subroutine header.
|
|
union {
|
|
BasicBlock *clone; // The copy of this BasicBlock, temporarily stored here while copying a subgraph of this graph
|
|
bool recompute; // True if verificationEnvIn has changed since it was last propagated to successors
|
|
};
|
|
|
|
VerificationTemps(VerificationEnv::Common &c):
|
|
generation(0), verificationEnvIn(c), subroutineHeader(0), subroutineRet(0), recompute(false) {}
|
|
VerificationTemps(const VerificationEnv &env, Function1<BytecodeBlock *, BytecodeBlock *> &translator,
|
|
BytecodeBlock *subroutineHeader, BytecodeBlock *subroutineRet):
|
|
generation(0), verificationEnvIn(env, translator), subroutineHeader(subroutineHeader), subroutineRet(subroutineRet) {}
|
|
};
|
|
|
|
// Temporary fields for translation into a primitive graph
|
|
struct TranslationTemps
|
|
{
|
|
Uint32 nSeenPredecessors; // Number of already seen BasicBlock successor pointers that refer to this BasicBlock
|
|
TranslationEnv translationEnvIn; // State of locals and stack at beginning of block
|
|
// For efficiency, the end block's envIn contains information only about memory bindings.
|
|
bool envInInitialized BOOL_8; // True if envIn has already been initialized; if false, no ControlNodes point to
|
|
#ifdef DEBUG // firstControlNode yet.
|
|
bool generatedControlNodes BOOL_8; // True if ControlNodes have already been generated or optimized out for this BasicBlock
|
|
#endif
|
|
mutable ControlNode *firstControlNode; // First ControlNode generated for this BasicBlock or nil if none yet or optimized out
|
|
DoublyLinkedList<ControlEdge> predecessors; // List of predecessors of this block's first generated control node
|
|
// (Moved into firstControlNode when the ControlNodes for this BasicBlock are created.)
|
|
TranslationTemps(TranslationCommonEnv &commonEnv);
|
|
};
|
|
|
|
CheckedUnion2(VerificationTemps, TranslationTemps) temps;
|
|
public:
|
|
|
|
BasicBlock(BytecodeGraph &bytecodeGraph, Kind kind, StackNormalization stackNormalization);
|
|
|
|
bool hasKind(Kind k) const {return k == kind;}
|
|
Uint32 nSuccessors() const {return successorsEnd - successorsBegin;}
|
|
BytecodeBlock &getSuccessor(Uint32 n) const;
|
|
|
|
// Accessors for temporary fields for verification
|
|
void initVerification(VerificationEnv::Common &c);
|
|
void initVerification(BasicBlock &src, Function1<BytecodeBlock *, BytecodeBlock *> &translator);
|
|
Uint32 &getGeneration() {return temps.getVerificationTemps().generation;}
|
|
VerificationEnv &getVerificationEnvIn() {return temps.getVerificationTemps().verificationEnvIn;}
|
|
BytecodeBlock *&getSubroutineHeader() {return temps.getVerificationTemps().subroutineHeader;}
|
|
BytecodeBlock *&getSubroutineRet() {return temps.getVerificationTemps().subroutineRet;}
|
|
BasicBlock *&getClone() {return temps.getVerificationTemps().clone;}
|
|
bool &getRecompute() {return temps.getVerificationTemps().recompute;}
|
|
|
|
// Accessors for temporary fields for primitive graph translation
|
|
void initTranslation(TranslationCommonEnv &commonEnv);
|
|
Uint32 &getNSeenPredecessors() {return temps.getTranslationTemps().nSeenPredecessors;}
|
|
bool &getEnvInInitialized() {return temps.getTranslationTemps().envInInitialized;}
|
|
#ifdef DEBUG
|
|
bool getGeneratedControlNodes() const {return temps.getTranslationTemps().generatedControlNodes;}
|
|
bool &getGeneratedControlNodes() {return temps.getTranslationTemps().generatedControlNodes;}
|
|
#endif
|
|
ControlNode *&getFirstControlNode() const {return temps.getTranslationTemps().firstControlNode;}
|
|
DoublyLinkedList<ControlEdge> &getPredecessors() {return temps.getTranslationTemps().predecessors;}
|
|
public:
|
|
TranslationEnv &getTranslationEnvIn() {return temps.getTranslationTemps().translationEnvIn;}
|
|
const TranslationEnv &getTranslationEnvIn() const {return temps.getTranslationTemps().translationEnvIn;}
|
|
|
|
// Debugging
|
|
#ifdef DEBUG_LOG
|
|
int printRef(LogModuleObject &f, const BytecodeGraph &bg) const;
|
|
void printPretty(LogModuleObject &f, const BytecodeGraph &bg, const ConstantPool *c, int margin) const;
|
|
#endif
|
|
};
|
|
|
|
|
|
struct EndBlock: BasicBlock
|
|
{
|
|
EndBlock(BytecodeGraph &bytecodeGraph);
|
|
};
|
|
|
|
|
|
struct CatchBlock: BasicBlock
|
|
{
|
|
private:
|
|
BasicBlock *successor; // The handler of exceptions caught here
|
|
public:
|
|
|
|
CatchBlock(BytecodeGraph &bytecodeGraph, BytecodeBlock &handler);
|
|
CatchBlock(BytecodeGraph &bytecodeGraph, const CatchBlock &src);
|
|
|
|
BytecodeBlock &getHandler() const;
|
|
};
|
|
|
|
|
|
struct BytecodeBlock: BasicBlock
|
|
{
|
|
enum Subkind
|
|
{
|
|
skNormal, // A BytecodeBlock that does not contain any return, ret, or jsr instructions
|
|
skReturn, // A BytecodeBlock consisting entirely of one of the return instructions
|
|
skJsr, // A BytecodeBlock consisting entirely of a jsr or jsr_w instruction whose subroutine may or may not return
|
|
skJsrNoRet, // A BytecodeBlock consisting entirely of a jsr or jsr_w instruction whose subroutine is known never to return
|
|
skRet, // A BytecodeBlock consisting entirely of a ret or wide ret instruction
|
|
skForward // A formerly skRet BytecodeBlock that is known to unconditionally branch to its one successor
|
|
};
|
|
|
|
const bytecode *const bytecodesBegin; // Pointer to first bytecode in this block
|
|
const bytecode *bytecodesEnd; // End of last bytecode + 1
|
|
CatchBlock *catchBlock; // If a catch handler begins at bytecodesBegin, a CatchBlock that points back to
|
|
// this block; nil otherwise.
|
|
const Class **exceptionClasses; // Array of exception classes; an exception matching the nth exception class
|
|
const Class **exceptionClassesEnd; // would transfer control to the nth exceptional successor
|
|
Subkind subkind ENUM_8; // Description of contents of this BytecodeBlock
|
|
|
|
BytecodeBlock(BytecodeGraph &bytecodeGraph, const bytecode *bytecodesBegin, StackNormalization stackNormalization);
|
|
BytecodeBlock(BytecodeGraph &bytecodeGraph, const BytecodeBlock &src);
|
|
|
|
bool hasSubkind(Subkind sk) const {return sk == subkind;}
|
|
bool handlersForbidden() const;
|
|
|
|
void initSuccessors(BasicBlock **successors, Uint32 nSuccessors, Int32 nActiveHandlers, Pool &bytecodeGraphPool);
|
|
BasicBlock **transformToJsrNoRet();
|
|
void transformToForward(BasicBlock **successor);
|
|
};
|
|
|
|
|
|
class BytecodeGraph
|
|
{
|
|
public:
|
|
// Persistent fields
|
|
Pool &bytecodeGraphPool; // Pool for allocating this BytecodeGraph's nodes (blocks)
|
|
ClassFileSummary &classFileSummary; // Java class file descriptor
|
|
Method& method; // The method this
|
|
// BytecodeGraph represents
|
|
const Uint32 nLocals; // Number of words of local variables
|
|
const Uint32 stackSize; // Number of words of local stack space
|
|
const bool isInstanceMethod BOOL_8; // True if this method has a "this" argument
|
|
const bool isSynchronized BOOL_8; // True if this method is synchronized
|
|
const uint nArguments; // Number of incoming arguments (including "this")
|
|
const ValueKind *const argumentKinds; // Kinds of incoming arguments (including "this")
|
|
const ValueKind resultKind; // Kind of result
|
|
const bytecode *const bytecodesBegin; // Pointer to first bytecode in this function (must be word-aligned)
|
|
const bytecode *const bytecodesEnd; // End of last bytecode in this function + 1
|
|
const Uint32 bytecodesSize; // bytecodesEnd - bytecodesBegin
|
|
const Uint32 nExceptionEntries; // Number of exception table entries
|
|
const ExceptionItem *const exceptionEntries;// Exception table
|
|
BytecodeBlock *beginBlock; // Starting basic block in function
|
|
EndBlock *endBlock; // The end BasicBlock
|
|
BytecodeBlock *returnBlock; // The return BytecodeBlock or nil if none
|
|
private:
|
|
DoublyLinkedList<BasicBlock> blocks; // List of basic blocks (may include unreachable blocks)
|
|
Uint32 nBlocks; // Number of reachable basic blocks
|
|
|
|
// Fields computed by depthFirstSearch
|
|
BasicBlock **dfsList; // Array of reachable basic blocks ordered by depth-first search;
|
|
// each block's dfsNum is an index into this array.
|
|
const bytecode returnBytecode; // The kind of return bytecode that corresponds to resultKind
|
|
bool hasBackEdges BOOL_8; // True if this graph contains a cycle
|
|
bool hasJSRs BOOL_8; // True if this graph contains a jsr or jsr_w instruction
|
|
|
|
public:
|
|
BytecodeGraph(ClassFileSummary &cfs, Pool &bytecodeGraphPool, bool isInstanceMethod, bool isSynchronized,
|
|
uint nArguments, const ValueKind *argumentKinds, ValueKind resultKind, Uint32 nLocals, Uint32 stackSize,
|
|
const bytecode *bytecodesBegin, Uint32 bytecodesSize, Uint32 nExceptionEntries,
|
|
const ExceptionItem *exceptionEntries, Method& method);
|
|
private:
|
|
BytecodeGraph(const BytecodeGraph &); // Copying forbidden
|
|
void operator=(const BytecodeGraph &); // Copying forbidden
|
|
public:
|
|
|
|
BasicBlock **getDFSList() const {assert(dfsList); return dfsList;}
|
|
Uint32 getDFSListLength() const {assert(dfsList); return nBlocks;}
|
|
void invalidateDFSList() {DEBUG_ONLY(dfsList = 0);}
|
|
void addBlock(BasicBlock &block) {blocks.addLast(block); invalidateDFSList();}
|
|
|
|
static const bytecode *switchAlign(const bytecode *bc);
|
|
|
|
private:
|
|
BytecodeBlock &followGotos(Uint32 initialOffset, Int32 displacement, BytecodeBlock **blocks);
|
|
BytecodeBlock ¬eBlockBoundary(Uint32 offset, BytecodeBlock **blocks);
|
|
void noteExceptionBoundaries(BytecodeBlock **blocks, Int32 *activeHandlerDeltas);
|
|
const bytecode *noteTableSwitchTargets(const bytecode *bc, BytecodeBlock **blocks);
|
|
const bytecode *noteLookupSwitchTargets(const bytecode *bc, BytecodeBlock **blocks);
|
|
const bytecode *recordTableSwitchTargets(const bytecode *bc, BytecodeBlock **blocks, BasicBlock **&successors,
|
|
Uint32 &nSuccessors, Int32 nActiveHandlers);
|
|
const bytecode *recordLookupSwitchTargets(const bytecode *bc, BytecodeBlock **blocks, BasicBlock **&successors,
|
|
Uint32 &nSuccessors, Int32 nActiveHandlers);
|
|
void recordHandlerTargets(BytecodeBlock **blocks);
|
|
void verifyNoBoundariesBetween(const bytecode *bc1, const bytecode *bc2, BytecodeBlock **blocks) const;
|
|
void createBlocks(Pool &tempPool);
|
|
bool depthFirstSearch(Pool &tempPool);
|
|
void splitCatchNodes();
|
|
public:
|
|
void divideIntoBlocks(Pool &tempPool);
|
|
|
|
#ifdef DEBUG_LOG
|
|
bool dfsBlockNumbersValid() const {return dfsList != 0;}
|
|
void print(LogModuleObject &f, const ConstantPool *c) const;
|
|
#endif
|
|
};
|
|
|
|
|
|
// --- INLINES ----------------------------------------------------------------
|
|
|
|
|
|
//
|
|
// Initialize BasicBlock fields used for translation into a primitive graph.
|
|
//
|
|
inline BasicBlock::TranslationTemps::TranslationTemps(TranslationCommonEnv &commonEnv):
|
|
nSeenPredecessors(0),
|
|
translationEnvIn(commonEnv),
|
|
envInInitialized(false),
|
|
firstControlNode(0)
|
|
{
|
|
#ifdef DEBUG
|
|
generatedControlNodes = false;
|
|
#endif
|
|
}
|
|
|
|
|
|
//
|
|
// Initialize this BasicBlock contained in the given BytecodeGraph.
|
|
//
|
|
inline BasicBlock::BasicBlock(BytecodeGraph &bytecodeGraph, Kind kind, StackNormalization stackNormalization):
|
|
kind(kind),
|
|
stackNormalization(stackNormalization)
|
|
{
|
|
bytecodeGraph.addBlock(*this);
|
|
}
|
|
|
|
|
|
//
|
|
// Return the nth regular (non-exceptional) successor.
|
|
// Don't call this to get the successor of the return node, because it is not
|
|
// a BytecodeBlock.
|
|
//
|
|
inline BytecodeBlock &BasicBlock::getSuccessor(Uint32 n) const
|
|
{
|
|
assert(n < nSuccessors() && successorsBegin[n]->hasKind(bbBytecode));
|
|
return *static_cast<BytecodeBlock *>(successorsBegin[n]);
|
|
}
|
|
|
|
|
|
//
|
|
// Prepare this BasicBlock for verification.
|
|
//
|
|
inline void BasicBlock::initVerification(VerificationEnv::Common &c)
|
|
{
|
|
new(temps.initVerificationTemps()) VerificationTemps(c);
|
|
}
|
|
|
|
|
|
//
|
|
// Prepare this BasicBlock for verification using a copy of src's env, subroutineHeader,
|
|
// and subroutineRet fields. Translate any BasicBlock pointers using the given
|
|
// translator. Set the generation to zero.
|
|
//
|
|
inline void BasicBlock::initVerification(BasicBlock &src, Function1<BytecodeBlock *, BytecodeBlock *> &translator)
|
|
{
|
|
new(temps.initVerificationTemps()) VerificationTemps(src.getVerificationEnvIn(), translator,
|
|
translator(src.getSubroutineHeader()), translator(src.getSubroutineRet()));
|
|
}
|
|
|
|
|
|
//
|
|
// Prepare this BasicBlock for translation into a primitive graph.
|
|
//
|
|
inline void BasicBlock::initTranslation(TranslationCommonEnv &commonEnv)
|
|
{
|
|
new(temps.initTranslationTemps()) TranslationTemps(commonEnv);
|
|
}
|
|
|
|
|
|
//
|
|
// Initialize this CatchBlock contained in the given BytecodeGraph.
|
|
// The CatchBlock's successor is given.
|
|
//
|
|
inline CatchBlock::CatchBlock(BytecodeGraph &bytecodeGraph, BytecodeBlock &handler):
|
|
BasicBlock(bytecodeGraph, bbCatch, sn0),
|
|
successor(&handler)
|
|
{
|
|
successorsBegin = &successor;
|
|
successorsEnd = &successor + 1;
|
|
handlersEnd = successorsEnd;
|
|
#ifdef DEBUG
|
|
successorsPhysicalEnd = handlersEnd;
|
|
#endif
|
|
}
|
|
|
|
|
|
//
|
|
// Make a copy of the src CatchBlock pointing to the same handler as src and add it
|
|
// to the given graph. However, do not copy or initialize the VerificationTemps or
|
|
// TranslationTemps in the copy.
|
|
//
|
|
inline CatchBlock::CatchBlock(BytecodeGraph &bytecodeGraph, const CatchBlock &src):
|
|
BasicBlock(bytecodeGraph, bbCatch, sn0),
|
|
successor(src.successor)
|
|
{
|
|
successorsBegin = &successor;
|
|
successorsEnd = &successor + 1;
|
|
handlersEnd = successorsEnd;
|
|
#ifdef DEBUG
|
|
successorsPhysicalEnd = handlersEnd;
|
|
#endif
|
|
}
|
|
|
|
|
|
//
|
|
// Return the handler passed to this CatchBlock's constructor.
|
|
//
|
|
inline BytecodeBlock &CatchBlock::getHandler() const
|
|
{
|
|
return *static_cast<BytecodeBlock *>(successor);
|
|
}
|
|
|
|
|
|
//
|
|
// Initialize this BytecodeBlock contained in the given BytecodeGraph.
|
|
// The caller should later call initSuccessors to set up this block's successors.
|
|
//
|
|
inline BytecodeBlock::BytecodeBlock(BytecodeGraph &bytecodeGraph, const bytecode *bytecodesBegin, StackNormalization stackNormalization):
|
|
BasicBlock(bytecodeGraph, bbBytecode, stackNormalization),
|
|
bytecodesBegin(bytecodesBegin),
|
|
catchBlock(0),
|
|
subkind(skNormal)
|
|
{}
|
|
|
|
|
|
//
|
|
// Return true if this block must not have any handlers and createBlocks should not
|
|
// allocates any room for handlers.
|
|
//
|
|
inline bool BytecodeBlock::handlersForbidden() const
|
|
{
|
|
return !hasSubkind(skNormal);
|
|
}
|
|
|
|
|
|
//
|
|
// Change this skJsr block to a skJsrNoRet block. Return a pointer suitable as an
|
|
// argument to transformToForward.
|
|
//
|
|
inline BasicBlock **BytecodeBlock::transformToJsrNoRet()
|
|
{
|
|
assert(hasSubkind(skJsr));
|
|
subkind = skJsrNoRet;
|
|
BasicBlock **e = successorsEnd - 1;
|
|
successorsEnd = e;
|
|
handlersEnd = e;
|
|
#ifdef DEBUG
|
|
successorsPhysicalEnd = e;
|
|
#endif
|
|
return e;
|
|
}
|
|
|
|
|
|
//
|
|
// Change this skRet block to a skForward block. successor must point to a one-word
|
|
// block of memory allocated from this bytecode graph's pool that points to this block's
|
|
// unique successor.
|
|
//
|
|
inline void BytecodeBlock::transformToForward(BasicBlock **successor)
|
|
{
|
|
assert(hasSubkind(skRet));
|
|
subkind = skForward;
|
|
successorsBegin = successor;
|
|
BasicBlock **e = successor + 1;
|
|
successorsEnd = e;
|
|
handlersEnd = e;
|
|
#ifdef DEBUG
|
|
successorsPhysicalEnd = e;
|
|
#endif
|
|
bytecodesEnd = bytecodesBegin;
|
|
}
|
|
|
|
|
|
//
|
|
// Return bc word-aligned as needed for a tableswitch or lookupswitch bytecode.
|
|
//
|
|
inline const bytecode *BytecodeGraph::switchAlign(const bytecode *bc)
|
|
{
|
|
// Assumes that bytecodesBegin is word-aligned.
|
|
return (const bytecode *)((size_t)bc + 3 & -4);
|
|
}
|
|
|
|
|
|
#endif
|