text:
#ifndef R600_SB_IR_H_
#define R600_SB_IR_H_

#include <algorithm>
#include <stdint.h>
#include <vector>
#include <set>
#include <algorithm>

#include "sb_bc.h"

namespace r600_sb {

enum special_regs {
	SV_ALU_PRED = 128,
	SV_EXEC_MASK,
	SV_AR_INDEX,
	SV_VALID_MASK
};

class node;
class value;
class shader;

struct sel_chan
{
	unsigned id;

	sel_chan(unsigned id = 0) : id(id) {}
	sel_chan(unsigned sel, unsigned chan) : id(((sel << 2) | chan) + 1) {}

	unsigned sel() const { return sel(id); }
	unsigned chan() const {return chan(id); }
	operator unsigned() const {return id;}

	static unsigned sel(unsigned idx) { return (idx-1) >> 2; }
	static unsigned chan(unsigned idx) { return (idx-1) & 3; }
};

inline sb_ostream& operator <<(sb_ostream& o, sel_chan r) {
	static const char * ch = "xyzw";
	o << r.sel() << "." << ch[r.chan()];
	return o;
}

typedef std::vector<value*>  vvec;

class sb_pool {
protected:
	static const unsigned SB_POOL_ALIGN = 8;
	static const unsigned SB_POOL_DEFAULT_BLOCK_SIZE = (1 << 16);

	typedef std::vector<void*> block_vector;

	unsigned block_size;
	block_vector blocks;
	unsigned total_size;

public:
	sb_pool(unsigned block_size = SB_POOL_DEFAULT_BLOCK_SIZE)
		: block_size(block_size), blocks(), total_size() {}

	virtual ~sb_pool() { free_all(); }

	void* allocate(unsigned sz);

protected:
	void free_all();
};

template <typename V, typename Comp = std::less<V> >
class sb_set {
	typedef std::vector<V> data_vector;
	data_vector vec;
public:

	typedef typename data_vector::iterator iterator;
	typedef typename data_vector::const_iterator const_iterator;

	sb_set() : vec() {}
	~sb_set() {  }

	iterator begin() { return vec.begin(); }
	iterator end() { return vec.end(); }
	const_iterator begin() const { return vec.begin(); }
	const_iterator end() const { return vec.end(); }

	void add_set(const sb_set& s) {
		data_vector t;
		t.reserve(vec.size() + s.vec.size());
		std::set_union(vec.begin(), vec.end(), s.vec.begin(), s.vec.end(),
		          std::inserter(t, t.begin()), Comp());
		vec.swap(t);
	}

	iterator lower_bound(const V& v) {
		return std::lower_bound(vec.begin(), vec.end(), v, Comp());
	}

	std::pair<iterator, bool> insert(const V& v) {
		iterator P = lower_bound(v);
		if (P != vec.end() && is_equal(*P, v))
			return std::make_pair(P, false);
		return std::make_pair(vec.insert(P, v), true);
	}

	unsigned erase(const V&  v) {
		iterator P = lower_bound(v);
		if (P == vec.end() || !is_equal(*P, v))
			return 0;
		vec.erase(P);
		return 1;
	}

	void clear() { vec.clear(); }

	bool empty() { return vec.empty(); }

	bool is_equal(const V& v1, const V& v2) {
		return !Comp()(v1, v2) && !Comp()(v2, v1);
	}

	iterator find(const V& v) {
		iterator P = lower_bound(v);
		return (P != vec.end() && is_equal(*P, v)) ? P : vec.end();
	}

	unsigned size() { return vec.size(); }
	void erase(iterator I) { vec.erase(I); }
};

template <typename K, typename V, typename KComp = std::less<K> >
class sb_map {
	typedef std::pair<K, V> datatype;

	struct Comp {
		bool operator()(const datatype &v1, const datatype &v2) {
			return KComp()(v1.first, v2.first);
		}
	};

	typedef sb_set<datatype, Comp> dataset;

	dataset set;

public:

	sb_map() : set() {}

	typedef typename dataset::iterator iterator;

	iterator begin() { return set.begin(); }
	iterator end() { return set.end(); }

	void clear() { set.clear(); }

	V& operator[](const K& key) {
		datatype P = std::make_pair(key, V());
		iterator F = set.find(P);
		if (F == set.end()) {
			return (*(set.insert(P).first)).second;
		} else {
			return (*F).second;
		}
	}

	std::pair<iterator, bool> insert(const datatype& d) {
		return set.insert(d);
	}

	iterator find(const K& key) {
		return set.find(std::make_pair(key, V()));
	}

	unsigned erase(const K& key) {
		return set.erase(std::make_pair(key, V()));
	}

	void erase(iterator I) {
		set.erase(I);
	}
};

class sb_bitset {
	typedef uint32_t basetype;
	static const unsigned bt_bits = sizeof(basetype) << 3;
	std::vector<basetype> data;
	unsigned bit_size;

public:

	sb_bitset() : data(), bit_size() {}

	bool get(unsigned id);
	void set(unsigned id, bool bit = true);
	bool set_chk(unsigned id, bool bit = true);

	void clear();
	void resize(unsigned size);

	unsigned size() { return bit_size; }

	unsigned find_bit(unsigned start = 0);

	void swap(sb_bitset & bs2);

	bool operator==(const sb_bitset &bs2);
	bool operator!=(const sb_bitset &bs2) { return !(*this == bs2); }

	sb_bitset& operator|=(const sb_bitset &bs2) {
		if (bit_size < bs2.bit_size) {
			resize(bs2.bit_size);
		}

		for (unsigned i = 0, c = std::min(data.size(), bs2.data.size()); i < c;
				++i) {
			data[i] |= bs2.data[i];
		}
		return *this;
	}

	sb_bitset& operator&=(const sb_bitset &bs2);
	sb_bitset& mask(const sb_bitset &bs2);

	friend sb_bitset operator|(const sb_bitset &b1, const sb_bitset &b2) {
			sb_bitset nbs(b1);
			nbs |= b2;
			return nbs;
	}
};

class value;

enum value_kind {
	VLK_REG,
	VLK_REL_REG,
	VLK_SPECIAL_REG,
	VLK_TEMP,

	VLK_CONST,
	VLK_KCACHE,
	VLK_PARAM,
	VLK_SPECIAL_CONST,

