Global Metrics
path: .metrics.cyclomatic.average
old: 3.4166666666666665
new: 2.7096774193548385
path: .metrics.cyclomatic.sum
old: 41.0
new: 84.0
path: .metrics.nargs.average
old: 1.3636363636363635
new: 0.6666666666666666
path: .metrics.nargs.sum
old: 15.0
new: 18.0
path: .metrics.nom.total
old: 11.0
new: 27.0
path: .metrics.nom.closures
old: 3.0
new: 0.0
path: .metrics.nom.functions
old: 8.0
new: 27.0
path: .metrics.cognitive.sum
old: 30.0
new: 58.0
path: .metrics.cognitive.average
old: 2.727272727272727
new: 2.1481481481481484
path: .metrics.nexits.average
old: 1.0
new: 0.8148148148148148
path: .metrics.nexits.sum
old: 11.0
new: 22.0
path: .metrics.halstead.purity_ratio
old: 1.4832459377145806
new: 0.8856739178023794
path: .metrics.halstead.n1
old: 26.0
new: 42.0
path: .metrics.halstead.level
old: 0.033268790705861646
new: 0.012274475007394262
path: .metrics.halstead.vocabulary
old: 215.0
new: 208.0
path: .metrics.halstead.time
old: 13533.888249009273
new: 57089.20454265513
path: .metrics.halstead.n2
old: 189.0
new: 166.0
path: .metrics.halstead.volume
old: 8104.609720670575
new: 12613.320258315109
path: .metrics.halstead.N2
old: 437.0
new: 644.0
path: .metrics.halstead.difficulty
old: 30.058201058201057
new: 81.46987951807229
path: .metrics.halstead.length
old: 1046.0
new: 1638.0
path: .metrics.halstead.N1
old: 609.0
new: 994.0
path: .metrics.halstead.effort
old: 243609.98848216687
new: 1027605.6817677924
path: .metrics.halstead.estimated_program_length
old: 1551.4752508494512
new: 1450.7338773602974
path: .metrics.halstead.bugs
old: 1.300195941597515
new: 3.394400451525694
path: .metrics.loc.ploc
old: 227.0
new: 322.0
path: .metrics.loc.sloc
old: 301.0
new: 494.0
path: .metrics.loc.cloc
old: 35.0
new: 101.0
path: .metrics.loc.blank
old: 39.0
new: 71.0
path: .metrics.loc.lloc
old: 91.0
new: 210.0
path: .metrics.mi.mi_original
old: 22.31383465454229
new: 2.0978793925055896
path: .metrics.mi.mi_visual_studio
old: 13.04902611376742
new: 1.226830054096836
path: .metrics.mi.mi_sei
old: -14.132159213228183
new: -31.891709388862537
Spaces Data
Minimal test - lines (43, 334)
path: .spaces[0].spaces[0].metrics.mi.mi_visual_studio
old: 14.227796268649804
new: 11.771384773878722
path: .spaces[0].spaces[0].metrics.mi.mi_sei
old: -12.947079694349554
new: -12.4211089861571
path: .spaces[0].spaces[0].metrics.mi.mi_original
old: 24.32953161939116
new: 20.129067963332616
path: .spaces[0].spaces[0].metrics.halstead.difficulty
old: 31.244318181818183
new: 85.51530612244898
path: .spaces[0].spaces[0].metrics.halstead.level
old: 0.03200581923986179
new: 0.01169381301831633
path: .spaces[0].spaces[0].metrics.halstead.n2
old: 176.0
new: 98.0
path: .spaces[0].spaces[0].metrics.halstead.volume
old: 7872.641404268845
new: 7975.571177876286
path: .spaces[0].spaces[0].metrics.halstead.n1
old: 26.0
new: 37.0
path: .spaces[0].spaces[0].metrics.halstead.purity_ratio
old: 1.3959838497585924
new: 0.7462212415719268
path: .spaces[0].spaces[0].metrics.halstead.vocabulary
old: 202.0
new: 135.0
path: .spaces[0].spaces[0].metrics.halstead.length
old: 1028.0
new: 1127.0
path: .spaces[0].spaces[0].metrics.halstead.N2
old: 423.0
new: 453.0
path: .spaces[0].spaces[0].metrics.halstead.time
old: 13665.295164796204
new: 37890.74504319287
path: .spaces[0].spaces[0].metrics.halstead.effort
old: 245975.3129663317
new: 682033.4107774716
path: .spaces[0].spaces[0].metrics.halstead.bugs
old: 1.3085985251455552
new: 2.582750842732423
path: .spaces[0].spaces[0].metrics.halstead.N1
old: 605.0
new: 674.0
path: .spaces[0].spaces[0].metrics.halstead.estimated_program_length
old: 1435.071397551833
new: 840.9913392515615
path: .spaces[0].spaces[0].metrics.loc.ploc
old: 213.0
new: 197.0
path: .spaces[0].spaces[0].metrics.loc.lloc
old: 91.0
new: 111.0
path: .spaces[0].spaces[0].metrics.loc.sloc
old: 276.0
new: 292.0
path: .spaces[0].spaces[0].metrics.loc.blank
old: 35.0
new: 49.0
path: .spaces[0].spaces[0].metrics.loc.cloc
old: 28.0
new: 46.0
path: .spaces[0].spaces[0].metrics.nexits.average
old: 1.0
new: 0.7391304347826086
path: .spaces[0].spaces[0].metrics.nexits.sum
old: 11.0
new: 17.0
path: .spaces[0].spaces[0].metrics.cyclomatic.average
old: 3.9
new: 2.2083333333333335
path: .spaces[0].spaces[0].metrics.cyclomatic.sum
old: 39.0
new: 53.0
path: .spaces[0].spaces[0].metrics.cognitive.sum
old: 30.0
new: 42.0
path: .spaces[0].spaces[0].metrics.cognitive.average
old: 2.727272727272727
new: 1.826086956521739
path: .spaces[0].spaces[0].metrics.nom.closures
old: 3.0
new: 0.0
path: .spaces[0].spaces[0].metrics.nom.total
old: 11.0
new: 23.0
path: .spaces[0].spaces[0].metrics.nom.functions
old: 8.0
new: 23.0
path: .spaces[0].spaces[0].metrics.nargs.average
old: 1.3636363636363635
new: 0.782608695652174
path: .spaces[0].spaces[0].metrics.nargs.sum
old: 15.0
new: 18.0
Code
namespace test_assembler {
using std::back_insert_iterator;
Label::Label() : value_(new Binding()) {}
Label::Label(uint64_t value) : value_(new Binding(value)) {}
Label::Label(const Label& label) {
value_ = label.value_;
value_->Acquire();
}
Label::~Label() {
if (value_->Release()) delete value_;
}
Label& Label::operator=(uint64_t value) {
value_->Set(NULL, value);
return *this;
}
Label& Label::operator=(const Label& label) {
value_->Set(label.value_, 0);
return *this;
}
Label Label::operator+(uint64_t addend) const {
Label l;
l.value_->Set(this->value_, addend);
return l;
}
Label Label::operator-(uint64_t subtrahend) const {
Label l;
l.value_->Set(this->value_, -subtrahend);
return l;
}
// When NDEBUG is #defined, assert doesn't evaluate its argument. This
// means you can't simply use assert to check the return value of a
// function with necessary side effects.
//
// ALWAYS_EVALUATE_AND_ASSERT(x) evaluates x regardless of whether
// NDEBUG is #defined; when NDEBUG is not #defined, it further asserts
// that x is true.
#ifdef NDEBUG
# define ALWAYS_EVALUATE_AND_ASSERT(x) x
#else
# define ALWAYS_EVALUATE_AND_ASSERT(x) assert(x)
#endif
uint64_t Label::operator-(const Label& label) const {
uint64_t offset;
ALWAYS_EVALUATE_AND_ASSERT(IsKnownOffsetFrom(label, &offset));
return offset;
}
bool Label::IsKnownConstant(uint64_t* value_p) const {
Binding* base;
uint64_t addend;
value_->Get(&base, &addend);
if (base != NULL) return false;
if (value_p) *value_p = addend;
return true;
}
bool Label::IsKnownOffsetFrom(const Label& label, uint64_t* offset_p) const {
Binding *label_base, *this_base;
uint64_t label_addend, this_addend;
label.value_->Get(&label_base, &label_addend);
value_->Get(&this_base, &this_addend);
// If this and label are related, Get will find their final
// common ancestor, regardless of how indirect the relation is. This
// comparison also handles the constant vs. constant case.
if (this_base != label_base) return false;
if (offset_p) *offset_p = this_addend - label_addend;
return true;
}
Label::Binding::Binding() : base_(this), addend_(), reference_count_(1) {}
Label::Binding::Binding(uint64_t addend)
: base_(NULL), addend_(addend), reference_count_(1) {}
Label::Binding::~Binding() {
assert(reference_count_ == 0);
if (base_ && base_ != this && base_->Release()) delete base_;
}
void Label::Binding::Set(Binding* binding, uint64_t addend) {
if (!base_ && !binding) {
// We're equating two constants. This could be okay.
assert(addend_ == addend);
} else if (!base_) {
// We are a known constant, but BINDING may not be, so turn the
// tables and try to set BINDING's value instead.
binding->Set(NULL, addend_ - addend);
} else {
if (binding) {
// Find binding's final value. Since the final value is always either
// completely unconstrained or a constant, never a reference to
// another variable (otherwise, it wouldn't be final), this
// guarantees we won't create cycles here, even for code like this:
// l = m, m = n, n = l;
uint64_t binding_addend;
binding->Get(&binding, &binding_addend);
addend += binding_addend;
}
// It seems likely that setting a binding to itself is a bug
// (although I can imagine this might turn out to be helpful to
// permit).
assert(binding != this);
if (base_ != this) {
// Set the other bindings on our chain as well. Note that this
// is sufficient even though binding relationships form trees:
// All binding operations traverse their chains to the end, and
// all bindings related to us share some tail of our chain, so
// they will see the changes we make here.
base_->Set(binding, addend - addend_);
// We're not going to use base_ any more.
if (base_->Release()) delete base_;
}
// Adopt BINDING as our base. Note that it should be correct to
// acquire here, after the release above, even though the usual
// reference-counting rules call for acquiring first, and then
// releasing: the self-reference assertion above should have
// complained if BINDING were 'this' or anywhere along our chain,
// so we didn't release BINDING.
if (binding) binding->Acquire();
base_ = binding;
addend_ = addend;
}
}
void Label::Binding::Get(Binding** base, uint64_t* addend) {
if (base_ && base_ != this) {
// Recurse to find the end of our reference chain (the root of our
// tree), and then rewrite every binding along the chain to refer
// to it directly, adjusting addends appropriately. (This is why
// this member function isn't this-const.)
Binding* final_base;
uint64_t final_addend;
base_->Get(&final_base, &final_addend);
if (final_base) final_base->Acquire();
if (base_->Release()) delete base_;
base_ = final_base;
addend_ += final_addend;
}
*base = base_;
*addend = addend_;
}
template
static inline void InsertEndian(test_assembler::Endianness endianness,
size_t size, uint64_t number, Inserter dest) {
assert(size > 0);
if (endianness == kLittleEndian) {
for (size_t i = 0; i < size; i++) {
*dest++ = (char)(number & 0xff);
number >>= 8;
}
} else {
assert(endianness == kBigEndian);
// The loop condition is odd, but it's correct for size_t.
for (size_t i = size - 1; i < size; i--)
*dest++ = (char)((number >> (i * 8)) & 0xff);
}
}
Section& Section::Append(Endianness endianness, size_t size, uint64_t number) {
InsertEndian(endianness, size, number,
back_insert_iterator(contents_));
return *this;
}
Section& Section::Append(Endianness endianness, size_t size,
const Label& label) {
// If this label's value is known, there's no reason to waste an
// entry in references_ on it.
uint64_t value;
if (label.IsKnownConstant(&value)) return Append(endianness, size, value);
// This will get caught when the references are resolved, but it's
// nicer to find out earlier.
assert(endianness != kUnsetEndian);
references_.push_back(Reference(contents_.size(), endianness, size, label));
contents_.append(size, 0);
return *this;
}
#define ENDIANNESS_L kLittleEndian
#define ENDIANNESS_B kBigEndian
#define ENDIANNESS(e) ENDIANNESS_##e
#define DEFINE_SHORT_APPEND_NUMBER_ENDIAN(e, bits) \
Section& Section::e##bits(uint##bits##_t v) { \
InsertEndian(ENDIANNESS(e), bits / 8, v, \
back_insert_iterator(contents_)); \
return *this; \
}
#define DEFINE_SHORT_APPEND_LABEL_ENDIAN(e, bits) \
Section& Section::e##bits(const Label& v) { \
return Append(ENDIANNESS(e), bits / 8, v); \
}
// Define L16, B32, and friends.
#define DEFINE_SHORT_APPEND_ENDIAN(e, bits) \
DEFINE_SHORT_APPEND_NUMBER_ENDIAN(e, bits) \
DEFINE_SHORT_APPEND_LABEL_ENDIAN(e, bits)
DEFINE_SHORT_APPEND_LABEL_ENDIAN(L, 8);
DEFINE_SHORT_APPEND_LABEL_ENDIAN(B, 8);
DEFINE_SHORT_APPEND_ENDIAN(L, 16);
DEFINE_SHORT_APPEND_ENDIAN(L, 32);
DEFINE_SHORT_APPEND_ENDIAN(L, 64);
DEFINE_SHORT_APPEND_ENDIAN(B, 16);
DEFINE_SHORT_APPEND_ENDIAN(B, 32);
DEFINE_SHORT_APPEND_ENDIAN(B, 64);
#define DEFINE_SHORT_APPEND_NUMBER_DEFAULT(bits) \
Section& Section::D##bits(uint##bits##_t v) { \
InsertEndian(endianness_, bits / 8, v, \
back_insert_iterator(contents_)); \
return *this; \
}
#define DEFINE_SHORT_APPEND_LABEL_DEFAULT(bits) \
Section& Section::D##bits(const Label& v) { \
return Append(endianness_, bits / 8, v); \
}
#define DEFINE_SHORT_APPEND_DEFAULT(bits) \
DEFINE_SHORT_APPEND_NUMBER_DEFAULT(bits) \
DEFINE_SHORT_APPEND_LABEL_DEFAULT(bits)
DEFINE_SHORT_APPEND_LABEL_DEFAULT(8)
DEFINE_SHORT_APPEND_DEFAULT(16);
DEFINE_SHORT_APPEND_DEFAULT(32);
DEFINE_SHORT_APPEND_DEFAULT(64);
Section& Section::LEB128(long long value) {
while (value < -0x40 || 0x3f < value) {
contents_ += (value & 0x7f) | 0x80;
if (value < 0)
value = (value >> 7) | ~(((unsigned long long)-1) >> 7);
else
value = (value >> 7);
}
contents_ += value & 0x7f;
return *this;
}
Section& Section::ULEB128(uint64_t value) {
while (value > 0x7f) {
contents_ += (value & 0x7f) | 0x80;
value = (value >> 7);
}
contents_ += value;
return *this;
}
Section& Section::Align(size_t alignment, uint8_t pad_byte) {
// ALIGNMENT must be a power of two.
assert(((alignment - 1) & alignment) == 0);
size_t new_size = (contents_.size() + alignment - 1) & ~(alignment - 1);
contents_.append(new_size - contents_.size(), pad_byte);
assert((contents_.size() & (alignment - 1)) == 0);
return *this;
}
bool Section::GetContents(string* contents) {
// For each label reference, find the label's value, and patch it into
// the section's contents.
for (size_t i = 0; i < references_.size(); i++) {
Reference& r = references_[i];
uint64_t value;
if (!r.label.IsKnownConstant(&value)) {
fprintf(stderr, "Undefined label #%zu at offset 0x%zx\n", i, r.offset);
return false;
}
assert(r.offset < contents_.size());
assert(contents_.size() - r.offset >= r.size);
InsertEndian(r.endianness, r.size, value, contents_.begin() + r.offset);
}
contents->clear();
std::swap(contents_, *contents);
references_.clear();
return true;
}
} // namespace test_assembler
Minimal test - lines (57, 60)
path: .spaces[0].spaces[0].spaces[4].metrics.nom.closures
old: 3.0
new: 0.0
path: .spaces[0].spaces[0].spaces[4].metrics.nom.total
old: 4.0
new: 1.0
path: .spaces[0].spaces[0].spaces[4].metrics.cognitive.average
old: 2.75
new: 0.0
path: .spaces[0].spaces[0].spaces[4].metrics.cognitive.sum
old: 11.0
new: 0.0
path: .spaces[0].spaces[0].spaces[4].metrics.loc.blank
old: 7.0
new: 0.0
path: .spaces[0].spaces[0].spaces[4].metrics.loc.ploc
old: 87.0
new: 4.0
path: .spaces[0].spaces[0].spaces[4].metrics.loc.sloc
old: 108.0
new: 4.0
path: .spaces[0].spaces[0].spaces[4].metrics.loc.lloc
old: 36.0
new: 2.0
path: .spaces[0].spaces[0].spaces[4].metrics.loc.cloc
old: 14.0
new: 0.0
path: .spaces[0].spaces[0].spaces[4].metrics.nargs.sum
old: 1.0
new: 0.0
path: .spaces[0].spaces[0].spaces[4].metrics.nargs.average
old: 0.25
new: 0.0
path: .spaces[0].spaces[0].spaces[4].metrics.halstead.bugs
old: 0.5604059795606705
new: 0.018752049849923146
path: .spaces[0].spaces[0].spaces[4].metrics.halstead.effort
old: 68934.40366336062
new: 421.94418432572
path: .spaces[0].spaces[0].spaces[4].metrics.halstead.n1
old: 21.0
new: 10.0
path: .spaces[0].spaces[0].spaces[4].metrics.halstead.purity_ratio
old: 1.5439115273055908
new: 2.4904956346283575
path: .spaces[0].spaces[0].spaces[4].metrics.halstead.level
old: 0.04616132167152576
new: 0.16666666666666666
path: .spaces[0].spaces[0].spaces[4].metrics.halstead.difficulty
old: 21.66315789473684
new: 6.0
path: .spaces[0].spaces[0].spaces[4].metrics.halstead.volume
old: 3182.103181739193
new: 70.32403072095333
path: .spaces[0].spaces[0].spaces[4].metrics.halstead.estimated_program_length
old: 716.3749486697941
new: 44.82892142331043
path: .spaces[0].spaces[0].spaces[4].metrics.halstead.time
old: 3829.689092408923
new: 23.44134357365111
path: .spaces[0].spaces[0].spaces[4].metrics.halstead.N2
old: 196.0
new: 6.0
path: .spaces[0].spaces[0].spaces[4].metrics.halstead.length
old: 464.0
new: 18.0
path: .spaces[0].spaces[0].spaces[4].metrics.halstead.n2
old: 95.0
new: 5.0
path: .spaces[0].spaces[0].spaces[4].metrics.halstead.vocabulary
old: 116.0
new: 15.0
path: .spaces[0].spaces[0].spaces[4].metrics.halstead.N1
old: 268.0
new: 12.0
path: .spaces[0].spaces[0].spaces[4].metrics.cyclomatic.average
old: 11.0
new: 1.0
path: .spaces[0].spaces[0].spaces[4].metrics.cyclomatic.sum
old: 11.0
new: 1.0
path: .spaces[0].spaces[0].spaces[4].metrics.mi.mi_visual_studio
old: 29.637383870319457
new: 73.79873729732505
path: .spaces[0].spaces[0].spaces[4].metrics.mi.mi_original
old: 50.67992641824627
new: 126.19584077842585
path: .spaces[0].spaces[0].spaces[4].metrics.mi.mi_sei
old: 24.99976212527903
new: 106.46308153923984
path: .spaces[0].spaces[0].spaces[4].metrics.nexits.average
old: 0.75
new: 1.0
path: .spaces[0].spaces[0].spaces[4].metrics.nexits.sum
old: 3.0
new: 1.0
Code
Label& Label::operator=(uint64_t value) {
value_->Set(NULL, value);
return *this;
}
Minimal test - lines (73, 77)
path: .spaces[0].spaces[0].spaces[7].metrics.nargs.sum
old: 3.0
new: 1.0
path: .spaces[0].spaces[0].spaces[7].metrics.nargs.average
old: 3.0
new: 1.0
path: .spaces[0].spaces[0].spaces[7].metrics.cyclomatic.average
old: 5.0
new: 1.0
path: .spaces[0].spaces[0].spaces[7].metrics.cyclomatic.sum
old: 5.0
new: 1.0
path: .spaces[0].spaces[0].spaces[7].metrics.halstead.length
old: 85.0
new: 24.0
path: .spaces[0].spaces[0].spaces[7].metrics.halstead.N2
old: 31.0
new: 10.0
path: .spaces[0].spaces[0].spaces[7].metrics.halstead.n2
old: 23.0
new: 5.0
path: .spaces[0].spaces[0].spaces[7].metrics.halstead.difficulty
old: 11.456521739130435
new: 10.0
path: .spaces[0].spaces[0].spaces[7].metrics.halstead.effort
old: 5182.516717619118
new: 937.6537429460444
path: .spaces[0].spaces[0].spaces[7].metrics.halstead.n1
old: 17.0
new: 10.0
path: .spaces[0].spaces[0].spaces[7].metrics.halstead.purity_ratio
old: 2.041515215183142
new: 1.867871725971268
path: .spaces[0].spaces[0].spaces[7].metrics.halstead.vocabulary
old: 40.0
new: 15.0
path: .spaces[0].spaces[0].spaces[7].metrics.halstead.volume
old: 452.36388806542584
new: 93.76537429460444
path: .spaces[0].spaces[0].spaces[7].metrics.halstead.time
old: 287.91759542328435
new: 52.09187460811358
path: .spaces[0].spaces[0].spaces[7].metrics.halstead.bugs
old: 0.09982497721736826
new: 0.03193305039268938
path: .spaces[0].spaces[0].spaces[7].metrics.halstead.estimated_program_length
old: 173.52879329056708
new: 44.82892142331043
path: .spaces[0].spaces[0].spaces[7].metrics.halstead.N1
old: 54.0
new: 14.0
path: .spaces[0].spaces[0].spaces[7].metrics.halstead.level
old: 0.0872865275142315
new: 0.1
path: .spaces[0].spaces[0].spaces[7].metrics.mi.mi_sei
old: 79.2589955870867
new: 99.0896514058146
path: .spaces[0].spaces[0].spaces[7].metrics.mi.mi_visual_studio
old: 50.62584559916968
new: 70.8099230820973
path: .spaces[0].spaces[0].spaces[7].metrics.mi.mi_original
old: 86.57019597458014
new: 121.08496847038636
path: .spaces[0].spaces[0].spaces[7].metrics.loc.sloc
old: 24.0
new: 5.0
path: .spaces[0].spaces[0].spaces[7].metrics.loc.blank
old: 2.0
new: 0.0
path: .spaces[0].spaces[0].spaces[7].metrics.loc.lloc
old: 10.0
new: 2.0
path: .spaces[0].spaces[0].spaces[7].metrics.loc.cloc
old: 4.0
new: 0.0
path: .spaces[0].spaces[0].spaces[7].metrics.loc.ploc
old: 18.0
new: 5.0
path: .spaces[0].spaces[0].spaces[7].metrics.nexits.average
old: 3.0
new: 1.0
path: .spaces[0].spaces[0].spaces[7].metrics.nexits.sum
old: 3.0
new: 1.0
path: .spaces[0].spaces[0].spaces[7].metrics.cognitive.sum
old: 4.0
new: 0.0
path: .spaces[0].spaces[0].spaces[7].metrics.cognitive.average
old: 4.0
new: 0.0
Code
Label Label::operator-(uint64_t subtrahend) const {
Label l;
l.value_->Set(this->value_, -subtrahend);
return l;
}
Minimal test - lines (53, 55)
path: .spaces[0].spaces[0].spaces[3].metrics.cyclomatic.average
old: 5.0
new: 2.0
path: .spaces[0].spaces[0].spaces[3].metrics.cyclomatic.sum
old: 5.0
new: 2.0
path: .spaces[0].spaces[0].spaces[3].metrics.nexits.sum
old: 1.0
new: 0.0
path: .spaces[0].spaces[0].spaces[3].metrics.nexits.average
old: 1.0
new: 0.0
path: .spaces[0].spaces[0].spaces[3].metrics.nargs.average
old: 1.0
new: 0.0
path: .spaces[0].spaces[0].spaces[3].metrics.nargs.sum
old: 1.0
new: 0.0
path: .spaces[0].spaces[0].spaces[3].metrics.cognitive.average
old: 6.0
new: 1.0
path: .spaces[0].spaces[0].spaces[3].metrics.cognitive.sum
old: 6.0
new: 1.0
path: .spaces[0].spaces[0].spaces[3].metrics.halstead.vocabulary
old: 53.0
new: 11.0
path: .spaces[0].spaces[0].spaces[3].metrics.halstead.difficulty
old: 13.628571428571428
new: 5.333333333333333
path: .spaces[0].spaces[0].spaces[3].metrics.halstead.level
old: 0.07337526205450734
new: 0.1875
path: .spaces[0].spaces[0].spaces[3].metrics.halstead.N2
old: 53.0
new: 4.0
path: .spaces[0].spaces[0].spaces[3].metrics.halstead.n1
old: 18.0
new: 8.0
path: .spaces[0].spaces[0].spaces[3].metrics.halstead.bugs
old: 0.15704513393982142
new: 0.013519680280728329
path: .spaces[0].spaces[0].spaces[3].metrics.halstead.n2
old: 35.0
new: 3.0
path: .spaces[0].spaces[0].spaces[3].metrics.halstead.effort
old: 10226.301869836872
new: 258.3042275249182
path: .spaces[0].spaces[0].spaces[3].metrics.halstead.N1
old: 78.0
new: 10.0
path: .spaces[0].spaces[0].spaces[3].metrics.halstead.purity_ratio
old: 1.9433859207559956
new: 2.0539205358688193
path: .spaces[0].spaces[0].spaces[3].metrics.halstead.estimated_program_length
old: 254.58355561903545
new: 28.75488750216347
path: .spaces[0].spaces[0].spaces[3].metrics.halstead.volume
old: 750.357579547779
new: 48.43204266092216
path: .spaces[0].spaces[0].spaces[3].metrics.halstead.time
old: 568.127881657604
new: 14.350234862495457
path: .spaces[0].spaces[0].spaces[3].metrics.halstead.length
old: 131.0
new: 14.0
path: .spaces[0].spaces[0].spaces[3].metrics.loc.ploc
old: 28.0
new: 3.0
path: .spaces[0].spaces[0].spaces[3].metrics.loc.blank
old: 6.0
new: 0.0
path: .spaces[0].spaces[0].spaces[3].metrics.loc.cloc
old: 3.0
new: 0.0
path: .spaces[0].spaces[0].spaces[3].metrics.loc.lloc
old: 14.0
new: 2.0
path: .spaces[0].spaces[0].spaces[3].metrics.loc.sloc
old: 37.0
new: 3.0
path: .spaces[0].spaces[0].spaces[3].metrics.mi.mi_sei
old: 57.13741893836033
new: 115.75457976937346
path: .spaces[0].spaces[0].spaces[3].metrics.mi.mi_visual_studio
old: 44.98612310750397
new: 77.52376633412248
path: .spaces[0].spaces[0].spaces[3].metrics.mi.mi_original
old: 76.92627051383178
new: 132.56564043134944
Code
Label::~Label() {
if (value_->Release()) delete value_;
}
Minimal test - lines (62, 65)
path: .spaces[0].spaces[0].spaces[5].metrics.halstead.n1
old: 9.0
new: 10.0
path: .spaces[0].spaces[0].spaces[5].metrics.halstead.N1
old: 19.0
new: 13.0
path: .spaces[0].spaces[0].spaces[5].metrics.halstead.N2
old: 14.0
new: 8.0
path: .spaces[0].spaces[0].spaces[5].metrics.halstead.purity_ratio
old: 1.8711698776319527
new: 2.1347105439671634
path: .spaces[0].spaces[0].spaces[5].metrics.halstead.bugs
old: 0.03068314009949471
new: 0.02517517122460569
path: .spaces[0].spaces[0].spaces[5].metrics.halstead.time
old: 49.06356278027341
new: 36.46431222567951
path: .spaces[0].spaces[0].spaces[5].metrics.halstead.volume
old: 140.1816079436383
new: 82.0447025077789
path: .spaces[0].spaces[0].spaces[5].metrics.halstead.effort
old: 883.1441300449213
new: 656.3576200622311
path: .spaces[0].spaces[0].spaces[5].metrics.halstead.length
old: 33.0
new: 21.0
path: .spaces[0].spaces[0].spaces[5].metrics.halstead.estimated_program_length
old: 61.74860596185444
new: 44.82892142331043
path: .spaces[0].spaces[0].spaces[5].metrics.halstead.vocabulary
old: 19.0
new: 15.0
path: .spaces[0].spaces[0].spaces[5].metrics.halstead.difficulty
old: 6.3
new: 8.0
path: .spaces[0].spaces[0].spaces[5].metrics.halstead.level
old: 0.15873015873015872
new: 0.125
path: .spaces[0].spaces[0].spaces[5].metrics.halstead.n2
old: 10.0
new: 5.0
path: .spaces[0].spaces[0].spaces[5].metrics.cyclomatic.average
old: 2.0
new: 1.0
path: .spaces[0].spaces[0].spaces[5].metrics.cyclomatic.sum
old: 2.0
new: 1.0
path: .spaces[0].spaces[0].spaces[5].metrics.cognitive.average
old: 1.0
new: 0.0
path: .spaces[0].spaces[0].spaces[5].metrics.cognitive.sum
old: 1.0
new: 0.0
path: .spaces[0].spaces[0].spaces[5].metrics.loc.sloc
old: 13.0
new: 4.0
path: .spaces[0].spaces[0].spaces[5].metrics.loc.lloc
old: 6.0
new: 2.0
path: .spaces[0].spaces[0].spaces[5].metrics.loc.cloc
old: 2.0
new: 0.0
path: .spaces[0].spaces[0].spaces[5].metrics.loc.blank
old: 2.0
new: 0.0
path: .spaces[0].spaces[0].spaces[5].metrics.loc.ploc
old: 9.0
new: 4.0
path: .spaces[0].spaces[0].spaces[5].metrics.mi.mi_original
old: 103.2845387449579
new: 125.39425724332408
path: .spaces[0].spaces[0].spaces[5].metrics.mi.mi_sei
old: 102.0576030479892
new: 105.30664094829032
path: .spaces[0].spaces[0].spaces[5].metrics.mi.mi_visual_studio
old: 60.40031505553093
new: 73.32997499609597
path: .spaces[0].spaces[0].spaces[5].metrics.nexits.sum
old: 2.0
new: 1.0
path: .spaces[0].spaces[0].spaces[5].metrics.nexits.average
old: 2.0
new: 1.0
path: .spaces[0].spaces[0].spaces[5].metrics.nargs.sum
old: 1.0
new: 0.0
path: .spaces[0].spaces[0].spaces[5].metrics.nargs.average
old: 1.0
new: 0.0
Code
Label& Label::operator=(const Label& label) {
value_->Set(label.value_, 0);
return *this;
}
Minimal test - lines (47, 47)
path: .spaces[0].spaces[0].spaces[0].metrics.halstead.time
old: 61.34227922068799
new: 4.166666666666667
path: .spaces[0].spaces[0].spaces[0].metrics.halstead.effort
old: 1104.161025972384
new: 75.0
path: .spaces[0].spaces[0].spaces[0].metrics.halstead.bugs
old: 0.03560959390880295
new: 0.005928155507483437
path: .spaces[0].spaces[0].spaces[0].metrics.halstead.level
old: 0.17105263157894737
new: 0.4
path: .spaces[0].spaces[0].spaces[0].metrics.halstead.volume
old: 188.86964917948671
new: 30.0
path: .spaces[0].spaces[0].spaces[0].metrics.halstead.N1
old: 24.0
new: 7.0
path: .spaces[0].spaces[0].spaces[0].metrics.halstead.estimated_program_length
old: 72.10571633583419
new: 16.36452797660028
path: .spaces[0].spaces[0].spaces[0].metrics.halstead.n1
old: 8.0
new: 5.0
path: .spaces[0].spaces[0].spaces[0].metrics.halstead.purity_ratio
old: 1.6768771240891671
new: 1.6364527976600278
path: .spaces[0].spaces[0].spaces[0].metrics.halstead.n2
old: 13.0
new: 3.0
path: .spaces[0].spaces[0].spaces[0].metrics.halstead.difficulty
old: 5.846153846153846
new: 2.5
path: .spaces[0].spaces[0].spaces[0].metrics.halstead.N2
old: 19.0
new: 3.0
path: .spaces[0].spaces[0].spaces[0].metrics.halstead.length
old: 43.0
new: 10.0
path: .spaces[0].spaces[0].spaces[0].metrics.halstead.vocabulary
old: 21.0
new: 8.0
path: .spaces[0].spaces[0].spaces[0].metrics.cyclomatic.sum
old: 2.0
new: 1.0
path: .spaces[0].spaces[0].spaces[0].metrics.loc.lloc
old: 1.0
new: 0.0
path: .spaces[0].spaces[0].spaces[0].metrics.loc.ploc
old: 8.0
new: 1.0
path: .spaces[0].spaces[0].spaces[0].metrics.loc.sloc
old: 8.0
new: 1.0
path: .spaces[0].spaces[0].spaces[0].metrics.nargs.sum
old: 6.0
new: 0.0
path: .spaces[0].spaces[0].spaces[0].metrics.nargs.average
old: 6.0
new: 0.0
path: .spaces[0].spaces[0].spaces[0].metrics.mi.mi_original
old: 109.59955015556356
new: 153.0837736153568
path: .spaces[0].spaces[0].spaces[0].metrics.mi.mi_sei
old: 82.62151521988892
new: 145.25416890283572
path: .spaces[0].spaces[0].spaces[0].metrics.mi.mi_visual_studio
old: 64.09330418454009
new: 89.52267462886361
Code
Label::Label() : value_(new Binding()) {}
Minimal test - lines (48, 48)
path: .spaces[0].spaces[0].spaces[1].metrics.halstead.vocabulary
old: 9.0
new: 10.0
path: .spaces[0].spaces[0].spaces[1].metrics.halstead.time
old: 5.811529169310906
new: 8.996888590319939
path: .spaces[0].spaces[0].spaces[1].metrics.halstead.level
old: 0.3333333333333333
new: 0.26666666666666666
path: .spaces[0].spaces[0].spaces[1].metrics.halstead.volume
old: 34.86917501586544
new: 43.18506523353571
path: .spaces[0].spaces[0].spaces[1].metrics.halstead.length
old: 11.0
new: 13.0
path: .spaces[0].spaces[0].spaces[1].metrics.halstead.N2
old: 3.0
new: 5.0
path: .spaces[0].spaces[0].spaces[1].metrics.halstead.n2
old: 3.0
new: 4.0
path: .spaces[0].spaces[0].spaces[1].metrics.halstead.purity_ratio
old: 1.842242046044582
new: 1.808444231102072
path: .spaces[0].spaces[0].spaces[1].metrics.halstead.bugs
old: 0.007400380157174523
new: 0.009903498582139372
path: .spaces[0].spaces[0].spaces[1].metrics.halstead.difficulty
old: 3.0
new: 3.75
path: .spaces[0].spaces[0].spaces[1].metrics.halstead.estimated_program_length
old: 20.264662506490403
new: 23.509775004326936
path: .spaces[0].spaces[0].spaces[1].metrics.halstead.effort
old: 104.60752504759633
new: 161.9439946257589
path: .spaces[0].spaces[0].spaces[1].metrics.nargs.average
old: 0.0
new: 1.0
path: .spaces[0].spaces[0].spaces[1].metrics.nargs.sum
old: 0.0
new: 1.0
path: .spaces[0].spaces[0].spaces[1].metrics.loc.lloc
old: 1.0
new: 0.0
path: .spaces[0].spaces[0].spaces[1].metrics.loc.sloc
old: 3.0
new: 1.0
path: .spaces[0].spaces[0].spaces[1].metrics.loc.ploc
old: 3.0
new: 1.0
path: .spaces[0].spaces[0].spaces[1].metrics.mi.mi_visual_studio
old: 78.65739431314731
new: 88.41486984730174
path: .spaces[0].spaces[0].spaces[1].metrics.mi.mi_original
old: 134.50414427548188
new: 151.189427438886
path: .spaces[0].spaces[0].spaces[1].metrics.mi.mi_sei
old: 118.44942979264312
new: 142.52120506831432
Code
Label::Label(uint64_t value) : value_(new Binding(value)) {}
Minimal test - lines (67, 71)
path: .spaces[0].spaces[0].spaces[6].metrics.mi.mi_sei
old: 93.95328610212584
new: 99.60253955663347
path: .spaces[0].spaces[0].spaces[6].metrics.mi.mi_visual_studio
old: 68.68662876803354
new: 71.017821898286
path: .spaces[0].spaces[0].spaces[6].metrics.mi.mi_original
old: 117.45413519333736
new: 121.44047544606906
path: .spaces[0].spaces[0].spaces[6].metrics.nargs.average
old: 0.0
new: 1.0
path: .spaces[0].spaces[0].spaces[6].metrics.nargs.sum
old: 0.0
new: 1.0
path: .spaces[0].spaces[0].spaces[6].metrics.cyclomatic.average
old: 2.0
new: 1.0
path: .spaces[0].spaces[0].spaces[6].metrics.cyclomatic.sum
old: 2.0
new: 1.0
path: .spaces[0].spaces[0].spaces[6].metrics.nexits.average
old: 0.0
new: 1.0
path: .spaces[0].spaces[0].spaces[6].metrics.nexits.sum
old: 0.0
new: 1.0
path: .spaces[0].spaces[0].spaces[6].metrics.halstead.effort
old: 749.3681875625622
new: 788.122468865924
path: .spaces[0].spaces[0].spaces[6].metrics.halstead.N2
old: 8.0
new: 10.0
path: .spaces[0].spaces[0].spaces[6].metrics.halstead.estimated_program_length
old: 53.5635228093372
new: 40.13896548741762
path: .spaces[0].spaces[0].spaces[6].metrics.halstead.N1
old: 17.0
new: 13.0
path: .spaces[0].spaces[0].spaces[6].metrics.halstead.level
old: 0.13636363636363638
new: 0.1111111111111111
path: .spaces[0].spaces[0].spaces[6].metrics.halstead.difficulty
old: 7.333333333333333
new: 9.0
path: .spaces[0].spaces[0].spaces[6].metrics.halstead.n2
old: 6.0
new: 5.0
path: .spaces[0].spaces[0].spaces[6].metrics.halstead.time
old: 41.631565975697896
new: 43.784581603662446
path: .spaces[0].spaces[0].spaces[6].metrics.halstead.volume
old: 102.18657103125848
new: 87.56916320732489
path: .spaces[0].spaces[0].spaces[6].metrics.halstead.purity_ratio
old: 2.142540912373488
new: 1.7451724124964183
path: .spaces[0].spaces[0].spaces[6].metrics.halstead.vocabulary
old: 17.0
new: 14.0
path: .spaces[0].spaces[0].spaces[6].metrics.halstead.n1
old: 11.0
new: 9.0
path: .spaces[0].spaces[0].spaces[6].metrics.halstead.bugs
old: 0.027500604913224463
new: 0.028440761343675472
path: .spaces[0].spaces[0].spaces[6].metrics.halstead.length
old: 25.0
new: 23.0
path: .spaces[0].spaces[0].spaces[6].metrics.cognitive.sum
old: 1.0
new: 0.0
path: .spaces[0].spaces[0].spaces[6].metrics.cognitive.average
old: 1.0
new: 0.0
path: .spaces[0].spaces[0].spaces[6].metrics.loc.sloc
old: 6.0
new: 5.0
path: .spaces[0].spaces[0].spaces[6].metrics.loc.ploc
old: 6.0
new: 5.0
Code
Label Label::operator+(uint64_t addend) const {
Label l;
l.value_->Set(this->value_, addend);
return l;
}
Minimal test - lines (49, 52)
path: .spaces[0].spaces[0].spaces[2].metrics.nargs.average
old: 3.0
new: 1.0
path: .spaces[0].spaces[0].spaces[2].metrics.nargs.sum
old: 3.0
new: 1.0
path: .spaces[0].spaces[0].spaces[2].metrics.nexits.average
old: 2.0
new: 0.0
path: .spaces[0].spaces[0].spaces[2].metrics.nexits.sum
old: 2.0
new: 0.0
path: .spaces[0].spaces[0].spaces[2].metrics.mi.mi_original
old: 66.52758643388843
new: 126.64300853627338
path: .spaces[0].spaces[0].spaces[2].metrics.mi.mi_sei
old: 35.983618726500616
new: 107.10820824593196
path: .spaces[0].spaces[0].spaces[2].metrics.mi.mi_visual_studio
old: 38.9050213063675
new: 74.0602389101014
path: .spaces[0].spaces[0].spaces[2].metrics.cyclomatic.average
old: 10.0
new: 1.0
path: .spaces[0].spaces[0].spaces[2].metrics.cyclomatic.sum
old: 10.0
new: 1.0
path: .spaces[0].spaces[0].spaces[2].metrics.cognitive.average
old: 7.0
new: 0.0
path: .spaces[0].spaces[0].spaces[2].metrics.cognitive.sum
old: 7.0
new: 0.0
path: .spaces[0].spaces[0].spaces[2].metrics.loc.blank
old: 6.0
new: 0.0
path: .spaces[0].spaces[0].spaces[2].metrics.loc.ploc
old: 46.0
new: 4.0
path: .spaces[0].spaces[0].spaces[2].metrics.loc.cloc
old: 2.0
new: 0.0
path: .spaces[0].spaces[0].spaces[2].metrics.loc.lloc
old: 20.0
new: 2.0
path: .spaces[0].spaces[0].spaces[2].metrics.loc.sloc
old: 54.0
new: 4.0
path: .spaces[0].spaces[0].spaces[2].metrics.halstead.estimated_program_length
old: 418.41343573651113
new: 32.0
path: .spaces[0].spaces[0].spaces[2].metrics.halstead.level
old: 0.08241758241758242
new: 0.125
path: .spaces[0].spaces[0].spaces[2].metrics.halstead.length
old: 219.0
new: 18.0
path: .spaces[0].spaces[0].spaces[2].metrics.halstead.bugs
old: 0.21692964024575936
new: 0.02145079956307671
path: .spaces[0].spaces[0].spaces[2].metrics.halstead.difficulty
old: 12.133333333333333
new: 8.0
path: .spaces[0].spaces[0].spaces[2].metrics.halstead.N1
old: 128.0
new: 10.0
path: .spaces[0].spaces[0].spaces[2].metrics.halstead.time
old: 922.3329438179052
new: 28.67970000576925
path: .spaces[0].spaces[0].spaces[2].metrics.halstead.volume
old: 1368.2961254441452
new: 64.5293250129808
path: .spaces[0].spaces[0].spaces[2].metrics.halstead.n1
old: 16.0
new: 8.0
path: .spaces[0].spaces[0].spaces[2].metrics.halstead.effort
old: 16601.992988722293
new: 516.2346001038464
path: .spaces[0].spaces[0].spaces[2].metrics.halstead.n2
old: 60.0
new: 4.0
path: .spaces[0].spaces[0].spaces[2].metrics.halstead.purity_ratio
old: 1.9105636335000509
new: 1.7777777777777777
path: .spaces[0].spaces[0].spaces[2].metrics.halstead.N2
old: 91.0
new: 8.0
path: .spaces[0].spaces[0].spaces[2].metrics.halstead.vocabulary
old: 76.0
new: 12.0
Code
Label::Label(const Label& label) {
value_ = label.value_;
value_->Acquire();
}
Minimal test - lines (42, 335)
path: .spaces[0].metrics.nom.closures
old: 3.0
new: 0.0
path: .spaces[0].metrics.nom.functions
old: 8.0
new: 23.0
path: .spaces[0].metrics.nom.total
old: 11.0
new: 23.0
path: .spaces[0].metrics.mi.mi_visual_studio
old: 14.01615285832464
new: 11.56225135636454
path: .spaces[0].metrics.mi.mi_original
old: 23.967621387735136
new: 19.771449819383363
path: .spaces[0].metrics.mi.mi_sei
old: -13.06303553225542
new: -12.650508267330338
path: .spaces[0].metrics.halstead.effort
old: 245869.3306372341
new: 678855.1601589287
path: .spaces[0].metrics.halstead.N1
old: 606.0
new: 675.0
path: .spaces[0].metrics.halstead.N2
old: 424.0
new: 454.0
path: .spaces[0].metrics.halstead.length
old: 1030.0
new: 1129.0
path: .spaces[0].metrics.halstead.vocabulary
old: 203.0
new: 136.0
path: .spaces[0].metrics.halstead.bugs
old: 1.3082226113214566
new: 2.574720915466769
path: .spaces[0].metrics.halstead.n2
old: 177.0
new: 99.0
path: .spaces[0].metrics.halstead.n1
old: 26.0
new: 37.0
path: .spaces[0].metrics.halstead.volume
old: 7895.295994700732
new: 8001.745547771633
path: .spaces[0].metrics.halstead.purity_ratio
old: 1.401920014598407
new: 0.7520425862853433
path: .spaces[0].metrics.halstead.time
old: 13659.407257624116
new: 37714.17556438493
path: .spaces[0].metrics.halstead.difficulty
old: 31.141242937853107
new: 84.83838383838383
path: .spaces[0].metrics.halstead.level
old: 0.03211175616835994
new: 0.011787117513989762
path: .spaces[0].metrics.halstead.estimated_program_length
old: 1443.977615036359
new: 849.0560799161525
path: .spaces[0].metrics.nargs.average
old: 1.3636363636363635
new: 0.782608695652174
path: .spaces[0].metrics.nargs.sum
old: 15.0
new: 18.0
path: .spaces[0].metrics.loc.lloc
old: 91.0
new: 111.0
path: .spaces[0].metrics.loc.blank
old: 34.0
new: 48.0
path: .spaces[0].metrics.loc.ploc
old: 215.0
new: 199.0
path: .spaces[0].metrics.loc.sloc
old: 278.0
new: 294.0
path: .spaces[0].metrics.loc.cloc
old: 29.0
new: 47.0
path: .spaces[0].metrics.nexits.average
old: 1.0
new: 0.7391304347826086
path: .spaces[0].metrics.nexits.sum
old: 11.0
new: 17.0
path: .spaces[0].metrics.cyclomatic.sum
old: 40.0
new: 54.0
path: .spaces[0].metrics.cyclomatic.average
old: 3.636363636363636
new: 2.16
path: .spaces[0].metrics.cognitive.sum
old: 30.0
new: 42.0
path: .spaces[0].metrics.cognitive.average
old: 2.727272727272727
new: 1.826086956521739
Code
namespace lul_test {
namespace test_assembler {
using std::back_insert_iterator;
Label::Label() : value_(new Binding()) {}
Label::Label(uint64_t value) : value_(new Binding(value)) {}
Label::Label(const Label& label) {
value_ = label.value_;
value_->Acquire();
}
Label::~Label() {
if (value_->Release()) delete value_;
}
Label& Label::operator=(uint64_t value) {
value_->Set(NULL, value);
return *this;
}
Label& Label::operator=(const Label& label) {
value_->Set(label.value_, 0);
return *this;
}
Label Label::operator+(uint64_t addend) const {
Label l;
l.value_->Set(this->value_, addend);
return l;
}
Label Label::operator-(uint64_t subtrahend) const {
Label l;
l.value_->Set(this->value_, -subtrahend);
return l;
}
// When NDEBUG is #defined, assert doesn't evaluate its argument. This
// means you can't simply use assert to check the return value of a
// function with necessary side effects.
//
// ALWAYS_EVALUATE_AND_ASSERT(x) evaluates x regardless of whether
// NDEBUG is #defined; when NDEBUG is not #defined, it further asserts
// that x is true.
#ifdef NDEBUG
# define ALWAYS_EVALUATE_AND_ASSERT(x) x
#else
# define ALWAYS_EVALUATE_AND_ASSERT(x) assert(x)
#endif
uint64_t Label::operator-(const Label& label) const {
uint64_t offset;
ALWAYS_EVALUATE_AND_ASSERT(IsKnownOffsetFrom(label, &offset));
return offset;
}
bool Label::IsKnownConstant(uint64_t* value_p) const {
Binding* base;
uint64_t addend;
value_->Get(&base, &addend);
if (base != NULL) return false;
if (value_p) *value_p = addend;
return true;
}
bool Label::IsKnownOffsetFrom(const Label& label, uint64_t* offset_p) const {
Binding *label_base, *this_base;
uint64_t label_addend, this_addend;
label.value_->Get(&label_base, &label_addend);
value_->Get(&this_base, &this_addend);
// If this and label are related, Get will find their final
// common ancestor, regardless of how indirect the relation is. This
// comparison also handles the constant vs. constant case.
if (this_base != label_base) return false;
if (offset_p) *offset_p = this_addend - label_addend;
return true;
}
Label::Binding::Binding() : base_(this), addend_(), reference_count_(1) {}
Label::Binding::Binding(uint64_t addend)
: base_(NULL), addend_(addend), reference_count_(1) {}
Label::Binding::~Binding() {
assert(reference_count_ == 0);
if (base_ && base_ != this && base_->Release()) delete base_;
}
void Label::Binding::Set(Binding* binding, uint64_t addend) {
if (!base_ && !binding) {
// We're equating two constants. This could be okay.
assert(addend_ == addend);
} else if (!base_) {
// We are a known constant, but BINDING may not be, so turn the
// tables and try to set BINDING's value instead.
binding->Set(NULL, addend_ - addend);
} else {
if (binding) {
// Find binding's final value. Since the final value is always either
// completely unconstrained or a constant, never a reference to
// another variable (otherwise, it wouldn't be final), this
// guarantees we won't create cycles here, even for code like this:
// l = m, m = n, n = l;
uint64_t binding_addend;
binding->Get(&binding, &binding_addend);
addend += binding_addend;
}
// It seems likely that setting a binding to itself is a bug
// (although I can imagine this might turn out to be helpful to
// permit).
assert(binding != this);
if (base_ != this) {
// Set the other bindings on our chain as well. Note that this
// is sufficient even though binding relationships form trees:
// All binding operations traverse their chains to the end, and
// all bindings related to us share some tail of our chain, so
// they will see the changes we make here.
base_->Set(binding, addend - addend_);
// We're not going to use base_ any more.
if (base_->Release()) delete base_;
}
// Adopt BINDING as our base. Note that it should be correct to
// acquire here, after the release above, even though the usual
// reference-counting rules call for acquiring first, and then
// releasing: the self-reference assertion above should have
// complained if BINDING were 'this' or anywhere along our chain,
// so we didn't release BINDING.
if (binding) binding->Acquire();
base_ = binding;
addend_ = addend;
}
}
void Label::Binding::Get(Binding** base, uint64_t* addend) {
if (base_ && base_ != this) {
// Recurse to find the end of our reference chain (the root of our
// tree), and then rewrite every binding along the chain to refer
// to it directly, adjusting addends appropriately. (This is why
// this member function isn't this-const.)
Binding* final_base;
uint64_t final_addend;
base_->Get(&final_base, &final_addend);
if (final_base) final_base->Acquire();
if (base_->Release()) delete base_;
base_ = final_base;
addend_ += final_addend;
}
*base = base_;
*addend = addend_;
}
template
static inline void InsertEndian(test_assembler::Endianness endianness,
size_t size, uint64_t number, Inserter dest) {
assert(size > 0);
if (endianness == kLittleEndian) {
for (size_t i = 0; i < size; i++) {
*dest++ = (char)(number & 0xff);
number >>= 8;
}
} else {
assert(endianness == kBigEndian);
// The loop condition is odd, but it's correct for size_t.
for (size_t i = size - 1; i < size; i--)
*dest++ = (char)((number >> (i * 8)) & 0xff);
}
}
Section& Section::Append(Endianness endianness, size_t size, uint64_t number) {
InsertEndian(endianness, size, number,
back_insert_iterator(contents_));
return *this;
}
Section& Section::Append(Endianness endianness, size_t size,
const Label& label) {
// If this label's value is known, there's no reason to waste an
// entry in references_ on it.
uint64_t value;
if (label.IsKnownConstant(&value)) return Append(endianness, size, value);
// This will get caught when the references are resolved, but it's
// nicer to find out earlier.
assert(endianness != kUnsetEndian);
references_.push_back(Reference(contents_.size(), endianness, size, label));
contents_.append(size, 0);
return *this;
}
#define ENDIANNESS_L kLittleEndian
#define ENDIANNESS_B kBigEndian
#define ENDIANNESS(e) ENDIANNESS_##e
#define DEFINE_SHORT_APPEND_NUMBER_ENDIAN(e, bits) \
Section& Section::e##bits(uint##bits##_t v) { \
InsertEndian(ENDIANNESS(e), bits / 8, v, \
back_insert_iterator(contents_)); \
return *this; \
}
#define DEFINE_SHORT_APPEND_LABEL_ENDIAN(e, bits) \
Section& Section::e##bits(const Label& v) { \
return Append(ENDIANNESS(e), bits / 8, v); \
}
// Define L16, B32, and friends.
#define DEFINE_SHORT_APPEND_ENDIAN(e, bits) \
DEFINE_SHORT_APPEND_NUMBER_ENDIAN(e, bits) \
DEFINE_SHORT_APPEND_LABEL_ENDIAN(e, bits)
DEFINE_SHORT_APPEND_LABEL_ENDIAN(L, 8);
DEFINE_SHORT_APPEND_LABEL_ENDIAN(B, 8);
DEFINE_SHORT_APPEND_ENDIAN(L, 16);
DEFINE_SHORT_APPEND_ENDIAN(L, 32);
DEFINE_SHORT_APPEND_ENDIAN(L, 64);
DEFINE_SHORT_APPEND_ENDIAN(B, 16);
DEFINE_SHORT_APPEND_ENDIAN(B, 32);
DEFINE_SHORT_APPEND_ENDIAN(B, 64);
#define DEFINE_SHORT_APPEND_NUMBER_DEFAULT(bits) \
Section& Section::D##bits(uint##bits##_t v) { \
InsertEndian(endianness_, bits / 8, v, \
back_insert_iterator(contents_)); \
return *this; \
}
#define DEFINE_SHORT_APPEND_LABEL_DEFAULT(bits) \
Section& Section::D##bits(const Label& v) { \
return Append(endianness_, bits / 8, v); \
}
#define DEFINE_SHORT_APPEND_DEFAULT(bits) \
DEFINE_SHORT_APPEND_NUMBER_DEFAULT(bits) \
DEFINE_SHORT_APPEND_LABEL_DEFAULT(bits)
DEFINE_SHORT_APPEND_LABEL_DEFAULT(8)
DEFINE_SHORT_APPEND_DEFAULT(16);
DEFINE_SHORT_APPEND_DEFAULT(32);
DEFINE_SHORT_APPEND_DEFAULT(64);
Section& Section::LEB128(long long value) {
while (value < -0x40 || 0x3f < value) {
contents_ += (value & 0x7f) | 0x80;
if (value < 0)
value = (value >> 7) | ~(((unsigned long long)-1) >> 7);
else
value = (value >> 7);
}
contents_ += value & 0x7f;
return *this;
}
Section& Section::ULEB128(uint64_t value) {
while (value > 0x7f) {
contents_ += (value & 0x7f) | 0x80;
value = (value >> 7);
}
contents_ += value;
return *this;
}
Section& Section::Align(size_t alignment, uint8_t pad_byte) {
// ALIGNMENT must be a power of two.
assert(((alignment - 1) & alignment) == 0);
size_t new_size = (contents_.size() + alignment - 1) & ~(alignment - 1);
contents_.append(new_size - contents_.size(), pad_byte);
assert((contents_.size() & (alignment - 1)) == 0);
return *this;
}
bool Section::GetContents(string* contents) {
// For each label reference, find the label's value, and patch it into
// the section's contents.
for (size_t i = 0; i < references_.size(); i++) {
Reference& r = references_[i];
uint64_t value;
if (!r.label.IsKnownConstant(&value)) {
fprintf(stderr, "Undefined label #%zu at offset 0x%zx\n", i, r.offset);
return false;
}
assert(r.offset < contents_.size());
assert(contents_.size() - r.offset >= r.size);
InsertEndian(r.endianness, r.size, value, contents_.begin() + r.offset);
}
contents->clear();
std::swap(contents_, *contents);
references_.clear();
return true;
}
} // namespace test_assembler
} // namespace lul_test