From 1d39e5ed56d497bdd39aa3877e00da22c64510a4 Mon Sep 17 00:00:00 2001 From: Sylvie <35663410+Rangi42@users.noreply.github.com> Date: Mon, 1 Apr 2024 10:47:15 -0400 Subject: [PATCH] Use `std::variant` for RPN expression value (#1389) --- include/asm/rpn.hpp | 19 ++-- src/asm/output.cpp | 11 +- src/asm/parser.y | 16 +-- src/asm/rpn.cpp | 267 ++++++++++++++++++++------------------------ src/asm/section.cpp | 16 +-- 5 files changed, 154 insertions(+), 175 deletions(-) diff --git a/include/asm/rpn.hpp b/include/asm/rpn.hpp index 53155ba1..2c74ecd1 100644 --- a/include/asm/rpn.hpp +++ b/include/asm/rpn.hpp @@ -5,6 +5,7 @@ #include #include +#include #include #include "linkdefs.hpp" @@ -12,9 +13,10 @@ struct Symbol; struct Expression { - int32_t val = 0; // If the expression's value is known, it's here - std::string reason{}; // Why the expression is not known, if it isn't - bool isKnown = true; // Whether the expression's value is known at assembly time + std::variant< + int32_t, // If the expression's value is known, it's here + std::string // Why the expression is not known, if it isn't + > data = 0; bool isSymbol = false; // Whether the expression represents a symbol suitable for const diffing std::vector rpn{}; // Bytes serializing the RPN expression uint32_t rpnPatchSize = 0; // Size the expression will take in the object file @@ -28,6 +30,9 @@ struct Expression { Expression &operator=(Expression &&) = default; + bool isKnown() const { return std::holds_alternative(data); } + int32_t value() const; + int32_t getConstVal() const; Symbol const *symbolOf() const; bool isDiffConstant(Symbol const *symName) const; @@ -56,14 +61,6 @@ private: void clear(); uint8_t *reserveSpace(uint32_t size); uint8_t *reserveSpace(uint32_t size, uint32_t patchSize); - - // Makes an expression "not known", also setting its error message - template - void makeUnknown(Ts... parts) { - isKnown = false; - reason.clear(); - (reason.append(parts), ...); - } }; #endif // RGBDS_ASM_RPN_H diff --git a/src/asm/output.cpp b/src/asm/output.cpp index b7515904..ccba20a3 100644 --- a/src/asm/output.cpp +++ b/src/asm/output.cpp @@ -244,14 +244,15 @@ static void initpatch(Patch &patch, uint32_t type, Expression const &expr, uint3 patch.pcSection = sect_GetSymbolSection(); patch.pcOffset = sect_GetSymbolOffset(); - if (expr.isKnown) { + if (expr.isKnown()) { // If the RPN expr's value is known, output a constant directly + uint32_t val = expr.value(); patch.rpn.resize(5); patch.rpn[0] = RPN_CONST; - patch.rpn[1] = (uint32_t)expr.val & 0xFF; - patch.rpn[2] = (uint32_t)expr.val >> 8; - patch.rpn[3] = (uint32_t)expr.val >> 16; - patch.rpn[4] = (uint32_t)expr.val >> 24; + patch.rpn[1] = val & 0xFF; + patch.rpn[2] = val >> 8; + patch.rpn[3] = val >> 16; + patch.rpn[4] = val >> 24; } else { patch.rpn.resize(expr.rpnPatchSize); writerpn(patch.rpn, expr.rpn); diff --git a/src/asm/parser.y b/src/asm/parser.y index 5788ef4b..6a4dde76 100644 --- a/src/asm/parser.y +++ b/src/asm/parser.y @@ -711,16 +711,16 @@ assert_type: assert: POP_ASSERT assert_type relocexpr { - if (!$3.isKnown) { + if (!$3.isKnown()) { out_CreateAssert($2, $3, "", sect_GetOutputOffset()); - } else if ($3.val == 0) { + } else if ($3.value() == 0) { failAssert($2); } } | POP_ASSERT assert_type relocexpr COMMA string { - if (!$3.isKnown) { + if (!$3.isKnown()) { out_CreateAssert($2, $3, $5, sect_GetOutputOffset()); - } else if ($3.val == 0) { + } else if ($3.value() == 0) { failAssertMsg($2, $5); } } @@ -1304,7 +1304,7 @@ relocexpr_no_str: $$.makeLow(); } | OP_ISCONST LPAREN relocexpr RPAREN { - $$.makeNumber($3.isKnown); + $$.makeNumber($3.isKnown()); } | OP_BANK LPAREN scoped_anon_id RPAREN { // '@' is also an ID; it is handled here @@ -1846,7 +1846,7 @@ z80_ldio: c_ind: LBRACK MODE_C RBRACK | LBRACK relocexpr OP_ADD MODE_C RBRACK { - if (!$2.isKnown || $2.val != 0xFF00) + if (!$2.isKnown() || $2.value() != 0xFF00) ::error("Expected constant expression equal to $FF00 for \"$ff00+c\"\n"); } ; @@ -2060,10 +2060,10 @@ z80_rrca: z80_rst: Z80_RST reloc_8bit { $2.makeCheckRST(); - if (!$2.isKnown) + if (!$2.isKnown()) sect_RelByte($2, 0); else - sect_AbsByte(0xC7 | $2.val); + sect_AbsByte(0xC7 | $2.value()); } ; diff --git a/src/asm/rpn.cpp b/src/asm/rpn.cpp index ff2cce83..a077a044 100644 --- a/src/asm/rpn.cpp +++ b/src/asm/rpn.cpp @@ -17,10 +17,15 @@ #include "asm/symbol.hpp" #include "asm/warning.hpp" +using namespace std::literals; + +int32_t Expression::value() const { + assert(std::holds_alternative(data)); + return std::get(data); +} + void Expression::clear() { - val = 0; - reason.clear(); - isKnown = true; + data = 0; isSymbol = false; rpn.clear(); rpnPatchSize = 0; @@ -38,11 +43,11 @@ uint8_t *Expression::reserveSpace(uint32_t size, uint32_t patchSize) { } int32_t Expression::getConstVal() const { - if (!isKnown) { - error("Expected constant expression: %s\n", reason.c_str()); + if (!isKnown()) { + error("Expected constant expression: %s\n", std::get(data).c_str()); return 0; } - return val; + return value(); } Symbol const *Expression::symbolOf() const { @@ -65,21 +70,19 @@ bool Expression::isDiffConstant(Symbol const *sym) const { void Expression::makeNumber(uint32_t value) { clear(); - val = value; + data = (int32_t)value; } void Expression::makeSymbol(std::string const &symName) { clear(); if (Symbol *sym = sym_FindScopedSymbol(symName); sym_IsPC(sym) && !sect_GetSymbolSection()) { error("PC has no value outside a section\n"); - val = 0; + data = 0; } else if (!sym || !sym->isConstant()) { isSymbol = true; - if (sym_IsPC(sym)) - makeUnknown("PC is not constant at assembly time"); - else - makeUnknown("'", symName, "' is not constant at assembly time"); + data = sym_IsPC(sym) ? "PC is not constant at assembly time" + : "'"s + symName + "' is not constant at assembly time"; sym = sym_Ref(symName); size_t nameLen = sym->name.length() + 1; // Don't forget NUL! @@ -89,7 +92,7 @@ void Expression::makeSymbol(std::string const &symName) { *ptr++ = RPN_SYM; memcpy(ptr, sym->name.c_str(), nameLen); } else { - val = sym_GetConstantValue(symName); + data = (int32_t)sym_GetConstantValue(symName); } } @@ -99,27 +102,27 @@ void Expression::makeBankSymbol(std::string const &symName) { // The @ symbol is treated differently. if (!currentSection) { error("PC has no bank outside a section\n"); - val = 1; + data = 1; } else if (currentSection->bank == (uint32_t)-1) { - makeUnknown("Current section's bank is not known"); + data = "Current section's bank is not known"; *reserveSpace(1) = RPN_BANK_SELF; } else { - val = currentSection->bank; + data = (int32_t)currentSection->bank; } return; } else if (sym && !sym->isLabel()) { error("BANK argument must be a label\n"); - val = 1; + data = 1; } else { sym = sym_Ref(symName); assert(sym); // If the symbol didn't exist, it should have been created if (sym->getSection() && sym->getSection()->bank != (uint32_t)-1) { // Symbol's section is known and bank is fixed - val = sym->getSection()->bank; + data = (int32_t)sym->getSection()->bank; } else { - makeUnknown("\"", symName, "\"'s bank is not known"); + data = "\""s + symName + "\"'s bank is not known"; size_t nameLen = sym->name.length() + 1; // Room for NUL! @@ -134,9 +137,9 @@ void Expression::makeBankSymbol(std::string const &symName) { void Expression::makeBankSection(std::string const §Name) { clear(); if (Section *sect = sect_FindSectionByName(sectName); sect && sect->bank != (uint32_t)-1) { - val = sect->bank; + data = (int32_t)sect->bank; } else { - makeUnknown("Section \"", sectName, "\"'s bank is not known"); + data = "Section \""s + sectName + "\"'s bank is not known"; size_t nameLen = sectName.length() + 1; // Room for NUL! @@ -149,9 +152,9 @@ void Expression::makeBankSection(std::string const §Name) { void Expression::makeSizeOfSection(std::string const §Name) { clear(); if (Section *sect = sect_FindSectionByName(sectName); sect && sect->isSizeKnown()) { - val = sect->size; + data = (int32_t)sect->size; } else { - makeUnknown("Section \"", sectName, "\"'s size is not known"); + data = "Section \""s + sectName + "\"'s size is not known"; size_t nameLen = sectName.length() + 1; // Room for NUL! @@ -164,9 +167,9 @@ void Expression::makeSizeOfSection(std::string const §Name) { void Expression::makeStartOfSection(std::string const §Name) { clear(); if (Section *sect = sect_FindSectionByName(sectName); sect && sect->org != (uint32_t)-1) { - val = sect->org; + data = (int32_t)sect->org; } else { - makeUnknown("Section \"", sectName, "\"'s start is not known"); + data = "Section \""s + sectName + "\"'s start is not known"; size_t nameLen = sectName.length() + 1; // Room for NUL! @@ -178,7 +181,7 @@ void Expression::makeStartOfSection(std::string const §Name) { void Expression::makeSizeOfSectionType(SectionType type) { clear(); - makeUnknown("Section type's size is not known"); + data = "Section type's size is not known"; uint8_t *ptr = reserveSpace(2); *ptr++ = RPN_SIZEOF_SECTTYPE; @@ -187,7 +190,7 @@ void Expression::makeSizeOfSectionType(SectionType type) { void Expression::makeStartOfSectionType(SectionType type) { clear(); - makeUnknown("Section type's start is not known"); + data = "Section type's start is not known"; uint8_t *ptr = reserveSpace(2); *ptr++ = RPN_STARTOF_SECTTYPE; @@ -216,14 +219,14 @@ static int32_t tryConstMask(Expression const &lhs, Expression const &rhs) { assert(sym.isNumeric()); - if (!expr.isKnown) + if (!expr.isKnown()) return -1; - // We can now safely use `expr.val` + // We can now safely use `expr.value()` Section const § = *sym.getSection(); int32_t unknownBits = (1 << 16) - (1 << sect.align); // The max alignment is 16 // The mask must ignore all unknown bits - if ((expr.val & unknownBits) != 0) + if ((expr.value() & unknownBits) != 0) return -1; // `sym.getValue()` attempts to add the section's address, but that's "-1" @@ -236,8 +239,8 @@ static int32_t tryConstMask(Expression const &lhs, Expression const &rhs) { void Expression::makeHigh() { isSymbol = false; - if (isKnown) { - val = (uint32_t)val >> 8 & 0xFF; + if (isKnown()) { + data = (int32_t)((uint32_t)value() >> 8 & 0xFF); } else { uint8_t bytes[] = {RPN_CONST, 8, 0, 0, 0, RPN_SHR, RPN_CONST, 0xFF, 0, 0, 0, RPN_AND}; @@ -247,8 +250,8 @@ void Expression::makeHigh() { void Expression::makeLow() { isSymbol = false; - if (isKnown) { - val = val & 0xFF; + if (isKnown()) { + data = value() & 0xFF; } else { uint8_t bytes[] = {RPN_CONST, 0xFF, 0, 0, 0, RPN_AND}; @@ -258,8 +261,8 @@ void Expression::makeLow() { void Expression::makeNeg() { isSymbol = false; - if (isKnown) { - val = -(uint32_t)val; + if (isKnown()) { + data = (int32_t) - (uint32_t)value(); } else { *reserveSpace(1) = RPN_NEG; } @@ -267,8 +270,8 @@ void Expression::makeNeg() { void Expression::makeNot() { isSymbol = false; - if (isKnown) { - val = ~val; + if (isKnown()) { + data = ~value(); } else { *reserveSpace(1) = RPN_NOT; } @@ -276,8 +279,8 @@ void Expression::makeNot() { void Expression::makeLogicNot() { isSymbol = false; - if (isKnown) { - val = !val; + if (isKnown()) { + data = !value(); } else { *reserveSpace(1) = RPN_LOGNOT; } @@ -286,130 +289,119 @@ void Expression::makeLogicNot() { void Expression::makeBinaryOp(RPNCommand op, Expression &&src1, Expression const &src2) { clear(); // First, check if the expression is known - isKnown = src1.isKnown && src2.isKnown; - if (isKnown) { + if (src1.isKnown() && src2.isKnown()) { // If both expressions are known, just compute the value - uint32_t uleft = src1.val, uright = src2.val; + int32_t lval = src1.value(), rval = src2.value(); switch (op) { case RPN_LOGOR: - val = src1.val || src2.val; + data = lval || rval; break; case RPN_LOGAND: - val = src1.val && src2.val; + data = lval && rval; break; case RPN_LOGEQ: - val = src1.val == src2.val; + data = lval == rval; break; case RPN_LOGGT: - val = src1.val > src2.val; + data = lval > rval; break; case RPN_LOGLT: - val = src1.val < src2.val; + data = lval < rval; break; case RPN_LOGGE: - val = src1.val >= src2.val; + data = lval >= rval; break; case RPN_LOGLE: - val = src1.val <= src2.val; + data = lval <= rval; break; case RPN_LOGNE: - val = src1.val != src2.val; + data = lval != rval; break; case RPN_ADD: - val = uleft + uright; + data = (int32_t)((uint32_t)lval + (uint32_t)rval); break; case RPN_SUB: - val = uleft - uright; + data = (int32_t)((uint32_t)lval - (uint32_t)rval); break; case RPN_XOR: - val = src1.val ^ src2.val; + data = lval ^ rval; break; case RPN_OR: - val = src1.val | src2.val; + data = lval | rval; break; case RPN_AND: - val = src1.val & src2.val; + data = lval & rval; break; case RPN_SHL: - if (src2.val < 0) + if (rval < 0) warning( - WARNING_SHIFT_AMOUNT, "Shifting left by negative amount %" PRId32 "\n", src2.val + WARNING_SHIFT_AMOUNT, "Shifting left by negative amount %" PRId32 "\n", rval ); - if (src2.val >= 32) - warning( - WARNING_SHIFT_AMOUNT, "Shifting left by large amount %" PRId32 "\n", src2.val - ); + if (rval >= 32) + warning(WARNING_SHIFT_AMOUNT, "Shifting left by large amount %" PRId32 "\n", rval); - val = op_shift_left(src1.val, src2.val); + data = op_shift_left(lval, rval); break; case RPN_SHR: - if (src1.val < 0) - warning(WARNING_SHIFT, "Shifting right negative value %" PRId32 "\n", src1.val); + if (lval < 0) + warning(WARNING_SHIFT, "Shifting right negative value %" PRId32 "\n", lval); - if (src2.val < 0) + if (rval < 0) warning( - WARNING_SHIFT_AMOUNT, - "Shifting right by negative amount %" PRId32 "\n", - src2.val + WARNING_SHIFT_AMOUNT, "Shifting right by negative amount %" PRId32 "\n", rval ); - if (src2.val >= 32) - warning( - WARNING_SHIFT_AMOUNT, "Shifting right by large amount %" PRId32 "\n", src2.val - ); + if (rval >= 32) + warning(WARNING_SHIFT_AMOUNT, "Shifting right by large amount %" PRId32 "\n", rval); - val = op_shift_right(src1.val, src2.val); + data = op_shift_right(lval, rval); break; case RPN_USHR: - if (src2.val < 0) + if (rval < 0) warning( - WARNING_SHIFT_AMOUNT, - "Shifting right by negative amount %" PRId32 "\n", - src2.val + WARNING_SHIFT_AMOUNT, "Shifting right by negative amount %" PRId32 "\n", rval ); - if (src2.val >= 32) - warning( - WARNING_SHIFT_AMOUNT, "Shifting right by large amount %" PRId32 "\n", src2.val - ); + if (rval >= 32) + warning(WARNING_SHIFT_AMOUNT, "Shifting right by large amount %" PRId32 "\n", rval); - val = op_shift_right_unsigned(src1.val, src2.val); + data = op_shift_right_unsigned(lval, rval); break; case RPN_MUL: - val = uleft * uright; + data = (int32_t)((uint32_t)lval * (uint32_t)rval); break; case RPN_DIV: - if (src2.val == 0) + if (rval == 0) fatalerror("Division by zero\n"); - if (src1.val == INT32_MIN && src2.val == -1) { + if (lval == INT32_MIN && rval == -1) { warning( WARNING_DIV, "Division of %" PRId32 " by -1 yields %" PRId32 "\n", INT32_MIN, INT32_MIN ); - val = INT32_MIN; + data = INT32_MIN; } else { - val = op_divide(src1.val, src2.val); + data = op_divide(lval, rval); } break; case RPN_MOD: - if (src2.val == 0) + if (rval == 0) fatalerror("Modulo by zero\n"); - if (src1.val == INT32_MIN && src2.val == -1) - val = 0; + if (lval == INT32_MIN && rval == -1) + data = 0; else - val = op_modulo(src1.val, src2.val); + data = op_modulo(lval, rval); break; case RPN_EXP: - if (src2.val < 0) + if (rval < 0) fatalerror("Exponentiation by negative power\n"); - val = op_exponent(src1.val, src2.val); + data = op_exponent(lval, rval); break; case RPN_NEG: @@ -429,20 +421,15 @@ void Expression::makeBinaryOp(RPNCommand op, Expression &&src1, Expression const fatalerror("%d is not a binary operator\n", op); } } else if (op == RPN_SUB && src1.isDiffConstant(src2.symbolOf())) { - Symbol const &symbol1 = *src1.symbolOf(); - Symbol const &symbol2 = *src2.symbolOf(); - - val = symbol1.getValue() - symbol2.getValue(); - isKnown = true; + data = src1.symbolOf()->getValue() - src2.symbolOf()->getValue(); } else if (int32_t constVal; op == RPN_AND && (constVal = tryConstMask(src1, src2)) != -1) { - val = constVal; - isKnown = true; + data = constVal; } else { // If it's not known, start computing the RPN expression // Convert the left-hand expression if it's constant - if (src1.isKnown) { - uint32_t lval = src1.val; + if (src1.isKnown()) { + uint32_t lval = src1.value(); uint8_t bytes[] = { RPN_CONST, (uint8_t)lval, @@ -455,67 +442,61 @@ void Expression::makeBinaryOp(RPNCommand op, Expression &&src1, Expression const memcpy(reserveSpace(sizeof(bytes)), bytes, sizeof(bytes)); // Use the other expression's un-const reason - reason = src2.reason; + data = std::move(src2.data); } else { // Otherwise just reuse its RPN buffer rpnPatchSize = src1.rpnPatchSize; std::swap(rpn, src1.rpn); - reason = src1.reason; + data = std::move(src1.data); } // Now, merge the right expression into the left one - uint8_t const *srcBytes = nullptr; - uint32_t srcLen = 0; - uint32_t srcPatchSize = 0; - - // If the right expression is constant, merge a shim instead - uint32_t rval = src2.val; - uint8_t bytes[] = { - RPN_CONST, - (uint8_t)rval, - (uint8_t)(rval >> 8), - (uint8_t)(rval >> 16), - (uint8_t)(rval >> 24), - }; - if (src2.isKnown) { - srcBytes = bytes; - srcLen = sizeof(bytes); - srcPatchSize = sizeof(bytes); + if (src2.isKnown()) { + // If the right expression is constant, append a shim instead + uint32_t rval = src2.value(); + uint8_t bytes[] = { + RPN_CONST, + (uint8_t)rval, + (uint8_t)(rval >> 8), + (uint8_t)(rval >> 16), + (uint8_t)(rval >> 24), + }; + uint8_t *ptr = reserveSpace(sizeof(bytes) + 1, sizeof(bytes) + 1); + memcpy(ptr, bytes, sizeof(bytes)); + ptr[sizeof(bytes)] = op; } else { - srcBytes = src2.rpn.data(); // Pointer to the right RPN - srcLen = src2.rpn.size(); // Size of the right RPN - srcPatchSize = src2.rpnPatchSize; + // Copy the right RPN and append the operator + uint32_t rightRpnSize = src2.rpn.size(); + uint8_t *ptr = reserveSpace(rightRpnSize + 1, src2.rpnPatchSize + 1); + if (rightRpnSize > 0) + // If `rightRpnSize == 0`, then `memcpy(ptr, nullptr, rightRpnSize)` would be UB + memcpy(ptr, src2.rpn.data(), rightRpnSize); + ptr[rightRpnSize] = op; } - // Copy the right RPN and append the operator - uint8_t *ptr = reserveSpace(srcLen + 1, srcPatchSize + 1); - if (srcBytes) - // If there were no `srcBytes`, then `memcpy(ptr, nullptr, 0)` would be UB - memcpy(ptr, srcBytes, srcLen); - ptr[srcLen] = op; } } void Expression::makeCheckHRAM() { isSymbol = false; - if (!isKnown) { + if (!isKnown()) { *reserveSpace(1) = RPN_HRAM; - } else if (val >= 0xFF00 && val <= 0xFFFF) { + } else if (int32_t val = value(); val >= 0xFF00 && val <= 0xFFFF) { // That range is valid, but only keep the lower byte - val &= 0xFF; + data = val & 0xFF; } else if (val < 0 || val > 0xFF) { error("Source address $%" PRIx32 " not between $FF00 to $FFFF\n", val); } } void Expression::makeCheckRST() { - if (isKnown) { - // A valid RST address must be masked with 0x38 - if (val & ~0x38) - error("Invalid address $%" PRIx32 " for RST\n", val); - // The target is in the "0x38" bits, all other bits are set - val |= 0xC7; - } else { + if (!isKnown()) { *reserveSpace(1) = RPN_RST; + } else if (int32_t val = value(); val & ~0x38) { + // A valid RST address must be masked with 0x38 + error("Invalid address $%" PRIx32 " for RST\n", val); + } else { + // The target is in the "0x38" bits, all other bits are set + data = val | 0xC7; } } @@ -524,8 +505,8 @@ void Expression::checkNBit(uint8_t n) const { assert(n != 0); // That doesn't make sense assert(n < CHAR_BIT * sizeof(int)); // Otherwise `1 << n` is UB - if (isKnown) { - if (val < -(1 << n) || val >= 1 << n) + if (isKnown()) { + if (int32_t val = value(); val < -(1 << n) || val >= 1 << n) warning(WARNING_TRUNCATION_1, "Expression must be %u-bit\n", n); else if (val < -(1 << (n - 1))) warning(WARNING_TRUNCATION_2, "Expression must be %u-bit\n", n); diff --git a/src/asm/section.cpp b/src/asm/section.cpp index e4eda44a..b037333e 100644 --- a/src/asm/section.cpp +++ b/src/asm/section.cpp @@ -734,11 +734,11 @@ void sect_RelByte(Expression &expr, uint32_t pcShift) { if (!reserveSpace(1)) return; - if (!expr.isKnown) { + if (!expr.isKnown()) { createPatch(PATCHTYPE_BYTE, expr, pcShift); writebyte(0); } else { - writebyte(expr.val); + writebyte(expr.value()); } } @@ -753,11 +753,11 @@ void sect_RelBytes(uint32_t n, std::vector &exprs) { for (uint32_t i = 0; i < n; i++) { Expression &expr = exprs[i % exprs.size()]; - if (!expr.isKnown) { + if (!expr.isKnown()) { createPatch(PATCHTYPE_BYTE, expr, i); writebyte(0); } else { - writebyte(expr.val); + writebyte(expr.value()); } } } @@ -770,11 +770,11 @@ void sect_RelWord(Expression &expr, uint32_t pcShift) { if (!reserveSpace(2)) return; - if (!expr.isKnown) { + if (!expr.isKnown()) { createPatch(PATCHTYPE_WORD, expr, pcShift); writeword(0); } else { - writeword(expr.val); + writeword(expr.value()); } } @@ -786,11 +786,11 @@ void sect_RelLong(Expression &expr, uint32_t pcShift) { if (!reserveSpace(2)) return; - if (!expr.isKnown) { + if (!expr.isKnown()) { createPatch(PATCHTYPE_LONG, expr, pcShift); writelong(0); } else { - writelong(expr.val); + writelong(expr.value()); } }