	VLK_UNDEF
};

class sb_value_pool : protected sb_pool {
	unsigned aligned_elt_size;

public:
	sb_value_pool(unsigned elt_size, unsigned block_elts = 256)
		: sb_pool(block_elts * (aligned_elt_size = ((elt_size +
				SB_POOL_ALIGN - 1) & ~(SB_POOL_ALIGN - 1)))) {}

	virtual ~sb_value_pool() { delete_all(); }

	value* create(value_kind k, sel_chan regid, unsigned ver);

	value* operator[](unsigned id) {
		unsigned offset = id * aligned_elt_size;
		unsigned block_id;
		if (offset < block_size) {
			block_id = 0;
		} else {
			block_id = offset / block_size;
			offset = offset % block_size;
		}
		return (value*)((char*)blocks[block_id] + offset);
	}

	unsigned size() { return total_size / aligned_elt_size; }

protected:
	void delete_all();
};

class sb_value_set {

	sb_bitset bs;

public:
	sb_value_set() : bs() {}

	class iterator {
		sb_value_pool &vp;
		sb_value_set *s;
		unsigned nb;
	public:
		iterator(shader &sh, sb_value_set *s, unsigned nb = 0);

		iterator& operator++() {
			if (nb + 1 < s->bs.size())
				nb = s->bs.find_bit(nb + 1);
			else
				nb = s->bs.size();
			return *this;
		}
		bool operator !=(const iterator &i) {
			return s != i.s || nb != i.nb;
		}
		bool operator ==(const iterator &i) { return !(*this != i); }
		value* operator *() {
			 return vp[nb];
		}

	};

	iterator begin(shader &sh) {
		return iterator(sh, this, bs.size() ? bs.find_bit(0) : 0);
	}
	iterator end(shader &sh) { return iterator(sh, this, bs.size()); }

	bool add_set_checked(sb_value_set & s2);

	void add_set(sb_value_set & s2)  {
		if (bs.size() < s2.bs.size())
			bs.resize(s2.bs.size());
		bs |= s2.bs;
	}

	void remove_set(sb_value_set & s2);

	bool add_vec(vvec &vv);

	bool add_val(value *v);
	bool contains(value *v);

	bool remove_val(value *v);

	bool remove_vec(vvec &vv);

	void clear();

	bool empty();
};

typedef sb_value_set val_set;

struct gpr_array {
	sel_chan base_gpr; // original gpr
	sel_chan gpr; // assigned by regalloc
	unsigned array_size;

	gpr_array(sel_chan base_gpr, unsigned array_size) : base_gpr(base_gpr),
			array_size(array_size) {}

	unsigned hash() { return (base_gpr << 10) * array_size; }

	val_set interferences;
	vvec refs;

	bool is_dead();

};

typedef std::vector<gpr_array*> regarray_vec;

enum value_flags {
	VLF_UNDEF = (1 << 0),
	VLF_READONLY = (1 << 1),
	VLF_DEAD = (1 << 2),

	VLF_PIN_REG = (1 << 3),
	VLF_PIN_CHAN = (1 << 4),

	// opposite to alu clause local value - goes through alu clause boundary
	// (can't use temp gpr, can't recolor in the alu scheduler, etc)
	VLF_GLOBAL = (1 << 5),
	VLF_FIXED = (1 << 6),
	VLF_PVPS = (1 << 7),

	VLF_PREALLOC = (1 << 8)
};

inline value_flags operator |(value_flags l, value_flags r) {
	return (value_flags)((unsigned)l|(unsigned)r);
}
inline value_flags operator &(value_flags l, value_flags r) {
	return (value_flags)((unsigned)l&(unsigned)r);
}
inline value_flags operator ~(value_flags l) {
	return (value_flags)(~(unsigned)l);
}
inline value_flags& operator |=(value_flags &l, value_flags r) {
	l = l | r;
	return l;
}
inline value_flags& operator &=(value_flags &l, value_flags r) {
	l = l & r;
	return l;
}

struct value;

sb_ostream& operator << (sb_ostream &o, value &v);

typedef uint32_t value_hash;

enum use_kind {
	UK_SRC,
	UK_SRC_REL,
	UK_DST_REL,
	UK_MAYDEF,
	UK_MAYUSE,
	UK_PRED,
	UK_COND
};

struct use_info {
	use_info *next;
	node *op;
	use_kind kind;
	int arg;

	use_info(node *n, use_kind kind, int arg, use_info* next)
		: next(next), op(n), kind(kind), arg(arg) {}
};

enum constraint_kind {
	CK_SAME_REG,
	CK_PACKED_BS,
	CK_PHI
};

class shader;
class sb_value_pool;
class ra_chunk;
class ra_constraint;

class value {
protected:
	value(unsigned sh_id, value_kind k, sel_chan select, unsigned ver = 0)
		: kind(k), flags(),
			rel(), array(),
			version(ver), select(select), pin_gpr(select), gpr(),
			gvn_source(), ghash(),
			def(), adef(), uses(), constraint(), chunk(),
			literal_value(), uid(sh_id) {}

	~value() { delete_uses(); }

	friend class sb_value_pool;
public:
	value_kind kind;
	value_flags flags;

	vvec mdef;
	vvec muse;
	value *rel;
	gpr_array *array;

	unsigned version;

	sel_chan select;
	sel_chan pin_gpr;
	sel_chan gpr;

	value *gvn_source;
	value_hash ghash;

	node *def, *adef;
	use_info *uses;

	ra_constraint *constraint;
	ra_chunk *chunk;

	literal literal_value;

	bool is_const() { return kind == VLK_CONST || kind == VLK_UNDEF; }

	bool is_AR() {
		return is_special_reg() && select == sel_chan(SV_AR_INDEX, 0);
	}

	node* any_def() {
		assert(!(def && adef));
		return def ? def : adef;
	}

	value* gvalue() {
		value *v = this;
		while (v->gvn_source && v != v->gvn_source)
			// FIXME we really shouldn't have such chains
			v = v->gvn_source;
		return v;
	}

	bool is_float_0_or_1() {
		value *v = gvalue();
		return v->is_const() && (v->literal_value == literal(0)
						|| v->literal_value == literal(1.0f));
	}

	bool is_undef() { return gvalue()->kind == VLK_UNDEF; }

	bool is_any_gpr() {
		return (kind == VLK_REG || kind == VLK_TEMP);
	}

	bool is_agpr() {
		return array && is_any_gpr();
	}

	// scalar gpr, as opposed to element of gpr array
	bool is_sgpr() {
		return !array && is_any_gpr();
	}

