Inlining LabelTable into Interpreter and ClassFileWriter: to support jumps spanning over 64K in Interpreter in future LabelTable should be modified significantly and complexity of shared code would not justify it. In addition such inlining actually decrese total code size.

This commit is contained in:
igor%mir2.org 2003-12-08 14:16:53 +00:00
parent 44fae2ad68
commit 528efdfe62
3 changed files with 189 additions and 191 deletions

View File

@ -35,7 +35,6 @@
package org.mozilla.classfile;
import org.mozilla.javascript.LabelTable;
import org.mozilla.javascript.ObjToIntMap;
import org.mozilla.javascript.ObjArray;
import org.mozilla.javascript.UintMap;
@ -269,7 +268,7 @@ public class ClassFileWriter {
if (itsCurrentMethod == null)
throw new IllegalStateException("No method to stop");
itsLabels.fixLabelGotos(itsCodeBuffer);
fixLabelGotos();
itsMaxLocals = maxLocals;
@ -318,10 +317,19 @@ public class ClassFileWriter {
if (itsExceptionTableTop > 0) {
index = putInt16(itsExceptionTableTop, codeAttribute, index);
for (int i = 0; i < itsExceptionTableTop; i++) {
short startPC = itsExceptionTable[i].getStartPC(itsLabels);
short endPC = itsExceptionTable[i].getEndPC(itsLabels);
short handlerPC = itsExceptionTable[i].getHandlerPC(itsLabels);
short catchType = itsExceptionTable[i].getCatchType();
ExceptionTableEntry ete = itsExceptionTable[i];
short startPC = (short)getLabelPC(ete.itsStartLabel);
short endPC = (short)getLabelPC(ete.itsEndLabel);
short handlerPC = (short)getLabelPC(ete.itsHandlerLabel);
short catchType = ete.itsCatchType;
if (startPC == -1)
throw new IllegalStateException("start label not defined");
if (endPC == -1)
throw new IllegalStateException("end label not defined");
if (handlerPC == -1)
throw new IllegalStateException(
"handler label not defined");
index = putInt16(startPC, codeAttribute, index);
index = putInt16(endPC, codeAttribute, index);
index = putInt16(handlerPC, codeAttribute, index);
@ -390,7 +398,8 @@ public class ClassFileWriter {
itsCurrentMethod = null;
itsMaxStack = 0;
itsStackTop = 0;
itsLabels.clearLabels();
itsLabelTableTop = 0;
itsFixupTableTop = 0;
}
/**
@ -460,9 +469,9 @@ public class ClassFileWriter {
addToCodeInt16(theOperand);
}
else { // a label
int theLabel = theOperand & 0x7FFFFFFF;
int targetPC = itsLabels.getLabelPC(theLabel);
int targetPC = getLabelPC(theOperand);
if (DEBUGLABELS) {
int theLabel = theOperand & 0x7FFFFFFF;
System.out.println("Fixing branch to " +
theLabel + " at " + targetPC +
" from " + branchPC);
@ -472,7 +481,7 @@ public class ClassFileWriter {
addToCodeInt16(offset);
}
else {
itsLabels.addLabelFixup(theLabel, branchPC + 1);
addLabelFixup(theOperand, branchPC + 1);
addToCodeInt16(0);
}
}
@ -1134,23 +1143,43 @@ public class ClassFileWriter {
putInt32(jumpTarget - switchStart, itsCodeBuffer, caseOffset);
}
public int acquireLabel() {
return itsLabels.acquireLabel() | 0x80000000;
public int acquireLabel()
{
int top = itsLabelTableTop;
if (itsLabelTable == null || top == itsLabelTable.length) {
if (itsLabelTable == null) {
itsLabelTable = new int[MIN_LABEL_TABLE_SIZE];
}else {
int[] tmp = new int[itsLabelTable.length * 2];
System.arraycopy(itsLabelTable, 0, tmp, 0, top);
itsLabelTable = tmp;
}
}
itsLabelTableTop = top + 1;
itsLabelTable[top] = -1;
return top | 0x80000000;
}
public void markLabel(int label) {
if ((label & 0x80000000) != 0x80000000)
public void markLabel(int label)
{
if (!(label < 0))
throw new IllegalArgumentException("Bad label, no biscuit");
itsLabels.markLabel(label & 0x7FFFFFFF, itsCodeBufferTop);
label &= 0x7FFFFFFF;
if (label > itsLabelTableTop)
throw new IllegalArgumentException("Bad label");
if (itsLabelTable[label] != -1) {
throw new IllegalStateException("Can only mark label once");
}
itsLabelTable[label] = itsCodeBufferTop;
}
public void markLabel(int label, short stackTop) {
if ((label & 0x80000000) != 0x80000000)
throw new IllegalArgumentException("Bad label, no biscuit");
public void markLabel(int label, short stackTop)
{
markLabel(label);
itsStackTop = stackTop;
itsLabels.markLabel(label & 0x7FFFFFFF, itsCodeBufferTop);
}
public void markHandler(int theLabel) {
@ -1158,6 +1187,61 @@ public class ClassFileWriter {
markLabel(theLabel);
}
private int getLabelPC(int label)
{
if (!(label < 0))
throw new IllegalArgumentException("Bad label, no biscuit");
label &= 0x7FFFFFFF;
if (!(label < itsLabelTableTop))
throw new IllegalArgumentException("Bad label");
return itsLabelTable[label];
}
private void addLabelFixup(int label, int fixupSite)
{
if (!(label < 0))
throw new IllegalArgumentException("Bad label, no biscuit");
label &= 0x7FFFFFFF;
if (!(label < itsLabelTableTop))
throw new IllegalArgumentException("Bad label");
int top = itsFixupTableTop;
if (itsFixupTable == null || top == itsFixupTable.length) {
if (itsFixupTable == null) {
itsFixupTable = new long[MIN_FIXUP_TABLE_SIZE];
}else {
long[] tmp = new long[itsFixupTable.length * 2];
System.arraycopy(itsFixupTable, 0, tmp, 0, top);
itsFixupTable = tmp;
}
}
itsFixupTableTop = top + 1;
itsFixupTable[top] = ((long)label << 32) | fixupSite;
}
private void fixLabelGotos()
{
byte[] codeBuffer = itsCodeBuffer;
for (int i = 0; i < itsFixupTableTop; i++) {
long fixup = itsFixupTable[i];
int label = (int)(fixup >> 32);
int fixupSite = (int)fixup;
int pc = itsLabelTable[label];
if (pc == -1) {
// Unlocated label
throw new RuntimeException();
}
// -1 to get delta from instruction start
int offset = pc - (fixupSite - 1);
if ((short)offset != offset) {
throw new RuntimeException
("Program too complex: too big jump offset");
}
codeBuffer[fixupSite] = (byte)(offset >> 8);
codeBuffer[fixupSite + 1] = (byte)offset;
}
itsFixupTableTop = 0;
}
/**
* Get the current offset into the code of the current method.
*
@ -2449,7 +2533,14 @@ public class ClassFileWriter {
private short itsSuperClassIndex;
private short itsSourceFileNameIndex;
private LabelTable itsLabels = new LabelTable();
private static final int MIN_LABEL_TABLE_SIZE = 32;
private int[] itsLabelTable;
private int itsLabelTableTop;
// itsFixupTable[i] = (label_index << 32) | fixup_site
private static final int MIN_FIXUP_TABLE_SIZE = 40;
private long[] itsFixupTable;
private int itsFixupTableTop;
private char[] tmpCharBuffer = new char[64];
}
@ -2466,39 +2557,10 @@ final class ExceptionTableEntry
itsCatchType = catchType;
}
short getStartPC(LabelTable table)
{
short pc = (short)table.getLabelPC(itsStartLabel & 0x7FFFFFFF);
if (pc == -1)
throw new RuntimeException("start label not defined");
return pc;
}
short getEndPC(LabelTable table)
{
short pc = (short)table.getLabelPC(itsEndLabel & 0x7FFFFFFF);
if (pc == -1)
throw new RuntimeException("end label not defined");
return pc;
}
short getHandlerPC(LabelTable table)
{
short pc = (short)table.getLabelPC(itsHandlerLabel & 0x7FFFFFFF);
if (pc == -1)
throw new RuntimeException("handler label not defined");
return pc;
}
short getCatchType()
{
return itsCatchType;
}
private int itsStartLabel;
private int itsEndLabel;
private int itsHandlerLabel;
private short itsCatchType;
int itsStartLabel;
int itsEndLabel;
int itsHandlerLabel;
short itsCatchType;
}
final class ClassFileField

View File

@ -198,7 +198,7 @@ public class Interpreter
int theICodeTop = 0;
theICodeTop = generateICode(tree, theICodeTop);
itsLabels.fixLabelGotos(itsData.itsICode);
fixLabelGotos();
// add RETURN_POPV only to scripts as function always ends with RETURN
if (itsData.itsFunctionType == 0) {
theICodeTop = addToken(Token.RETURN_POPV, theICodeTop);
@ -1153,23 +1153,42 @@ public class Interpreter
private int getTargetLabel(Node.Target target)
{
int targetLabel = target.labelId;
if (targetLabel == -1) {
targetLabel = itsLabels.acquireLabel();
target.labelId = targetLabel;
int label = target.labelId;
if (label != -1) {
return label;
}
return targetLabel;
label = itsLabelTableTop;
if (itsLabelTable == null || label == itsLabelTable.length) {
if (itsLabelTable == null) {
itsLabelTable = new int[MIN_LABEL_TABLE_SIZE];
}else {
int[] tmp = new int[itsLabelTable.length * 2];
System.arraycopy(itsLabelTable, 0, tmp, 0, label);
itsLabelTable = tmp;
}
}
itsLabelTableTop = label + 1;
itsLabelTable[label] = -1;
target.labelId = label;
return label;
}
private void markTargetLabel(Node.Target target, int iCodeTop)
{
int label = getTargetLabel(target);
itsLabels.markLabel(label, iCodeTop);
if (itsLabelTable[label] != -1) {
// Can mark label only once
Kit.codeBug();
}
itsLabelTable[label] = iCodeTop;
}
private int addGoto(Node.Target target, int gotoOp, int iCodeTop)
{
int targetLabel = getTargetLabel(target);
int label = getTargetLabel(target);
if (!(label < itsLabelTableTop)) Kit.codeBug();
int targetPC = itsLabelTable[label];
int gotoPC = iCodeTop;
if (gotoOp > BASE_ICODE) {
@ -1177,17 +1196,52 @@ public class Interpreter
} else {
iCodeTop = addToken(gotoOp, iCodeTop);
}
int jumpSite = iCodeTop;
iCodeTop = addShort(0, iCodeTop);
int targetPC = itsLabels.getLabelPC(targetLabel);
if (targetPC != -1) {
recordJumpOffset(gotoPC + 1, targetPC - gotoPC);
recordJumpOffset(jumpSite, targetPC - gotoPC);
} else {
itsLabels.addLabelFixup(targetLabel, gotoPC + 1);
int top = itsFixupTableTop;
if (itsFixupTable == null || top == itsFixupTable.length) {
if (itsFixupTable == null) {
itsFixupTable = new long[MIN_FIXUP_TABLE_SIZE];
} else {
long[] tmp = new long[itsFixupTable.length * 2];
System.arraycopy(itsFixupTable, 0, tmp, 0, top);
itsFixupTable = tmp;
}
}
itsFixupTableTop = top + 1;
itsFixupTable[top] = ((long)label << 32) | jumpSite;
}
return iCodeTop;
}
private void fixLabelGotos()
{
byte[] codeBuffer = itsData.itsICode;
for (int i = 0; i < itsFixupTableTop; i++) {
long fixup = itsFixupTable[i];
int label = (int)(fixup >> 32);
int fixupSite = (int)fixup;
int pc = itsLabelTable[label];
if (pc == -1) {
// Unlocated label
throw new RuntimeException();
}
// -1 to get delta from instruction start
int offset = pc - (fixupSite - 1);
if ((short)offset != offset) {
throw new RuntimeException
("Program too complex: too big jump offset");
}
codeBuffer[fixupSite] = (byte)(offset >> 8);
codeBuffer[fixupSite + 1] = (byte)offset;
}
itsFixupTableTop = 0;
}
private int addForwardGoto(int gotoOp, int iCodeTop)
{
iCodeTop = addToken(gotoOp, iCodeTop);
@ -3244,12 +3298,19 @@ public class Interpreter
private int itsStackDepth = 0;
private int itsWithDepth = 0;
private int itsLineNumber = 0;
private LabelTable itsLabels = new LabelTable();
private int itsDoubleTableTop;
private ObjToIntMap itsStrings = new ObjToIntMap(20);
private String lastAddString;
private int itsLocalTop;
private static final int MIN_LABEL_TABLE_SIZE = 32;
private static final int MIN_FIXUP_TABLE_SIZE = 40;
private int[] itsLabelTable;
private int itsLabelTableTop;
// itsFixupTable[i] = (label_index << 32) | fixup_site
private long[] itsFixupTable;
private int itsFixupTableTop;
private int itsExceptionTableTop;
// 5 = space for try start/end, catch begin, finally begin and with depth
private static final int EXCEPTION_SLOT_SIZE = 6;

View File

@ -1,125 +0,0 @@
/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is Rhino code, released
* May 6, 1999.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
* Roger Lawrence
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU Public License (the "GPL"), in which case the
* provisions of the GPL are applicable instead of those above.
* If you wish to allow use of your version of this file only
* under the terms of the GPL and not to allow others to use your
* version of this file under the NPL, indicate your decision by
* deleting the provisions above and replace them with the notice
* and other provisions required by the GPL. If you do not delete
* the provisions above, a recipient may use your version of this
* file under either the NPL or the GPL.
*/
package org.mozilla.javascript;
public class LabelTable {
public int acquireLabel()
{
int top = itsLabelTableTop;
if (itsLabelTable == null || top == itsLabelTable.length) {
if (itsLabelTable == null) {
itsLabelTable = new int[MIN_LABEL_TABLE_SIZE];
}else {
int[] tmp = new int[itsLabelTable.length * 2];
System.arraycopy(itsLabelTable, 0, tmp, 0, top);
itsLabelTable = tmp;
}
}
itsLabelTableTop = top + 1;
itsLabelTable[top] = -1;
return top;
}
public int getLabelPC(int label) {
if (label > itsLabelTableTop) throw new RuntimeException();
return itsLabelTable[label];
}
public void markLabel(int label, int pc) {
if (label > itsLabelTableTop || pc < 0) throw new RuntimeException();
if (itsLabelTable[label] != -1) {
// Can mark label only once
throw new RuntimeException();
}
itsLabelTable[label] = pc;
}
public void addLabelFixup(int label, int fixupSite) {
if (label > itsLabelTableTop || fixupSite < 0) {
throw new RuntimeException();
}
int top = itsFixupTableTop;
if (itsFixupTable == null || top == itsFixupTable.length) {
if (itsFixupTable == null) {
itsFixupTable = new long[MIN_FIXUP_TABLE_SIZE];
}else {
long[] tmp = new long[itsFixupTable.length * 2];
System.arraycopy(itsFixupTable, 0, tmp, 0, top);
itsFixupTable = tmp;
}
}
itsFixupTableTop = top + 1;
itsFixupTable[top] = ((long)label << 32) | fixupSite;
}
public void fixLabelGotos(byte[] codeBuffer) {
for (int i = 0; i < itsFixupTableTop; i++) {
long fixup = itsFixupTable[i];
int label = (int)(fixup >> 32);
int fixupSite = (int)fixup;
int pc = itsLabelTable[label];
if (pc == -1) {
// Unlocated label
throw new RuntimeException();
}
// -1 to get delta from instruction start
int offset = pc - (fixupSite - 1);
if ((short)offset != offset) {
throw new RuntimeException
("Program too complex: too big jump offset");
}
codeBuffer[fixupSite] = (byte)(offset >> 8);
codeBuffer[fixupSite + 1] = (byte)offset;
}
itsFixupTableTop = 0;
}
public void clearLabels() {
itsLabelTableTop = 0;
itsFixupTableTop = 0;
}
private static final int MIN_LABEL_TABLE_SIZE = 32;
private int[] itsLabelTable;
private int itsLabelTableTop;
// itsFixupTable[i] = (label_index << 32) | fixup_site
private static final int MIN_FIXUP_TABLE_SIZE = 40;
private long[] itsFixupTable;
private int itsFixupTableTop;
}