Files
avmplus/halfmoon/hm-abcgraph.cpp
dmcallis 65a0592776 Initial source code drop
Source code drop for the Actionscript virtual machine in the Adobe
Flash Player for December 2013
2013-12-02 16:04:04 -08:00

119 lines
4.0 KiB
C++

/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 2 -*- */
/* vi: set ts=2 sw=2 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
//
// hm-abcgraph.cpp: implementation code for ABC Control Flow Graphs
//
#include "hm-main.h"
#ifdef VMCFG_HALFMOON
namespace halfmoon {
AbcGraph::AbcGraph(MethodInfo* method)
: alloc0_(alloc_), blockmap_(alloc_), abc_instrs(alloc_), entry_(0)
, handlers_(0), handler_count_(0), table_(0), method(method) {
// create label at head of method's abc stream
code_pos_ = method->getMethodSignature()->abc_code_start();
entry_ = newAbcBlock(code_pos_);
if ((table_ = method->abc_exceptions()) != 0)
createTryCatchBlocks();
}
/// Create and add a label starting at pc to blockmap_,
/// if not already present.
///
AbcBlock* AbcGraph::newAbcBlock(const uint8_t* pc) {
AbcBlock* b = blockmap_.get(pc);
if (!b) {
if (enable_verbose)
method->pool()->core->console << "createBlock " << int(pc - code_pos_) << "\n";
blockmap_.put(pc, b = new (alloc0_) AbcBlock(pc));
}
return b;
}
/// Record an edge from one label to another, by adding
/// 'to' label to 'from' label's succ list. Create 'to'
/// label from target pc if necessary, and add it to
/// worklist if so.
///
void AbcGraph::addAbcEdge(AbcBlock* fm, const uint8_t* target_pc, int edge_index) {
AbcBlock* to = newAbcBlock(target_pc);
++to->num_preds;
if (target_pc <= fm->start)
to->abc_loop = true;
fm->succ_blocks[edge_index] = to;
if (enable_verbose)
method->pool()->core->console << "edge " << int(fm->start - code_pos_) << "->" << int(target_pc - code_pos_) << "\n";
}
void AbcGraph::createTryCatchBlocks() {
handler_count_ = table_->exception_count;
if (!handler_count_)
return;
handlers_ = new (alloc_) AbcBlock*[handler_count_];
for (int i = 0, n = handler_count_; i < n; ++i) {
ExceptionHandler* handler = &table_->exceptions[i];
newAbcBlock(code_pos_ + handler->from);
newAbcBlock(code_pos_ + handler->to);
handlers_[i] = newAbcBlock(code_pos_ + handler->target);
}
}
void AbcGraph::analyzeExceptions(AbcBlock* fm) {
assert(!fm->catch_blocks && !fm->max_catch_blocks);
if (!table_)
return;
int n = table_->exception_count;
const uint8_t* pc = fm->start;
fm->max_catch_blocks = n;
fm->catch_blocks = new (alloc0_) AbcBlock*[n];
for (int i = 0; i < n; ++i) {
ExceptionHandler* handler = &table_->exceptions[i];
if (pc >= code_pos_ + handler->from && pc < code_pos_ + handler->to) {
AbcBlock* catch_block = blockmap_.get(code_pos_ + handler->target);
++catch_block->num_preds;
fm->catch_blocks[i] = catch_block;
}
}
}
void AbcGraph::analyzeBranch(AbcBlock* blk, AbcOpcode abcop,
const uint8_t* nextpc, int32_t offset) {
assert(isBranchOpcode(abcop) && abcop != OP_jump); (void)abcop;
newSuccEdges(blk, 2);
addAbcEdge(blk, nextpc, 0);
addAbcEdge(blk, nextpc + offset, 1);
}
void AbcGraph::analyzeSwitch(AbcBlock* blk, const uint8_t* pc,
const uint8_t* nextpc, int32_t default_offset,
uint32_t num_cases) {
newSuccEdges(blk, num_cases + 1);
for (uint32_t i = 0; i < num_cases; ++i, nextpc += 3)
addAbcEdge(blk, pc + AvmCore::readS24(nextpc), i); // case edge
addAbcEdge(blk, pc + default_offset, num_cases); // default edge
}
// Add edge to next instr - our label ends here and
// we fall through to next label
void AbcGraph::analyzeEnd(AbcBlock* blk, const uint8_t* nextpc) {
newSuccEdges(blk, 1);
addAbcEdge(blk, nextpc, 0);
}
void AbcGraph::newSuccEdges(AbcBlock* block, int count) {
assert(!block->succ_blocks && !block->num_succ_blocks);
block->succ_blocks = new (alloc_) AbcBlock*[count];
block->num_succ_blocks = count;
}
} // namespace avmplus
#endif // VMCFG_HALFMOON