	bool is_special_reg() {	return kind == VLK_SPECIAL_REG;	}
	bool is_any_reg() { return is_any_gpr() || is_special_reg(); }
	bool is_kcache() { return kind == VLK_KCACHE; }
	bool is_rel() {	return kind == VLK_REL_REG; }
	bool is_readonly() { return flags & VLF_READONLY; }

	bool is_chan_pinned() { return flags & VLF_PIN_CHAN; }
	bool is_reg_pinned() { return flags & VLF_PIN_REG; }

	bool is_global();
	void set_global();
	void set_prealloc();

	bool is_prealloc();

	bool is_fixed();
	void fix();

	bool is_dead() { return flags & VLF_DEAD; }

	literal & get_const_value() {
		value *v = gvalue();
		assert(v->is_const());
		return v->literal_value;
	}

	// true if needs to be encoded as literal in alu
	bool is_literal() {
		return is_const()
				&& literal_value != literal(0)
				&& literal_value != literal(1)
				&& literal_value != literal(-1)
				&& literal_value != literal(0.5)
				&& literal_value != literal(1.0);
	}

	void add_use(node *n, use_kind kind, int arg);

	value_hash hash();
	value_hash rel_hash();

	void assign_source(value *v) {
		assert(!gvn_source || gvn_source == this);
		gvn_source = v->gvalue();
	}

	bool v_equal(value *v) { return gvalue() == v->gvalue(); }

	unsigned use_count();
	void delete_uses();

	sel_chan get_final_gpr() {
		if (array && array->gpr) {
			int reg_offset = select.sel() - array->base_gpr.sel();
			if (rel && rel->is_const())
				reg_offset += rel->get_const_value().i;
			return array->gpr + (reg_offset << 2);
		} else {
			return gpr;
		}
	}

	unsigned get_final_chan() {
		if (array) {
			assert(array->gpr);
			return array->gpr.chan();
		} else {
			assert(gpr);
			return gpr.chan();
		}
	}

	val_set interferences;
	unsigned uid;
};

class expr_handler;

class value_table {
	typedef std::vector<value*> vt_item;
	typedef std::vector<vt_item> vt_table;

	expr_handler &ex;

	unsigned size_bits;
	unsigned size;
	unsigned size_mask;

	vt_table hashtable;

	unsigned cnt;

public:

	value_table(expr_handler &ex, unsigned size_bits = 10)
		: ex(ex), size_bits(size_bits), size(1u << size_bits),
		  size_mask(size - 1), hashtable(size), cnt() {}

	~value_table() {}

	void add_value(value* v);

	bool expr_equal(value* l, value* r);

	unsigned count() { return cnt; }

	void get_values(vvec & v);
};

class sb_context;

enum node_type {
	NT_UNKNOWN,
	NT_LIST,
	NT_OP,
	NT_REGION,
	NT_REPEAT,
	NT_DEPART,
	NT_IF,
};

enum node_subtype {
	NST_UNKNOWN,
	NST_LIST,
	NST_ALU_GROUP,
	NST_ALU_CLAUSE,
	NST_ALU_INST,
	NST_ALU_PACKED_INST,
	NST_CF_INST,
	NST_FETCH_INST,
	NST_TEX_CLAUSE,
	NST_VTX_CLAUSE,

	NST_BB,

	NST_PHI,
	NST_PSI,
	NST_COPY,

	NST_LOOP_PHI_CONTAINER,
	NST_LOOP_CONTINUE,
	NST_LOOP_BREAK
};

enum node_flags {
	NF_EMPTY = 0,
	NF_DEAD = (1 << 0),
	NF_REG_CONSTRAINT = (1 << 1),
	NF_CHAN_CONSTRAINT = (1 << 2),
	NF_ALU_4SLOT = (1 << 3),
	NF_CONTAINER = (1 << 4),

	NF_COPY_MOV = (1 << 5),

	NF_DONT_KILL = (1 << 6),
	NF_DONT_HOIST = (1 << 7),
	NF_DONT_MOVE = (1 << 8),

	// for KILLxx - we want to schedule them as early as possible
	NF_SCHEDULE_EARLY = (1 << 9),

	// for ALU_PUSH_BEFORE - when set, replace with PUSH + ALU
	NF_ALU_STACK_WORKAROUND = (1 << 10)
};

inline node_flags operator |(node_flags l, node_flags r) {
	return (node_flags)((unsigned)l|(unsigned)r);
}
inline node_flags& operator |=(node_flags &l, node_flags r) {
	l = l | r;
	return l;
}

inline node_flags& operator &=(node_flags &l, node_flags r) {
	l = (node_flags)((unsigned)l & (unsigned)r);
	return l;
}

inline node_flags operator ~(node_flags r) {
	return (node_flags)~(unsigned)r;
}

struct node_stats {
	unsigned alu_count;
	unsigned alu_kill_count;
	unsigned alu_copy_mov_count;
	unsigned cf_count;
	unsigned fetch_count;
	unsigned region_count;
	unsigned loop_count;
	unsigned phi_count;
	unsigned loop_phi_count;
	unsigned depart_count;
	unsigned repeat_count;
	unsigned if_count;

	node_stats() : alu_count(), alu_kill_count(), alu_copy_mov_count(),
			cf_count(), fetch_count(), region_count(),
			loop_count(), phi_count(), loop_phi_count(), depart_count(),
			repeat_count(), if_count() {}

	void dump();
};

class shader;

class vpass;

class container_node;
class region_node;

class node {

protected:
	node(node_type nt, node_subtype nst, node_flags flags = NF_EMPTY)
	: prev(), next(), parent(),
	  type(nt), subtype(nst), flags(flags),
	  pred(), dst(), src() {}

	virtual ~node() {};

public:
	node *prev, *next;
	container_node *parent;

	node_type type;
	node_subtype subtype;
	node_flags flags;

	value *pred;

	vvec dst;
	vvec src;

	virtual bool is_valid() { return true; }
	virtual bool accept(vpass &p, bool enter);

	void insert_before(node *n);
	void insert_after(node *n);
	void replace_with(node *n);
	void remove();

	virtual value_hash hash();
	value_hash hash_src();

	virtual bool fold_dispatch(expr_handler *ex);

	bool is_container() { return flags & NF_CONTAINER; }

	bool is_alu_packed() { return subtype == NST_ALU_PACKED_INST; }
	bool is_alu_inst() { return subtype == NST_ALU_INST; }
	bool is_alu_group() { return subtype == NST_ALU_GROUP; }
	bool is_alu_clause() { return subtype == NST_ALU_CLAUSE; }

