Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 61 additions & 1 deletion core/src/core/org/jnode/vm/x86/compiler/l1a/IntItem.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@

package org.jnode.vm.x86.compiler.l1a;

import org.jnode.assembler.Label;
import org.jnode.assembler.x86.X86Assembler;
import org.jnode.assembler.x86.X86Constants;
import org.jnode.assembler.x86.X86Register;
import org.jnode.assembler.x86.X86Register.GPR;
import org.jnode.vm.JvmType;
Expand All @@ -34,6 +36,8 @@

final class IntItem extends WordItem {

private static int labelCounter;

private int value;

final void initialize(EmitterContext ec, byte kind, short offsetToFP, X86Register reg, int value) {
Expand Down Expand Up @@ -84,14 +88,70 @@ protected void loadToConstant(EmitterContext ec, X86Assembler os,
}

/**
* Pop the top of the FPU stack into the given memory location.
* Pop the top of the FPU stack into the given memory location,
* with JLS-correct handling for NaN, infinity, and overflow.
*
* @param os
* @param reg
* @param disp
*/
protected void popFromFPU(X86Assembler os, GPR reg, int disp) {
final String uid = "f2i_" + (++labelCounter) + "_";
final Label done = new Label(uid + "fix");
final Label overflow = new Label(uid + "ovf");
final Label isInf = new Label(uid + "inf");

os.writePUSH(X86Register.EAX);

// Save float copy at [reg+disp-4], then reload for FISTP
os.writeFSTP32(reg, disp - 4);
os.writeFLD32(reg, disp - 4);
os.writeFISTP32(reg, disp);

// Check if result == MIN_VALUE (indefinite integer)
os.writeMOV(X86Constants.BITS32, X86Register.EAX, reg, disp);
os.writeCMP_Const(X86Register.EAX, 0x80000000);
os.writeJCC(done, X86Constants.JNE);

// Check saved float for NaN/Infinity (exponent all 1s?)
os.writeMOV(X86Constants.BITS32, X86Register.EAX, reg, disp - 4);
os.writeAND(X86Register.EAX, 0x7F800000);
os.writeCMP_Const(X86Register.EAX, 0x7F800000);
os.writeJCC(overflow, X86Constants.JNE);

// NaN or Infinity
os.writeMOV(X86Constants.BITS32, X86Register.EAX, reg, disp - 4);
os.writeTEST(X86Register.EAX, 0x007FFFFF);
os.writeJCC(isInf, X86Constants.JZ);

// NaN -> 0
os.writeXOR(X86Register.EAX, X86Register.EAX);
os.writeMOV(X86Constants.BITS32, reg, disp, X86Register.EAX);
os.writeJMP(done);

// Infinity
os.setObjectRef(isInf);
os.writeMOV(X86Constants.BITS32, X86Register.EAX, reg, disp - 4);
os.writeTEST(X86Register.EAX, 0x80000000);
os.writeJCC(done, X86Constants.JNZ); // -Inf -> MIN_VALUE (correct)

// +Inf -> MAX_VALUE
os.writeMOV_Const(X86Register.EAX, 0x7FFFFFFF);
os.writeMOV(X86Constants.BITS32, reg, disp, X86Register.EAX);
os.writeJMP(done);

// Not NaN/Inf, but result is MIN_VALUE: overflow or genuine MIN_VALUE
os.setObjectRef(overflow);
os.writeMOV(X86Constants.BITS32, X86Register.EAX, reg, disp - 4);
os.writeTEST(X86Register.EAX, 0x80000000);
os.writeJCC(done, X86Constants.JNZ); // Negative -> keep MIN_VALUE

// Positive overflow -> MAX_VALUE
os.writeMOV_Const(X86Register.EAX, 0x7FFFFFFF);
os.writeMOV(X86Constants.BITS32, reg, disp, X86Register.EAX);

os.setObjectRef(done);
os.writePOP(X86Register.EAX);
}

/**
Expand Down
83 changes: 82 additions & 1 deletion core/src/core/org/jnode/vm/x86/compiler/l1a/LongItem.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@

package org.jnode.vm.x86.compiler.l1a;

import org.jnode.assembler.Label;
import org.jnode.assembler.x86.X86Assembler;
import org.jnode.assembler.x86.X86Constants;
import org.jnode.assembler.x86.X86Register;
import org.jnode.assembler.x86.X86Register.GPR;
import org.jnode.assembler.x86.X86Register.GPR32;
Expand All @@ -38,6 +40,8 @@
*/
final class LongItem extends DoubleWordItem {

private static int labelCounter;

private long value;

/**
Expand Down Expand Up @@ -100,14 +104,91 @@ protected final void loadToConstant64(EmitterContext ec, X86Assembler os,
}

/**
* Pop the top of the FPU stack into the given memory location.
* Pop the top of the FPU stack into the given memory location,
* with JLS-correct handling for NaN, infinity, and overflow.
*
* @param os
* @param reg
* @param disp
*/
protected void popFromFPU(X86Assembler os, GPR reg, int disp) {
final String uid = "f2l_" + (++labelCounter) + "_";
final Label done = new Label(uid + "fix");
final Label overflow = new Label(uid + "ovf");
final Label isInf = new Label(uid + "inf");
final Label isInf2 = new Label(uid + "inf2");

os.writePUSH(X86Register.EAX);

// Save double copy at [reg+disp-8], then reload for FISTP
os.writeFSTP64(reg, disp - 8);
os.writeFLD64(reg, disp - 8);
os.writeFISTP64(reg, disp);

// Check if 64-bit result == Long.MIN_VALUE (indefinite integer)
// Check low 32 bits == 0
os.writeCMP_Const(X86Constants.BITS32, reg, disp, 0);
os.writeJCC(done, X86Constants.JNE);
// Check high 32 bits == 0x80000000
os.writeCMP_Const(X86Constants.BITS32, reg, disp + 4, 0x80000000);
os.writeJCC(done, X86Constants.JNE);

// Check saved double for NaN/Infinity
// Double high word at [reg+disp-4]: exponent bits 30:20 = 0x7FF00000
os.writeMOV(X86Constants.BITS32, X86Register.EAX, reg, disp - 4);
os.writeAND(X86Register.EAX, 0x7FF00000);
os.writeCMP_Const(X86Register.EAX, 0x7FF00000);
os.writeJCC(overflow, X86Constants.JNE);

// NaN or Infinity: check mantissa
os.writeMOV(X86Constants.BITS32, X86Register.EAX, reg, disp - 8);
os.writeTEST(X86Register.EAX, X86Register.EAX);
os.writeJCC(isInf, X86Constants.JZ);
// NaN (low mantissa != 0)
os.writeXOR(X86Register.EAX, X86Register.EAX);
os.writeMOV(X86Constants.BITS32, reg, disp, X86Register.EAX);
os.writeMOV(X86Constants.BITS32, reg, disp + 4, X86Register.EAX);
os.writeJMP(done);

// Check high mantissa bits
os.setObjectRef(isInf);
os.writeMOV(X86Constants.BITS32, X86Register.EAX, reg, disp - 4);
os.writeAND(X86Register.EAX, 0x000FFFFF);
os.writeTEST(X86Register.EAX, X86Register.EAX);
os.writeJCC(isInf2, X86Constants.JZ);
// NaN (high mantissa != 0)
os.writeXOR(X86Register.EAX, X86Register.EAX);
os.writeMOV(X86Constants.BITS32, reg, disp, X86Register.EAX);
os.writeMOV(X86Constants.BITS32, reg, disp + 4, X86Register.EAX);
os.writeJMP(done);

// Infinity
os.setObjectRef(isInf2);
os.writeMOV(X86Constants.BITS32, X86Register.EAX, reg, disp - 4);
os.writeTEST(X86Register.EAX, 0x80000000);
os.writeJCC(done, X86Constants.JNZ); // -Inf -> MIN_VALUE (correct)

// +Inf -> MAX_VALUE
os.writeMOV_Const(X86Register.EAX, 0xFFFFFFFF);
os.writeMOV(X86Constants.BITS32, reg, disp, X86Register.EAX);
os.writeMOV_Const(X86Register.EAX, 0x7FFFFFFF);
os.writeMOV(X86Constants.BITS32, reg, disp + 4, X86Register.EAX);
os.writeJMP(done);

// Not NaN/Inf, but result is MIN_VALUE: overflow or genuine MIN_VALUE
os.setObjectRef(overflow);
os.writeMOV(X86Constants.BITS32, X86Register.EAX, reg, disp - 4);
os.writeTEST(X86Register.EAX, 0x80000000);
os.writeJCC(done, X86Constants.JNZ); // Negative -> keep MIN_VALUE

// Positive overflow -> MAX_VALUE
os.writeMOV_Const(X86Register.EAX, 0xFFFFFFFF);
os.writeMOV(X86Constants.BITS32, reg, disp, X86Register.EAX);
os.writeMOV_Const(X86Register.EAX, 0x7FFFFFFF);
os.writeMOV(X86Constants.BITS32, reg, disp + 4, X86Register.EAX);

os.setObjectRef(done);
os.writePOP(X86Register.EAX);
}

/**
Expand Down
62 changes: 61 additions & 1 deletion core/src/core/org/jnode/vm/x86/compiler/l1b/IntItem.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@

package org.jnode.vm.x86.compiler.l1b;

import org.jnode.assembler.Label;
import org.jnode.assembler.x86.X86Assembler;
import org.jnode.assembler.x86.X86Constants;
import org.jnode.assembler.x86.X86Register;
import org.jnode.assembler.x86.X86Register.GPR;
import org.jnode.vm.JvmType;
Expand All @@ -35,6 +37,8 @@

final class IntItem extends WordItem implements X86CompilerConstants {

private static int labelCounter;

private int value;

final void initialize(EmitterContext ec, byte kind, short offsetToFP, X86Register reg, int value) {
Expand Down Expand Up @@ -85,14 +89,70 @@ protected void loadToConstant(EmitterContext ec, X86Assembler os,
}

/**
* Pop the top of the FPU stack into the given memory location.
* Pop the top of the FPU stack into the given memory location,
* with JLS-correct handling for NaN, infinity, and overflow.
*
* @param os
* @param reg
* @param disp
*/
protected void popFromFPU(X86Assembler os, GPR reg, int disp) {
final String uid = "f2i_" + (++labelCounter) + "_";
final Label done = new Label(uid + "fix");
final Label overflow = new Label(uid + "ovf");
final Label isInf = new Label(uid + "inf");

os.writePUSH(X86Register.EAX);

// Save float copy at [reg+disp-4], then reload for FISTP
os.writeFSTP32(reg, disp - 4);
os.writeFLD32(reg, disp - 4);
os.writeFISTP32(reg, disp);

// Check if result == MIN_VALUE (indefinite integer)
os.writeMOV(X86Constants.BITS32, X86Register.EAX, reg, disp);
os.writeCMP_Const(X86Register.EAX, 0x80000000);
os.writeJCC(done, X86Constants.JNE);

// Check saved float for NaN/Infinity (exponent all 1s?)
os.writeMOV(X86Constants.BITS32, X86Register.EAX, reg, disp - 4);
os.writeAND(X86Register.EAX, 0x7F800000);
os.writeCMP_Const(X86Register.EAX, 0x7F800000);
os.writeJCC(overflow, X86Constants.JNE);

// NaN or Infinity
os.writeMOV(X86Constants.BITS32, X86Register.EAX, reg, disp - 4);
os.writeTEST(X86Register.EAX, 0x007FFFFF);
os.writeJCC(isInf, X86Constants.JZ);

// NaN -> 0
os.writeXOR(X86Register.EAX, X86Register.EAX);
os.writeMOV(X86Constants.BITS32, reg, disp, X86Register.EAX);
os.writeJMP(done);

// Infinity
os.setObjectRef(isInf);
os.writeMOV(X86Constants.BITS32, X86Register.EAX, reg, disp - 4);
os.writeTEST(X86Register.EAX, 0x80000000);
os.writeJCC(done, X86Constants.JNZ); // -Inf -> MIN_VALUE (correct)

// +Inf -> MAX_VALUE
os.writeMOV_Const(X86Register.EAX, 0x7FFFFFFF);
os.writeMOV(X86Constants.BITS32, reg, disp, X86Register.EAX);
os.writeJMP(done);

// Not NaN/Inf, but result is MIN_VALUE: overflow or genuine MIN_VALUE
os.setObjectRef(overflow);
os.writeMOV(X86Constants.BITS32, X86Register.EAX, reg, disp - 4);
os.writeTEST(X86Register.EAX, 0x80000000);
os.writeJCC(done, X86Constants.JNZ); // Negative -> keep MIN_VALUE

// Positive overflow -> MAX_VALUE
os.writeMOV_Const(X86Register.EAX, 0x7FFFFFFF);
os.writeMOV(X86Constants.BITS32, reg, disp, X86Register.EAX);

os.setObjectRef(done);
os.writePOP(X86Register.EAX);
}

/**
Expand Down
Loading
Loading