> From: "Guy Steele" <[email protected]>
> To: "Brian Goetz" <[email protected]>
> Cc: "amber-spec-experts" <[email protected]>
> Sent: Saturday, April 16, 2022 4:10:06 AM
> Subject: Re: Evolving past reference type patterns
> Yes, this is a clear improvement to the example code.
> That said, I am always (or at least now) a bit leery of language designers
> motivating a new language feature by pointing out that it would make a
> compiler
> easier to write. As I have learned the hard way on more than one language
> project, compilers are not always representative of typical application code.
> (Please consider this remark as only very minor pushback on the form of the
> argument.)
This is a very specific example due to the way integers are encoded in the
bytecode,
also you can simplify the code a bit more because ICONST_M1, ICONST_0, etc are
all subsequents.
Moreover, as i said earlier, it's more a work for method patterns.
If we suppose we have a static pattern method isByte in java.lang.Byte
class Byte {
static pattern (byte) isByte(int value) {
if (value >= -128 && value <= 127) {
return match (short) value;
}
return no-match;
}
}
the code becomes
return with(switch (value) {
case -1 .. 5 -> ConstantInstruction.ofIntrinsic(Opcode.ICONST_M1 +
value);
case Byte.isByte(byte _) -> ConstantInstruction.ofArgument(Opcode.BIPUSH,
value);
case Short.isShort(short _) ->
ConstantInstruction.ofArgument(Opcode.SIPUSH, value);
default -> ConstantInstruction.ofLoad(Opcode.LDC,
BytecodeHelpers.constantEntry(constantPool(), value));
});
Rémi
>> On Apr 15, 2022, at 5:36 PM, Brian Goetz < [ mailto:[email protected] |
>> [email protected] ] > wrote:
>>> * asking if something fits in the range of a byte or int; doing this by
>>> hand is
>>> annoying and error-prone
>>> * asking if casting from long to int would produce truncation; doing
>>> this by
>>> hand is annoying and error-prone
>> Here’s some real code I wrote recently that would benefit dramatically from
>> this:
>> default CodeBuilder constantInstruction(int value) {
>> return with(switch (value) {
>> case -1 -> ConstantInstruction.ofIntrinsic(Opcode.ICONST_M1);
>> case 0 -> ConstantInstruction.ofIntrinsic(Opcode.ICONST_0);
>> case 1 -> ConstantInstruction.ofIntrinsic(Opcode.ICONST_1);
>> case 2 -> ConstantInstruction.ofIntrinsic(Opcode.ICONST_2);
>> case 3 -> ConstantInstruction.ofIntrinsic(Opcode.ICONST_3);
>> case 4 -> ConstantInstruction.ofIntrinsic(Opcode.ICONST_4);
>> case 5 -> ConstantInstruction.ofIntrinsic(Opcode.ICONST_5);
>> default -> {
>> if (value >= -128 && value <= 127) {
>> yield ConstantInstruction.ofArgument(Opcode.BIPUSH, value);
>> }
>> else if (value >= -32768 && value <= 32767) {
>> yield ConstantInstruction.ofArgument(Opcode.SIPUSH, value);
>> }
>> else {
>> yield ConstantInstruction.ofLoad(Opcode.LDC,
>> BytecodeHelpers.constantEntry(constantPool(), value));
>> }
>> }
>> });
>> }
>> could become the less error-prone and uniform:
>> default CodeBuilder constantInstruction(int value) {
>> return with(switch (value) {
>> case -1 -> ConstantInstruction.ofIntrinsic(Opcode.ICONST_M1);
>> case 0 -> ConstantInstruction.ofIntrinsic(Opcode.ICONST_0);
>> case 1 -> ConstantInstruction.ofIntrinsic(Opcode.ICONST_1);
>> case 2 -> ConstantInstruction.ofIntrinsic(Opcode.ICONST_2);
>> case 3 -> ConstantInstruction.ofIntrinsic(Opcode.ICONST_3);
>> case 4 -> ConstantInstruction.ofIntrinsic(Opcode.ICONST_4);
>> case 5 -> ConstantInstruction.ofIntrinsic(Opcode.ICONST_5);
>> case byte value -> ConstantInstruction.ofArgument(Opcode.BIPUSH,
>> value);
>> case short value -> ConstantInstruction.ofArgument(Opcode.SIPUSH,
>> value);
>> default -> ConstantInstruction.ofLoad(Opcode.LDC,
>> BytecodeHelpers.constantEntry(constantPool(), value));
>> });
>> }
>>