	bool is_fetch_clause() {
		return subtype == NST_TEX_CLAUSE || subtype == NST_VTX_CLAUSE;
	}

	bool is_copy() { return subtype == NST_COPY; }
	bool is_copy_mov() { return flags & NF_COPY_MOV; }
	bool is_any_alu() { return is_alu_inst() || is_alu_packed() || is_copy(); }

	bool is_fetch_inst() { return subtype == NST_FETCH_INST; }
	bool is_cf_inst() { return subtype == NST_CF_INST; }

	bool is_region() { return type == NT_REGION; }
	bool is_depart() { return type == NT_DEPART; }
	bool is_repeat() { return type == NT_REPEAT; }
	bool is_if() { return type == NT_IF; }
	bool is_bb() { return subtype == NST_BB; }

	bool is_phi() { return subtype == NST_PHI; }

	bool is_dead() { return flags & NF_DEAD; }

	bool is_cf_op(unsigned op);
	bool is_alu_op(unsigned op);
	bool is_fetch_op(unsigned op);

	unsigned cf_op_flags();
	unsigned alu_op_flags();
	unsigned alu_op_slot_flags();
	unsigned fetch_op_flags();

	bool is_mova();
	bool is_pred_set();

	bool vec_uses_ar(vvec &vv) {
		for (vvec::iterator I = vv.begin(), E = vv.end(); I != E; ++I) {
			value *v = *I;
			if (v && v->rel && !v->rel->is_const())
				return true;
		}
		return false;
	}

	bool uses_ar() {
		return vec_uses_ar(dst) || vec_uses_ar(src);
	}

	region_node* get_parent_region();

	friend class shader;
};

class container_node : public node {
public:

	container_node(node_type nt = NT_LIST, node_subtype nst = NST_LIST,
	               node_flags flags = NF_EMPTY)
	: node(nt, nst, flags | NF_CONTAINER), first(), last(),
	  live_after(), live_before() {}

	// child items list
	node *first, *last;

	val_set live_after;
	val_set live_before;

	class iterator {
		node *p;
	public:
		iterator(node *pp = NULL) : p(pp) {}
		iterator & operator ++() { p = p->next; return *this;}
		iterator & operator --() { p = p->prev; return *this;}
		node* operator *() { return p; }
		node* operator ->() { return p; }
		const iterator advance(int n) {
			if (!n) return *this;
			iterator I(p);
			if (n > 0) while (n--) ++I;
			else while (n++) --I;
			return I;
		}
		const iterator operator +(int n) { return advance(n); }
		const iterator operator -(int n) { return advance(-n); }
		bool operator !=(const iterator &i) { return p != i.p; }
		bool operator ==(const iterator &i) { return p == i.p; }
	};

	class riterator {
		iterator i;
	public:
		riterator(node *p = NULL) : i(p) {}
		riterator & operator ++() { --i; return *this;}
		riterator & operator --() { ++i; return *this;}
		node* operator *() { return *i; }
		node* operator ->() { return *i; }
		bool operator !=(const riterator &r) { return i != r.i; }
		bool operator ==(const riterator &r) { return i == r.i; }
	};

	iterator begin() { return first; }
	iterator end() { return NULL; }
	riterator rbegin() { return last; }
	riterator rend() { return NULL; }

	bool empty() { assert(first != NULL || first == last); return !first; }
	unsigned count();

	// used with node containers that represent shceduling queues
	// ignores copies and takes into account alu_packed_node items
	unsigned real_alu_count();

	void push_back(node *n);
	void push_front(node *n);

	void insert_node_before(node *s, node *n);
	void insert_node_after(node *s, node *n);

	void append_from(container_node *c);

	// remove range [b..e) from some container and assign to this container
	void move(iterator b, iterator e);

	void expand();
	void expand(container_node *n);
	void remove_node(node *n);

	node *cut(iterator b, iterator e);

	void clear() { first = last = NULL; }

	virtual bool is_valid() { return true; }
	virtual bool accept(vpass &p, bool enter);
	virtual bool fold_dispatch(expr_handler *ex);

	node* front() { return first; }
	node* back() { return last; }

	void collect_stats(node_stats &s);

	friend class shader;

};

typedef container_node::iterator node_iterator;
typedef container_node::riterator node_riterator;

class alu_group_node : public container_node {
protected:
	alu_group_node() : container_node(NT_LIST, NST_ALU_GROUP), literals() {}
public:

	std::vector<literal> literals;

	virtual bool is_valid() { return subtype == NST_ALU_GROUP; }
	virtual bool accept(vpass &p, bool enter);

	unsigned literal_chan(literal l) {
		std::vector<literal>::iterator F =
				std::find(literals.begin(), literals.end(), l);
		assert(F != literals.end());
		return F - literals.begin();
	}

	friend class shader;
};

class cf_node : public container_node {
protected:
	cf_node() : container_node(NT_OP, NST_CF_INST), jump_target(),
		jump_after_target() { memset(&bc, 0, sizeof(bc_cf)); };
public:
	bc_cf bc;

	cf_node *jump_target;
	bool jump_after_target;

	virtual bool is_valid() { return subtype == NST_CF_INST; }
	virtual bool accept(vpass &p, bool enter);
	virtual bool fold_dispatch(expr_handler *ex);

	void jump(cf_node *c) { jump_target = c; jump_after_target = false; }
	void jump_after(cf_node *c) { jump_target = c; jump_after_target = true; }

	friend class shader;
};

class alu_node : public node {
protected:
	alu_node() : node(NT_OP, NST_ALU_INST) { memset(&bc, 0, sizeof(bc_alu)); };
public:
	bc_alu bc;

	virtual bool is_valid() { return subtype == NST_ALU_INST; }
	virtual bool accept(vpass &p, bool enter);
	virtual bool fold_dispatch(expr_handler *ex);

	unsigned forced_bank_swizzle() {
		return ((bc.op_ptr->flags & AF_INTERP) && (bc.slot_flags == AF_4V)) ?
				VEC_210 : 0;
	}

	// return param index + 1 if instruction references interpolation param,
	// otherwise 0
	unsigned interp_param();

	alu_group_node *get_alu_group_node();

	friend class shader;
};

// for multi-slot instrs - DOT/INTERP/... (maybe useful for 64bit pairs later)
class alu_packed_node : public container_node {
protected:
	alu_packed_node() : container_node(NT_OP, NST_ALU_PACKED_INST) {}
public:

	const alu_op_info* op_ptr() {
		return static_cast<alu_node*>(first)->bc.op_ptr;
	}
	unsigned op() { return static_cast<alu_node*>(first)->bc.op; }
	void init_args(bool repl);

	virtual bool is_valid() { return subtype == NST_ALU_PACKED_INST; }
	virtual bool accept(vpass &p, bool enter);
	virtual bool fold_dispatch(expr_handler *ex);

	unsigned get_slot_mask();
	void update_packed_items(sb_context &ctx);

	friend class shader;
};

class fetch_node : public node {
protected:
	fetch_node() : node(NT_OP, NST_FETCH_INST) { memset(&bc, 0, sizeof(bc_fetch)); };
public:
	bc_fetch bc;

	virtual bool is_valid() { return subtype == NST_FETCH_INST; }
	virtual bool accept(vpass &p, bool enter);
	virtual bool fold_dispatch(expr_handler *ex);

	bool uses_grad() { return bc.op_ptr->flags & FF_USEGRAD; }

	friend class shader;
};

class region_node;

class repeat_node : public container_node {
protected:
	repeat_node(region_node *target, unsigned id)
	: container_node(NT_REPEAT, NST_LIST), target(target), rep_id(id) {}
public:
	region_node *target;
	unsigned rep_id;

	virtual bool accept(vpass &p, bool enter);

	friend class shader;
};

class depart_node : public container_node {
protected:
	depart_node(region_node *target, unsigned id)
	: container_node(NT_DEPART, NST_LIST), target(target), dep_id(id) {}
public:
	region_node *target;
	unsigned dep_id;

	virtual bool accept(vpass &p, bool enter);

	friend class shader;
};

class if_node : public container_node {
protected:
	if_node() : container_node(NT_IF, NST_LIST), cond() {};
public:
	value *cond; // glued to pseudo output (dst[2]) of the PRED_SETxxx

	virtual bool accept(vpass &p, bool enter);

	friend class shader;
};

typedef std::vector<depart_node*> depart_vec;
typedef std::vector<repeat_node*> repeat_vec;

class region_node : public container_node {
protected:
	region_node(unsigned id) : container_node(NT_REGION, NST_LIST), region_id(id),
			loop_phi(), phi(), vars_defined(), departs(), repeats() {}
public:
	unsigned region_id;

	container_node *loop_phi;
	container_node *phi;

	val_set vars_defined;

	depart_vec departs;
	repeat_vec repeats;

	virtual bool accept(vpass &p, bool enter);

	unsigned dep_count() { return departs.size(); }
	unsigned rep_count() { return repeats.size() + 1; }

	bool is_loop() { return !repeats.empty(); }

	container_node* get_entry_code_location() {
		node *p = first;
		while (p && (p->is_depart() || p->is_repeat()))
			p = static_cast<container_node*>(p)->first;

		container_node *c = static_cast<container_node*>(p);
		if (c->is_bb())
			return c;
		else
			return c->parent;
	}

	void expand_depart(depart_node *d);
	void expand_repeat(repeat_node *r);

	friend class shader;
};

class bb_node : public container_node {
protected:
	bb_node(unsigned id, unsigned loop_level)
		: container_node(NT_LIST, NST_BB), id(id), loop_level(loop_level) {}
public:
	unsigned id;
	unsigned loop_level;

	virtual bool accept(vpass &p, bool enter);

	friend class shader;
};

typedef std::vector<region_node*> regions_vec;
typedef std::vector<bb_node*> bbs_vec;
typedef std::list<node*> sched_queue;
typedef sched_queue::iterator sq_iterator;
typedef std::vector<node*> node_vec;
typedef std::list<node*> node_list;
typedef std::set<node*> node_set;

} // namespace r600_sb

#endif /* R600_SB_IR_H_ */


text:
'use strict';

Object.defineProperty(exports, "__esModule", {
    value: true
});

var _typeof2 = require('babel-runtime/helpers/typeof');

var _typeof3 = _interopRequireDefault(_typeof2);

var _ensureClientSideSelectorSupport = require('../helpers/ensureClientSideSelectorSupport');

var _ensureClientSideSelectorSupport2 = _interopRequireDefault(_ensureClientSideSelectorSupport);

var _createSelectorScript = require('../scripts/createSelectorScript');

var _createSelectorScript2 = _interopRequireDefault(_createSelectorScript);

var _ErrorHandler = require('../utils/ErrorHandler');

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

var selectorExecute = function selectorExecute(selector, script) {
    for (var _len = arguments.length, args = Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++) {
        args[_key - 2] = arguments[_key];
    }

    /**
     * if selectorExecute gets executed with element as first citizen like
     *
     * ```js
     * var elem = browser.element('#elem');
     * elem.selectorExecute(function () {...}, some, args);
     * ```
     */
    if (typeof selector === 'function' && this.lastResult && typeof this.lastResult.selector === 'string') {
        args.unshift(script);
        script = selector;
        selector = [this.lastResult.selector];

        /**
         * if selectorExecute gets executed by getHTML
         */
    } else if (selector === null) {
        selector = [this.lastResult.selector];
    }

    if (typeof selector === 'string') {
        selector = [selector];
    }

    if (!Array.isArray(selector)) {
        throw new _ErrorHandler.CommandError('Argument \'selector\' must be string or array of strings.');
    }
    if (!/string|function/.test(typeof script === 'undefined' ? 'undefined' : (0, _typeof3.default)(script))) {
        throw new _ErrorHandler.CommandError('Argument \'script\' must be a function or string.');
    }

    var fullScript = _createSelectorScript2.default.call(this, script, selector, args);
    return _ensureClientSideSelectorSupport2.default.call(this).execute(fullScript).then(function (res) {
        var result = res && res.value;

        if (result && result.message === 'NoSuchElement') {
            throw new _ErrorHandler.CommandError(7);
        }

        return result;
    });
}; /**
    * Works just like execute, only you can use selectors to pass html elements to
    * the function you wish to execute in the browser.
    *
    * The function fn will receive every resolved selector as an array of html elements,
    * even if there is only one result, or no result.
    * These arrays are the first arguments the function fn receives.
    * If you pass an array of selectors, the resulting html element arrays are returned in the same order.
    *
    * All arguments you append after function fn are added as the arguments after the html arrays.
    * You can use any JSON value or a function as such an argument.
    *
    * <example>
       :selectorExecuteAsync.js
       client.selectorExecute("//div", function(divs, message) {
           return divs.length + message;
       }, " divs on the page").then(function(res) {
           console.log(res); // returns, for example, "68 divs on the page"
       });

       client.selectorExecute(["//div", "=Read Post"], function(divs, links) {
           var message = 'There are ';

           message += divs.length + ' divs on the page';
           message += ' and ';
           message += links.length + ' links with an link text "' + links[0].text + '"';

           return message;
       }).then(function(res) {
           console.log(res); // returns, for example, "There are 68 divs on the page and 42 links with an link text 'Read Post'"
       });
    * </example>
    *
    * @alias browser.selectorExecute
    * @param {String|Array.<String>} selectors                  single selector or array of selectors
    * @param {Function}              script                     function to get executed in the browser
    * @param {...*}                  [argument1,...,argumentN]  arguments added to fn. Can be any JSON value or function
    * @uses protocol/execute
    * @type action
    */

exports.default = selectorExecute;
module.exports = exports['default'];

redpajama_set_name: RedPajamaGithub


text:
require 'spec_helper'
require 'wikitext'

describe Wikitext::Parser, 'parsing unordered lists' do
  before do
    @parser = Wikitext::Parser.new
  end

  it 'should recognize a single item list' do
    @parser.parse('*foo').should == "
\n
foo
\n
\n"
  end

  it 'should allow and consume optional space after the last
 marker' do
    @parser.parse('* foo').should == "
\n
foo
\n
\n"    # exactly one space consumed
    @parser.parse('*  foo').should == "
\n
foo
\n
\n"   # multiple spaces consumed
  end

  it 'should consider a space after an
 marker to indicate that it will be the last marker' do
    @parser.parse('* * foo').should == "
\n
* foo
\n
\n"
  end

  it 'should only recognize
 markers if they or a direct ancestor start in the left column' do
    @parser.parse(' * foo').should == "
* foo
\n"
  end

  it 'should recognize
 markers nested inside blockquote blocks' do
    expected = dedent <<-END

foo

    END
    @parser.parse('> * foo').should == expected
  end

  it 'should display excess
 markers as literals' do
    # this provides feedback to the user
    @parser.parse('** foo').should == "
\n
* foo
\n
\n"
    @parser.parse('*** foo').should == "
\n
** foo
\n
\n"
  end

  it 'should recognize a multi-item, single-level list' do
    expected = dedent <<-END

foo

bar

    END
    @parser.parse("* foo\n* bar").should == expected
  end

  it 'should recognize a multi-item, nested list (two levels)' do
    # indentation of nested lists is tricky
    # the last
 appears too far to the left
    # the difficult is that sometimes li has to act like a block level element (like blockquote, does emit before dedent)
    # and at other times it has to act like p (doesn't emit before dedent)
    # so basically when nested we need to do an emitting dedent
    # and when not we need to do a non-emitting one
    expected = dedent <<-END

foo

bar

    END
  @parser.parse("* foo\n** bar").should == expected
  end

  it 'should recognize a multi-item, nested list (three levels)' do
    expected = dedent <<-END

foo

bar

baz

    END
    @parser.parse("* foo\n** bar\n*** baz").should == expected
  end

  it 'should recognize lists in which nesting level increases and then is maintained' do
    expected = dedent <<-END

foo

bar

baz

    END
    @parser.parse("* foo\n** bar\n** baz").should == expected
  end

  it 'should recognize lists in which nesting level increases and then decreases' do
    expected = dedent <<-END

foo

bar

baz

    END
    @parser.parse("* foo\n** bar\n* baz").should == expected
  end

  it 'should be terminated by subsequent paragraph at the same level' do
    expected = dedent <<-END

foo

bar

    END
    @parser.parse("* foo\nbar").should == expected
  end

  it 'should be terminated by subsequent blockquote at the same level' do
    expected = dedent <<-END

foo

bar

    END
    @parser.parse("* foo\n> bar").should == expected
  end

  it 'should be terminated by subsequent heading at the same level' do
    @parser.parse("* foo\n====== bar ======").should == "
\n
foo
\n
\n
bar
\n"
    @parser.parse("* foo\n===== bar =====").should == "
\n
foo
\n
\n
bar
\n"
    @parser.parse("* foo\n==== bar ====").should == "
\n
foo
\n
\n
bar
\n"
    @parser.parse("* foo\n=== bar ===").should == "
\n
foo
\n
\n
bar
\n"
    @parser.parse("* foo\n== bar ==").should == "
\n
foo
\n
\n
bar
\n"
    @parser.parse("* foo\n= bar =").should == "
\n
foo
\n
\n
bar
\n"
  end

  it 'should be terminated by subsequent
 block at the same level' do
    @parser.parse("* foo\n bar").should == "
\n
foo
\n
\n
bar
\n"
  end

  it 'should be terminated by subsequent ordered list at the same level' do
    expected = dedent 6,<<-END

foo

bar

    END
    @parser.parse("* foo\n# bar").should == expected
  end

  it 'should recognize lists which contain nested ordered lists' do
    expected = dedent <<-END

foo

bar

    END
    @parser.parse("* foo\n*# bar").should == expected

    input = dedent <<-END
      * foo
      *# bar
      *# baz
    END
    expected = dedent <<-END

foo

bar

baz

    END
    @parser.parse(input).should == expected
  end

  it 'should automatically close open TT_START elements on reaching the end of the line' do
    # this (and the same for all other span-level elements) was a bug
    input = dedent <<-END
      * <tt>hello
      * world
    END
    expected = dedent <<-END

hello

world

    END
    @parser.parse(input).should == expected
  end

  it 'should automatically close open TT elements on reaching the end of the line' do
    input = dedent <<-END
      * `hello
      * world
    END
    expected = dedent <<-END

hello

world

    END
    @parser.parse(input).should == expected
  end

  it 'should automatically close open EM_START elements on reaching the end of the line' do
    input = dedent <<-END
      * hello
      * world
    END
    expected = dedent <<-END

hello

world

    END
    @parser.parse(input).should == expected
  end

  it 'should automatically close open EM elements on reaching the end of the line' do
    input = dedent <<-END
      * ''hello
      * world
    END
    expected = dedent <<-END

hello

world

    END
    @parser.parse(input).should == expected
  end

  it 'should automatically close open STRONG_START elements on reaching the end of the line' do
    input = dedent <<-END
      * hello
      * world
    END
    expected = dedent <<-END

hello

world

    END
    @parser.parse(input).should == expected
  end

  it 'should automatically close open STRONG elements on reaching the end of the line' do
    input = dedent <<-END
      * '''hello
      * world
    END
    expected = dedent <<-END

hello

world

    END
    @parser.parse(input).should == expected
  end

  it 'should automatically close open STRONG_EM elements on reaching the end of the line' do
    input = dedent <<-END
      * '''''hello
      * world
    END
    expected = dedent <<-END

hello

world

    END
    @parser.parse(input).should == expected
  end
end


text:
package com.android.tools.perflib.vmtrace;

import com.android.annotations.NonNull;
import com.android.annotations.VisibleForTesting;
import com.android.ddmlib.ByteBufferUtil;
import com.google.common.base.Charsets;
import com.google.common.collect.Maps;
import com.google.common.io.Closeables;
import com.google.common.primitives.UnsignedInts;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.Map;
import java.util.Set;

public class VmTraceParser {
    private static final int TRACE_MAGIC = 0x574f4c53; // 'SLOW'

    private static final String HEADER_SECTION_VERSION = "*version";
    private static final String HEADER_SECTION_THREADS = "*threads";
    private static final String HEADER_SECTION_METHODS = "*methods";
    private static final String HEADER_END = "*end";

    private static final String KEY_CLOCK = "clock";
    private static final String KEY_DATA_OVERFLOW = "data-file-overflow";
    private static final String KEY_VM = "vm";

    private final File mTraceFile;

    private final VmTraceData.Builder mTraceDataBuilder;
    private VmTraceData mTraceData;

    public VmTraceParser(File traceFile) {
        if (!traceFile.exists()) {
            throw new IllegalArgumentException(
                    "Trace file " + traceFile.getAbsolutePath() + " does not exist.");
        }
        mTraceFile = traceFile;
        mTraceDataBuilder = new VmTraceData.Builder();
    }

    public void parse() throws IOException {
        long headerLength = parseHeader(mTraceFile);
        ByteBuffer buffer = ByteBufferUtil.mapFile(mTraceFile, headerLength, ByteOrder.LITTLE_ENDIAN);
        parseData(buffer);
        computeTimingStatistics();
    }

    public VmTraceData getTraceData() {
        if (mTraceData == null) {
            mTraceData = mTraceDataBuilder.build();
        }

        return mTraceData;
    }

    static final int PARSE_VERSION = 0;
    static final int PARSE_THREADS = 1;
    static final int PARSE_METHODS = 2;
    static final int PARSE_OPTIONS = 4;

    /** Parses the trace file header and returns the offset in the file where the header ends. */
    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
    long parseHeader(File f) throws IOException {
        long offset = 0;
        BufferedReader in = null;
        try {
            in = new BufferedReader(new InputStreamReader(new FileInputStream(f), Charsets.US_ASCII));

            int mode = PARSE_VERSION;
            String line;
            while (true) {
                line = in.readLine();
                if (line == null) {
                    throw new IOException("Key section does not have an *end marker");
                }

                // Calculate how much we have read from the file so far.  The
                // extra byte is for the line ending not included by readLine().
                offset += line.length() + 1;

                if (line.startsWith("*")) {
                    if (line.equals(HEADER_SECTION_VERSION)) {
                        mode = PARSE_VERSION;
                        continue;
                    }
                    if (line.equals(HEADER_SECTION_THREADS)) {
                        mode = PARSE_THREADS;
                        continue;
                    }
                    if (line.equals(HEADER_SECTION_METHODS)) {
                        mode = PARSE_METHODS;
                        continue;
                    }
                    if (line.equals(HEADER_END)) {
                        break;
                    }
                }

                switch (mode) {
                    case PARSE_VERSION:
                        mTraceDataBuilder.setVersion(Integer.decode(line));
                        mode = PARSE_OPTIONS;
                        break;
                    case PARSE_THREADS:
                        parseThread(line);
                        break;
                    case PARSE_METHODS:
                        parseMethod(line);
                        break;
                    case PARSE_OPTIONS:
                        parseOption(line);
                        break;
                }
            }
        } finally {
            if (in != null) {
                try {
                    Closeables.close(in, true /* swallowIOException */);
                } catch (IOException e) {
                    // cannot happen
                }
            }
        }

        return offset;
    }

    /** Parses trace option formatted as a key value pair. */
    private void parseOption(String line) {
        String[] tokens = line.split("=");
        if (tokens.length == 2) {
            String key = tokens[0];
            String value = tokens[1];

            if (key.equals(KEY_CLOCK)) {
                if (value.equals("thread-cpu")) {
                    mTraceDataBuilder.setVmClockType(VmTraceData.VmClockType.THREAD_CPU);
                } else if (value.equals("wall")) {
                    mTraceDataBuilder.setVmClockType(VmTraceData.VmClockType.WALL);
                } else if (value.equals("dual")) {
                    mTraceDataBuilder.setVmClockType(VmTraceData.VmClockType.DUAL);
                }
            } else if (key.equals(KEY_DATA_OVERFLOW)) {
                mTraceDataBuilder.setDataFileOverflow(Boolean.parseBoolean(value));
            } else if (key.equals(KEY_VM)) {
                mTraceDataBuilder.setVm(value);
            } else {
                mTraceDataBuilder.setProperty(key, value);
            }
        }
    }

    /** Parses thread information comprising an integer id and the thread name */
    private void parseThread(String line) {
        int index = line.indexOf('\t');
        if (index < 0) {
            return;
        }

        try {
            int id = Integer.decode(line.substring(0, index));
            String name = line.substring(index).trim();
            mTraceDataBuilder.addThread(id, name);
        } catch (NumberFormatException ignored) {
        }
    }

    void parseMethod(String line) {
        String[] tokens = line.split("\t");
        long id;
        try {
            id = Long.decode(tokens[0]);
        } catch (NumberFormatException e) {
            return;
        }

        String className = tokens[1];
        String methodName = null;
        String signature = null;
        String pathname = null;
        int lineNumber = -1;
        if (tokens.length == 6) {
            methodName = tokens[2];
            signature = tokens[3];
            pathname = tokens[4];
            lineNumber = Integer.decode(tokens[5]);
            pathname = constructPathname(className, pathname);
        } else if (tokens.length > 2) {
            if (tokens[3].startsWith("(")) {
                methodName = tokens[2];
                signature = tokens[3];
            } else {
                pathname = tokens[2];
                lineNumber = Integer.decode(tokens[3]);
            }
        }

        mTraceDataBuilder.addMethod(id, new MethodInfo(id, className, methodName, signature,
                pathname, lineNumber));
    }

    private String constructPathname(String className, String pathname) {
        int index = className.lastIndexOf('/');
        if (index > 0 && index < className.length() - 1 && pathname.endsWith(".java")) {
            pathname = className.substring(0, index + 1) + pathname;
        }
        return pathname;
    }

    /**
     * Parses the data section of the trace. The data section comprises of a header followed
     * by a list of records.
     *
     * All values are stored in little-endian order.
     */
    private void parseData(ByteBuffer buffer) {
        int recordSize = readDataFileHeader(buffer);
        parseMethodTraceData(buffer, recordSize);
    }

    /**
     * Parses the list of records corresponding to each trace event (method entry, exit, ...)
     *  Record format v1:
     *  u1  thread ID
     *  u4  method ID | method action
     *  u4  time delta since start, in usec
     *
     * Record format v2:
     *  u2  thread ID
     *  u4  method ID | method action
     *  u4  time delta since start, in usec
     *
     * Record format v3:
     *  u2  thread ID
     *  u4  method ID | method action
     *  u4  time delta since start, in usec
     *  u4  wall time since start, in usec (when clock == "dual" only)
     *
     * 32 bits of microseconds is 70 minutes.
     */
    private void parseMethodTraceData(ByteBuffer buffer, int recordSize) {
        int methodId;
        int threadId;
        int version = mTraceDataBuilder.getVersion();
        VmTraceData.VmClockType vmClockType = mTraceDataBuilder.getVmClockType();
        while (buffer.hasRemaining()) {
            int threadTime;
            int globalTime;

            int positionStart = buffer.position();

            threadId = version == 1 ? buffer.get() : buffer.getShort();
            methodId = buffer.getInt();

            switch (vmClockType) {
                case WALL:
                    globalTime = buffer.getInt();
                    threadTime = globalTime;
                    break;
                case DUAL:
                    threadTime = buffer.getInt();
                    globalTime = buffer.getInt();
                    break;
                case THREAD_CPU:
                default:
                    threadTime = buffer.getInt();
                    globalTime = threadTime;
                    break;
            }

            int positionEnd = buffer.position();
            int bytesRead = positionEnd - positionStart;
            if (bytesRead < recordSize) {
                buffer.position(positionEnd + (recordSize - bytesRead));
            }

            int action = methodId & 0x03;
            TraceAction methodAction;
            switch (action) {
                case 0:
                    methodAction = TraceAction.METHOD_ENTER;
                    break;
                case 1:
                    methodAction = TraceAction.METHOD_EXIT;
                    break;
                case 2:
                    methodAction = TraceAction.METHOD_EXIT_UNROLL;
                    break;
                default:
                    throw new RuntimeException(
                            "Invalid trace action, expected one of method entry, exit or unroll.");
            }
            methodId = methodId & ~0x03;

            mTraceDataBuilder.addMethodAction(threadId, UnsignedInts.toLong(methodId), methodAction,
                    threadTime, globalTime);
        }
    }

    /**
     *  Parses the data header with the following format:
     *  u4  magic ('SLOW')
     *  u2  version
     *  u2  offset to data
     *  u8  start date/time in usec
     *  u2  record size in bytes (version >= 2 only)
     *  ... padding to 32 bytes

     * @param buffer byte buffer pointing to the header
     * @return record size for each data entry following the header
     */
    private int readDataFileHeader(ByteBuffer buffer) {
        int magic = buffer.getInt();
        if (magic != TRACE_MAGIC) {
            String msg = String.format("Error: magic number mismatch; got 0x%x, expected 0x%x\n",
                    magic, TRACE_MAGIC);
            throw new RuntimeException(msg);
        }

        // read version
        int version = buffer.getShort();
        if (version != mTraceDataBuilder.getVersion()) {
            String msg = String.format(
                    "Error: version number mismatch; got %d in data header but %d in options\n",
                    version, mTraceData.getVersion());
            throw new RuntimeException(msg);
        }
        if (version < 1 || version > 3) {
            String msg = String.format(
                    "Error: unsupported trace version number %d.  "
                            + "Please use a newer version of TraceView to read this file.",
                    version);
            throw new RuntimeException(msg);
        }

        // read offset
        int offsetToData = buffer.getShort() - 16;

        // read startWhen
        buffer.getLong();

        // read record size
        int recordSize;
        switch (version) {
            case 1:
                recordSize = 9;
                break;
            case 2:
                recordSize = 10;
                break;
            default:
                recordSize = buffer.getShort();
                offsetToData -= 2;
                break;
        }

        // Skip over offsetToData bytes
        while (offsetToData-- > 0) {
            buffer.get();
        }

        return recordSize;
    }

    private void computeTimingStatistics() {
        VmTraceData data = getTraceData();

        ProfileDataBuilder builder = new ProfileDataBuilder();
        for (ThreadInfo thread : data.getThreads()) {
            Call c = thread.getTopLevelCall();
            if (c == null) {
                continue;
            }

            builder.computeCallStats(c, null, thread);
        }

        for (Long methodId : builder.getMethodsWithProfileData()) {
            MethodInfo method = data.getMethod(methodId);
            method.setProfileData(builder.getProfileData(methodId));
        }
    }

    private static class ProfileDataBuilder {
        /** Maps method ids to their corresponding method data builders */
        private final Map<Long, MethodProfileData.Builder> mBuilderMap = Maps.newHashMap();

        public void computeCallStats(Call c, Call parent, ThreadInfo thread) {
            long methodId = c.getMethodId();
            MethodProfileData.Builder builder = getProfileDataBuilder(methodId);
            builder.addCallTime(c, parent, thread);
            builder.incrementInvocationCount(c, parent, thread);
            if (c.isRecursive()) {
                builder.setRecursive();
            }

            for (Call callee: c.getCallees()) {
                computeCallStats(callee, c, thread);
            }
        }

        @NonNull
        private MethodProfileData.Builder getProfileDataBuilder(long methodId) {
            MethodProfileData.Builder builder = mBuilderMap.get(methodId);
            if (builder == null) {
                builder = new MethodProfileData.Builder();
                mBuilderMap.put(methodId, builder);
            }
            return builder;
        }

        public Set<Long> getMethodsWithProfileData() {
            return mBuilderMap.keySet();
        }

        public MethodProfileData getProfileData(Long methodId) {
            return mBuilderMap.get(methodId).build();
        }
    }
}


text: Test.assert_equals(shortcut('hello'), 'hll')