diff --git a/app/build.gradle b/app/build.gradle index 914c5cbe6..fb830158f 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -8,8 +8,8 @@ android { applicationId "net.kdt.pojavlaunch" minSdkVersion 21 targetSdkVersion 26 - versionCode 156235 - versionName "2.5.0_preview1_6397b_20200417" + versionCode 1 + versionName "3.0.0_preview1_1b_20200426" } buildTypes { @@ -21,18 +21,12 @@ android { debuggable = true } } - - // Keep the following configuration in order to might make Minecraft 1.12 support. - compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 - } } dependencies { - implementation 'javax.annotation:javax.annotation-api:1.3.2' - implementation 'commons-codec:commons-codec:1.14' - implementation 'com.wu-man:android-bsf-api:3.1.3' + // implementation 'javax.annotation:javax.annotation-api:1.3.2' + // implementation 'commons-codec:commons-codec:1.14' + // implementation 'com.wu-man:android-bsf-api:3.1.3' implementation 'com.android.support:support-v4:26.0.0' implementation 'com.android.support:preference-v7:26.0.0' implementation 'com.android.support:appcompat-v7:26.0.0' diff --git a/app/src/main/java/android/graphics/PixelXorXfermode.java b/app/src/main/java/android/graphics/PixelXorXfermode.java deleted file mode 100644 index 2337c8d06..000000000 --- a/app/src/main/java/android/graphics/PixelXorXfermode.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package android.graphics; -import java.lang.reflect.*; -/** - * PixelXorXfermode implements a simple pixel xor (op ^ src ^ dst). - * This transformation does not follow premultiplied conventions, therefore - * this mode *always* returns an opaque color (alpha == 255). Thus it is - * not really usefull for operating on blended colors. - */ -@Deprecated -public class PixelXorXfermode extends Xfermode { - public PixelXorXfermode(int opColor) { - try { - Field field_nativeInstance = getClass().getDeclaredField("native_instance"); - field_nativeInstance.setAccessible(true); - field_nativeInstance.set(null, nativeCreate(opColor)); - } catch (Exception e) { - e.printStackTrace(); - } - } - private static native int nativeCreate(int opColor); -} diff --git a/app/src/main/java/com/android/internal/awt/AndroidGraphics2D.java b/app/src/main/java/com/android/internal/awt/AndroidGraphics2D.java deleted file mode 100644 index 40c2b8494..000000000 --- a/app/src/main/java/com/android/internal/awt/AndroidGraphics2D.java +++ /dev/null @@ -1,1355 +0,0 @@ -/* - * Copyright 2007, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.internal.awt; - -import com.android.internal.awt.AndroidGraphicsConfiguration; -// import com.android.internal.graphics.NativeUtils; - -import java.awt.AlphaComposite; -import java.awt.BasicStroke; -import java.awt.Color; -import java.awt.Composite; -import java.awt.Font; -import java.awt.FontMetrics; -import java.awt.Graphics; -import java.awt.Graphics2D; -import java.awt.GraphicsConfiguration; -import java.awt.Image; -import java.awt.Polygon; -import java.awt.Rectangle; -import java.awt.RenderingHints; -import java.awt.Shape; -import java.awt.Stroke; -import java.awt.font.FontRenderContext; -import java.awt.font.GlyphVector; -import java.awt.geom.AffineTransform; -import java.awt.geom.Area; -import java.awt.geom.GeneralPath; -import java.awt.geom.NoninvertibleTransformException; -import java.awt.geom.PathIterator; -import java.awt.image.AffineTransformOp; -import java.awt.image.BufferedImage; -import java.awt.image.BufferedImageOp; -import java.awt.image.DataBuffer; -import java.awt.image.DirectColorModel; -import java.awt.image.ImageObserver; -import java.awt.image.Raster; -import java.awt.image.RenderedImage; -import java.awt.image.SinglePixelPackedSampleModel; -import java.awt.image.WritableRaster; -import java.awt.image.renderable.RenderableImage; -import java.text.AttributedCharacterIterator; -import java.util.Map; - -import org.apache.harmony.awt.gl.ImageSurface; -import org.apache.harmony.awt.gl.MultiRectArea; -import org.apache.harmony.awt.gl.Surface; -import org.apache.harmony.awt.gl.font.AndroidGlyphVector; -import org.apache.harmony.awt.gl.font.FontMetricsImpl; -import org.apache.harmony.awt.gl.image.OffscreenImage; - -import android.graphics.Bitmap; -import android.graphics.Canvas; -import android.graphics.Matrix; -import android.graphics.Paint; -import android.graphics.Path; - -import android.graphics.Rect; -import android.graphics.RectF; -import android.graphics.Region; -import android.graphics.Typeface; -import android.graphics.PixelXorXfermode; -import android.view.Display; -import android.view.WindowManager; -import android.content.Context; - -public class AndroidGraphics2D extends Graphics2D { - - private int displayWidth, displayHeight; - - protected Surface dstSurf = null; - protected MultiRectArea clip = null; - - protected Composite composite = AlphaComposite.SrcOver; - protected AffineTransform transform = new AffineTransform(); - - private static AndroidGraphics2D mAg; - private static Canvas mC; - - // Android Paint - public static Paint mP; - - private static java.awt.Font mFnt; - - // Cached Matrix - public static Matrix mM; - private static FontMetrics mFm; - private static RenderingHints mRh; - private static Color mBc; - - private Area mCurrClip; - - public final static double RAD_360 = Math.PI / 180 * 360; - - // Image drawing - private AndroidJavaBlitter blitter; - private DirectColorModel cm; - private SinglePixelPackedSampleModel sm; - private WritableRaster wr; - - - public static AndroidGraphics2D getInstance() { - if (mAg == null) { - throw new RuntimeException("AndroidGraphics2D not instantiated!"); - } - return mAg; - } - - public static AndroidGraphics2D getInstance(Context ctx, Canvas c, Paint p) { - if (c == null || ctx == null) { - throw new RuntimeException( - "Illegal argument, Canvas cannot be null!"); - } - mAg = new AndroidGraphics2D(ctx, c, p); - return mAg; - } - - private AndroidGraphics2D(Context ctx, Canvas c, Paint p) { - super(); - mC = c; - mP = p; - mM = new Matrix(); - mM.reset(); - mM = mC.getMatrix(); - Rect r = mC.getClipBounds(); - int cl[] = {-1, r.top, r.left, -2, r.top, r.right, -2, r.bottom, r.right, -2, r.bottom, r.left}; - mCurrClip = new Area(createShape(cl)); - if(ctx != null) { - WindowManager wm = (WindowManager)ctx.getSystemService(Context.WINDOW_SERVICE); - Display d = wm.getDefaultDisplay(); - displayWidth = d.getWidth(); - displayHeight = d.getHeight(); - } - blitter = new AndroidJavaBlitter(c); - cm = new DirectColorModel(32, 0xff0000, 0xff00, 0xff, 0xff000000); - sm = new SinglePixelPackedSampleModel( - DataBuffer.TYPE_INT, displayWidth, displayHeight, cm.getMasks()); - wr = Raster.createWritableRaster(sm, null); - dstSurf = new ImageSurface(cm, wr); - } - - @Override - public void addRenderingHints(Map hints) { - if (mRh == null) { - mRh = (RenderingHints) hints; - } - mRh.add((RenderingHints) hints); - } - - public float[] getMatrix() { - float[] f = new float[9]; - mC.getMatrix().getValues(f); - return f; - } - - /** - * - * @return a Matrix in Android format - */ - public float[] getInverseMatrix() { - AffineTransform af = new AffineTransform(createAWTMatrix(getMatrix())); - try { - af = af.createInverse(); - } catch (NoninvertibleTransformException e) { - } - return createMatrix(af); - } - - private Path getPath(Shape s) { - Path path = new Path(); - PathIterator pi = s.getPathIterator(null); - while (pi.isDone() == false) { - getCurrentSegment(pi, path); - pi.next(); - } - return path; - } - - private void getCurrentSegment(PathIterator pi, Path path) { - float[] coordinates = new float[6]; - int type = pi.currentSegment(coordinates); - switch (type) { - case PathIterator.SEG_MOVETO: - path.moveTo(coordinates[0], coordinates[1]); - break; - case PathIterator.SEG_LINETO: - path.lineTo(coordinates[0], coordinates[1]); - break; - case PathIterator.SEG_QUADTO: - path.quadTo(coordinates[0], coordinates[1], coordinates[2], - coordinates[3]); - break; - case PathIterator.SEG_CUBICTO: - path.cubicTo(coordinates[0], coordinates[1], coordinates[2], - coordinates[3], coordinates[4], coordinates[5]); - break; - case PathIterator.SEG_CLOSE: - path.close(); - break; - default: - break; - } - } - - private Shape createShape(int[] arr) { - Shape s = new GeneralPath(); - for(int i = 0; i < arr.length; i++) { - int type = arr[i]; - switch (type) { - case -1: - //MOVETO - ((GeneralPath)s).moveTo(arr[++i], arr[++i]); - break; - case -2: - //LINETO - ((GeneralPath)s).lineTo(arr[++i], arr[++i]); - break; - case -3: - //QUADTO - ((GeneralPath)s).quadTo(arr[++i], arr[++i], arr[++i], - arr[++i]); - break; - case -4: - //CUBICTO - ((GeneralPath)s).curveTo(arr[++i], arr[++i], arr[++i], - arr[++i], arr[++i], arr[++i]); - break; - case -5: - //CLOSE - return s; - default: - break; - } - } - return s; - } - /* - public int[] getPixels() { - return mC.getPixels(); - }*/ - - public static float getRadian(float degree) { - return (float) ((Math.PI / 180) * degree); - } - - private Shape getShape() { - return null; - } - - public static float getDegree(float radian) { - return (float) ((180 / Math.PI) * radian); - } - - /* - * Degree in radian - */ - public static float getEllipsisX(float degree, float princAxis) { - return (float) Math.cos(degree) * princAxis; - } - - public static float getEllipsisY(float degree, float conAxis) { - return (float) Math.sin(degree) * conAxis; - } - - @Override - public void clip(Shape s) { - mC.clipPath(getPath(s)); - } - - public void setCanvas(Canvas c) { - mC = c; - } - - @Override - public void draw(Shape s) { - if (mP == null) { - mP = new Paint(); - } - Paint.Style tmp = mP.getStyle(); - mP.setStyle(Paint.Style.STROKE); - mC.drawPath(getPath(s), mP); - mP.setStyle(tmp); - } -/* - private ArrayList getSegments(Shape s) { - ArrayList arr = new ArrayList(); - PathIterator pi = s.getPathIterator(null); - while (pi.isDone() == false) { - getCurrentSegment(pi, arr); - pi.next(); - } - return arr; - } - - private void getCurrentSegment(PathIterator pi, ArrayList arr) { - float[] coordinates = new float[6]; - int type = pi.currentSegment(coordinates); - switch (type) { - case PathIterator.SEG_MOVETO: - arr.add(new Integer(-1)); - break; - case PathIterator.SEG_LINETO: - arr.add(new Integer(-2)); - break; - case PathIterator.SEG_QUADTO: - arr.add(new Integer(-3)); - break; - case PathIterator.SEG_CUBICTO: - arr.add(new Integer(-4)); - break; - case PathIterator.SEG_CLOSE: - arr.add(new Integer(-5)); - break; - default: - break; - } - } -*/ - /* - * Convenience method, not standard AWT - */ - public void draw(Path s) { - if (mP == null) { - mP = new Paint(); - } - Paint.Style tmp = mP.getStyle(); - mP.setStyle(Paint.Style.STROKE); - s.transform(mM); - mC.drawPath(s, mP); - mP.setStyle(tmp); - } - - @Override - public void drawGlyphVector(GlyphVector g, float x, float y) { - // TODO draw at x, y - // draw(g.getOutline()); - /* - Matrix matrix = new Matrix(); - matrix.setTranslate(x, y); - Path pth = getPath(g.getOutline()); - pth.transform(matrix); - draw(pth); - */ - Path path = new Path(); - char[] c = ((AndroidGlyphVector)g).getGlyphs(); - mP.getTextPath(c, 0, c.length, x, y, path); - mC.drawPath(path, mP); - } - - @Override - public void drawRenderableImage(RenderableImage img, AffineTransform xform) { - throw new RuntimeException("Not implemented!"); - } - - @Override - public void drawRenderedImage(RenderedImage img, AffineTransform xform) { - throw new RuntimeException("Not implemented!"); - } - - @Override - public void drawString(AttributedCharacterIterator iterator, float x, - float y) { - throw new RuntimeException("AttributedCharacterIterator not supported!"); - - } - - @Override - public void drawString(AttributedCharacterIterator iterator, int x, int y) { - throw new RuntimeException("AttributedCharacterIterator not supported!"); - - } - - @Override - public void drawString(String s, float x, float y) { - if (mP == null) { - mP = new Paint(); - } - Paint.Style tmp = mP.getStyle(); - - mP.setStyle(Paint.Style.FILL); - Path pth = new Path(); - mP.getTextPath(s, 0, s.length(), x, y, pth); - mC.drawPath(pth, mP); - mP.setStyle(tmp); - } - - @Override - public void drawString(String str, int x, int y) { - if (mP == null) { - mP = new Paint(); - } - Paint.Style tmp = mP.getStyle(); - mP.setStrokeWidth(0); - - mC.drawText(str.toCharArray(), 0, str.toCharArray().length, x, y, - mP); - mP.setStyle(tmp); - } - - @Override - public void fill(Shape s) { - if (mP == null) { - mP = new Paint(); - } - Paint.Style tmp = mP.getStyle(); - mP.setStyle(Paint.Style.FILL); - mC.drawPath(getPath(s), mP); - mP.setStyle(tmp); - } - - @Override - public Color getBackground() { - return mBc; - } - - @Override - public Composite getComposite() { - throw new RuntimeException("Composite not implemented!"); - } - - @Override - public GraphicsConfiguration getDeviceConfiguration() { - return new AndroidGraphicsConfiguration(); - } - - @Override - public FontRenderContext getFontRenderContext() { - return new FontRenderContext(getTransform(), mP.isAntiAlias(), true); - } - - @Override - public java.awt.Paint getPaint() { - throw new RuntimeException("AWT Paint not implemented in Android!"); - } - - public static Canvas getAndroidCanvas() { - return mC; - } - - public static Paint getAndroidPaint() { - return mP; - } - - @Override - public RenderingHints getRenderingHints() { - return mRh; - } - - @Override - public Stroke getStroke() { - if (mP != null) { - return new BasicStroke(mP.getStrokeWidth(), mP.getStrokeCap() - .ordinal(), mP.getStrokeJoin().ordinal()); - } - return null; - } - - @Override - public AffineTransform getTransform() { - return new AffineTransform(createAWTMatrix(getMatrix())); - } - - @Override - public boolean hit(Rectangle rect, Shape s, boolean onStroke) { - // ???AWT TODO check if on stroke - return s.intersects(rect.getX(), rect.getY(), rect.getWidth(), rect - .getHeight()); - } - - @Override - public void rotate(double theta) { - mM.preRotate((float) AndroidGraphics2D - .getDegree((float) (RAD_360 - theta))); - mC.concat(mM); - } - - @Override - public void rotate(double theta, double x, double y) { - mM.preRotate((float) AndroidGraphics2D.getDegree((float) theta), - (float) x, (float) y); - mC.concat(mM); - } - - @Override - public void scale(double sx, double sy) { - mM.setScale((float) sx, (float) sy); - mC.concat(mM); - } - - @Override - public void setBackground(Color color) { - mBc = color; - mC.clipRect(new Rect(0, 0, mC.getWidth(), mC.getHeight())); - // TODO don't limit to current clip - mC.drawARGB(color.getAlpha(), color.getRed(), color.getGreen(), color - .getBlue()); - } - - @Override - public void setComposite(Composite comp) { - throw new RuntimeException("Composite not implemented!"); - } - - public void setSpaint(Paint paint) { - mP = paint; - } - - @Override - public void setPaint(java.awt.Paint paint) { - setColor((Color)paint); - } - - @Override - public Object getRenderingHint(RenderingHints.Key key) { - if (mRh == null) { - return null; - } - return mRh.get(key); - } - - @Override - public void setRenderingHint(RenderingHints.Key hintKey, Object hintValue) { - if (mRh == null) { - mRh = new RenderingHints(hintKey, hintValue); - } else { - mRh.put(hintKey, hintValue); - } - applyHints(); - } - - @Override - public void setRenderingHints(Map hints) { - mRh = (RenderingHints) hints; - applyHints(); - } - - private void applyHints() { - Object o; - - // TODO do something like this: - /* - * Set s = mRh.keySet(); Iterator it = s.iterator(); while(it.hasNext()) { - * o = it.next(); } - */ - - // ///////////////////////////////////////////////////////////////////// - // not supported in skia - /* - * o = mRh.get(RenderingHints.KEY_ALPHA_INTERPOLATION); if - * (o.equals(RenderingHints.VALUE_ALPHA_INTERPOLATION_DEFAULT)) { } else - * if (o.equals(RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY)) { } - * else if (o.equals(RenderingHints.VALUE_ALPHA_INTERPOLATION_SPEED)) { } - * - * o = mRh.get(RenderingHints.KEY_COLOR_RENDERING); if - * (o.equals(RenderingHints.VALUE_COLOR_RENDER_DEFAULT)) { } else if - * (o.equals(RenderingHints.VALUE_COLOR_RENDER_QUALITY)) { } else if - * (o.equals(RenderingHints.VALUE_COLOR_RENDER_SPEED)) { } - * - * o = mRh.get(RenderingHints.KEY_DITHERING); if - * (o.equals(RenderingHints.VALUE_DITHER_DEFAULT)) { } else if - * (o.equals(RenderingHints.VALUE_DITHER_DISABLE)) { } else if - * (o.equals(RenderingHints.VALUE_DITHER_ENABLE)) { } - * - * o = mRh.get(RenderingHints.KEY_FRACTIONALMETRICS); if - * (o.equals(RenderingHints.VALUE_FRACTIONALMETRICS_DEFAULT)) { } else - * if (o.equals(RenderingHints.VALUE_FRACTIONALMETRICS_OFF)) { } else if - * (o.equals(RenderingHints.VALUE_FRACTIONALMETRICS_ON)) { } - * - * o = mRh.get(RenderingHints.KEY_INTERPOLATION); if - * (o.equals(RenderingHints.VALUE_INTERPOLATION_BICUBIC)) { } else if - * (o.equals(RenderingHints.VALUE_INTERPOLATION_BILINEAR)) { } else if - * (o .equals(RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR)) { } - * - * o = mRh.get(RenderingHints.KEY_RENDERING); if - * (o.equals(RenderingHints.VALUE_RENDER_DEFAULT)) { } else if - * (o.equals(RenderingHints.VALUE_RENDER_QUALITY)) { } else if - * (o.equals(RenderingHints.VALUE_RENDER_SPEED)) { } - * - * o = mRh.get(RenderingHints.KEY_STROKE_CONTROL); if - * (o.equals(RenderingHints.VALUE_STROKE_DEFAULT)) { } else if - * (o.equals(RenderingHints.VALUE_STROKE_NORMALIZE)) { } else if - * (o.equals(RenderingHints.VALUE_STROKE_PURE)) { } - */ - - o = mRh.get(RenderingHints.KEY_ANTIALIASING); - if (o != null) { - if (o.equals(RenderingHints.VALUE_ANTIALIAS_DEFAULT)) { - mP.setAntiAlias(false); - } else if (o.equals(RenderingHints.VALUE_ANTIALIAS_OFF)) { - mP.setAntiAlias(false); - } else if (o.equals(RenderingHints.VALUE_ANTIALIAS_ON)) { - mP.setAntiAlias(true); - } - } - - o = mRh.get(RenderingHints.KEY_TEXT_ANTIALIASING); - if (o != null) { - if (o.equals(RenderingHints.VALUE_TEXT_ANTIALIAS_DEFAULT)) { - mP.setAntiAlias(false); - } else if (o.equals(RenderingHints.VALUE_TEXT_ANTIALIAS_OFF)) { - mP.setAntiAlias(false); - } else if (o.equals(RenderingHints.VALUE_TEXT_ANTIALIAS_ON)) { - mP.setAntiAlias(true); - } - } - } - - @Override - public void setStroke(Stroke s) { - if (mP == null) { - mP = new Paint(); - } - BasicStroke bs = (BasicStroke) s; - mP.setStyle(Paint.Style.STROKE); - mP.setStrokeWidth(bs.getLineWidth()); - - int cap = bs.getEndCap(); - if (cap == 0) { - mP.setStrokeCap(Paint.Cap.BUTT); - } else if (cap == 1) { - mP.setStrokeCap(Paint.Cap.ROUND); - } else if (cap == 2) { - mP.setStrokeCap(Paint.Cap.SQUARE); - } - - int join = bs.getLineJoin(); - if (join == 0) { - mP.setStrokeJoin(Paint.Join.MITER); - } else if (join == 1) { - mP.setStrokeJoin(Paint.Join.ROUND); - } else if (join == 2) { - mP.setStrokeJoin(Paint.Join.BEVEL); - } - } - - public static float[] createMatrix(AffineTransform Tx) { - double[] at = new double[9]; - Tx.getMatrix(at); - float[] f = new float[at.length]; - f[0] = (float) at[0]; - f[1] = (float) at[2]; - f[2] = (float) at[4]; - f[3] = (float) at[1]; - f[4] = (float) at[3]; - f[5] = (float) at[5]; - f[6] = 0; - f[7] = 0; - f[8] = 1; - return f; - } - - private float[] createAWTMatrix(float[] matrix) { - float[] at = new float[9]; - at[0] = matrix[0]; - at[1] = matrix[3]; - at[2] = matrix[1]; - at[3] = matrix[4]; - at[4] = matrix[2]; - at[5] = matrix[5]; - at[6] = 0; - at[7] = 0; - at[8] = 1; - return at; - } - - public static Matrix createMatrixObj(AffineTransform Tx) { - Matrix m = new Matrix(); - m.reset(); - m.setValues(createMatrix(Tx)); - return m; - } - - @Override - public void setTransform(AffineTransform Tx) { - mM.reset(); - /* - * if(Tx.isIdentity()) { mM = new Matrix(); } - */ - mM.setValues(createMatrix(Tx)); - Matrix m = new Matrix(); - m.setValues(getInverseMatrix()); - mC.concat(m); - mC.concat(mM); - } - - @Override - public void shear(double shx, double shy) { - mM.setSkew((float) shx, (float) shy); - mC.concat(mM); - } - - @Override - public void transform(AffineTransform Tx) { - Matrix m = new Matrix(); - m.setValues(createMatrix(Tx)); - mC.concat(m); - } - - @Override - public void translate(double tx, double ty) { - mM.setTranslate((float) tx, (float) ty); - mC.concat(mM); - } - - @Override - public void translate(int x, int y) { - mM.setTranslate((float) x, (float) y); - mC.concat(mM); - } - - @Override - public void clearRect(int x, int y, int width, int height) { - mC.clipRect(x, y, x + width, y + height); - if (mBc != null) { - mC.drawARGB(mBc.getAlpha(), mBc.getBlue(), mBc.getGreen(), mBc - .getRed()); - } else { - mC.drawARGB(0xff, 0xff, 0xff, 0xff); - } - } - - @Override - public void clipRect(int x, int y, int width, int height) { - int cl[] = {-1, x, y, -2, x, y + width, -2, x + height, y + width, -2, x + height, y}; - Shape shp = createShape(cl); - mCurrClip.intersect(new Area(shp)); - mC.clipRect(new Rect(x, y, x + width, y + height), Region.Op.INTERSECT); - } - - @Override - public void copyArea(int sx, int sy, int width, int height, int dx, int dy) { - copyArea(mC, sx, sy, width + dx, height + dy, dx, dy); - } - - @Override - public Graphics create() { - return this; - } - - @Override - public void dispose() { - // mC = null; - mP = null; - } - - @Override - public void drawArc(int x, int y, int width, int height, int sa, int ea) { - if (mP == null) { - mP = new Paint(); - } - mP.setStrokeWidth(0); - mC.drawArc(new RectF(x, y, x + width, y + height), 360 - (ea + sa), - ea, true, mP); - } - - - // ???AWT: only used for debuging, delete in final version - public void drawBitmap(Bitmap bm, float x, float y, Paint p) { - mC.drawBitmap(bm, x, y, null); - } - - @Override - public boolean drawImage(Image image, int x, int y, Color bgcolor, - ImageObserver imageObserver) { - - if(image == null) { - return true; - } - - boolean done = false; - boolean somebits = false; - Surface srcSurf = null; - if(image instanceof OffscreenImage){ - OffscreenImage oi = (OffscreenImage) image; - if((oi.getState() & ImageObserver.ERROR) != 0) { - return false; - } - done = oi.prepareImage(imageObserver); - somebits = (oi.getState() & ImageObserver.SOMEBITS) != 0; - srcSurf = oi.getImageSurface(); - }else{ - done = true; - srcSurf = Surface.getImageSurface(image); - } - - if(done || somebits) { - int w = srcSurf.getWidth(); - int h = srcSurf.getHeight(); - - blitter.blit(0, 0, srcSurf, x, y, dstSurf, w, h, (AffineTransform) transform.clone(), - composite, bgcolor, clip); - } - return done; - } - - @Override - public boolean drawImage(Image image, int x, int y, ImageObserver imageObserver) { - return drawImage(image, x, y, null, imageObserver); - } - - @Override - public boolean drawImage(Image image, int x, int y, int width, int height, - Color bgcolor, ImageObserver imageObserver) { - - if(image == null) { - return true; - } - if(width == 0 || height == 0) { - return true; - } - - boolean done = false; - boolean somebits = false; - Surface srcSurf = null; - - if(image instanceof OffscreenImage){ - OffscreenImage oi = (OffscreenImage) image; - if((oi.getState() & ImageObserver.ERROR) != 0) { - return false; - } - done = oi.prepareImage(imageObserver); - somebits = (oi.getState() & ImageObserver.SOMEBITS) != 0; - srcSurf = oi.getImageSurface(); - }else{ - done = true; - srcSurf = Surface.getImageSurface(image); - } - - if(done || somebits) { - int w = srcSurf.getWidth(); - int h = srcSurf.getHeight(); - if(w == width && h == height){ - blitter.blit(0, 0, srcSurf, x, y, dstSurf, w, h, - (AffineTransform) transform.clone(), - composite, bgcolor, clip); - }else{ - AffineTransform xform = new AffineTransform(); - xform.setToScale((float)width / w, (float)height / h); - blitter.blit(0, 0, srcSurf, x, y, dstSurf, w, h, - (AffineTransform) transform.clone(), - xform, composite, bgcolor, clip); - } - } - return done; - } - - @Override - public boolean drawImage(Image image, int x, int y, int width, int height, - ImageObserver imageObserver) { - return drawImage(image, x, y, width, height, null, imageObserver); - } - - @Override - public boolean drawImage(Image image, int dx1, int dy1, int dx2, int dy2, - int sx1, int sy1, int sx2, int sy2, Color bgcolor, - ImageObserver imageObserver) { - - if(image == null) { - return true; - } - if(dx1 == dx2 || dy1 == dy2 || sx1 == sx2 || sy1 == sy2) { - return true; - } - - boolean done = false; - boolean somebits = false; - Surface srcSurf = null; - if(image instanceof OffscreenImage){ - OffscreenImage oi = (OffscreenImage) image; - if((oi.getState() & ImageObserver.ERROR) != 0) { - return false; - } - done = oi.prepareImage(imageObserver); - somebits = (oi.getState() & ImageObserver.SOMEBITS) != 0; - srcSurf = oi.getImageSurface(); - }else{ - done = true; - srcSurf = Surface.getImageSurface(image); - } - - if(done || somebits) { - - int dstX = dx1; - int dstY = dy1; - int srcX = sx1; - int srcY = sy1; - - int dstW = dx2 - dx1; - int dstH = dy2 - dy1; - int srcW = sx2 - sx1; - int srcH = sy2 - sy1; - - if(srcW == dstW && srcH == dstH){ - blitter.blit(srcX, srcY, srcSurf, dstX, dstY, dstSurf, srcW, srcH, - (AffineTransform) transform.clone(), - composite, bgcolor, clip); - }else{ - AffineTransform xform = new AffineTransform(); - xform.setToScale((float)dstW / srcW, (float)dstH / srcH); - blitter.blit(srcX, srcY, srcSurf, dstX, dstY, dstSurf, srcW, srcH, - (AffineTransform) transform.clone(), - xform, composite, bgcolor, clip); - } - } - return done; - } - - @Override - public boolean drawImage(Image image, int dx1, int dy1, int dx2, int dy2, - int sx1, int sy1, int sx2, int sy2, ImageObserver imageObserver) { - - return drawImage(image, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, null, - imageObserver); - } - - @Override - public void drawImage(BufferedImage bufImage, BufferedImageOp op, - int x, int y) { - - if(bufImage == null) { - return; - } - - if(op == null) { - drawImage(bufImage, x, y, null); - } else if(op instanceof AffineTransformOp){ - AffineTransformOp atop = (AffineTransformOp) op; - AffineTransform xform = atop.getTransform(); - Surface srcSurf = Surface.getImageSurface(bufImage); - int w = srcSurf.getWidth(); - int h = srcSurf.getHeight(); - blitter.blit(0, 0, srcSurf, x, y, dstSurf, w, h, - (AffineTransform) transform.clone(), xform, - composite, null, clip); - } else { - bufImage = op.filter(bufImage, null); - Surface srcSurf = Surface.getImageSurface(bufImage); - int w = srcSurf.getWidth(); - int h = srcSurf.getHeight(); - blitter.blit(0, 0, srcSurf, x, y, dstSurf, w, h, - (AffineTransform) transform.clone(), - composite, null, clip); - } - } - - @Override - public boolean drawImage(Image image, AffineTransform trans, - ImageObserver imageObserver) { - - if(image == null) { - return true; - } - if(trans == null || trans.isIdentity()) { - return drawImage(image, 0, 0, imageObserver); - } - - boolean done = false; - boolean somebits = false; - Surface srcSurf = null; - if(image instanceof OffscreenImage){ - OffscreenImage oi = (OffscreenImage) image; - if((oi.getState() & ImageObserver.ERROR) != 0) { - return false; - } - done = oi.prepareImage(imageObserver); - somebits = (oi.getState() & ImageObserver.SOMEBITS) != 0; - srcSurf = oi.getImageSurface(); - }else{ - done = true; - srcSurf = Surface.getImageSurface(image); - } - - if(done || somebits) { - int w = srcSurf.getWidth(); - int h = srcSurf.getHeight(); - AffineTransform xform = (AffineTransform) transform.clone(); - xform.concatenate(trans); - blitter.blit(0, 0, srcSurf, 0, 0, dstSurf, w, h, xform, composite, - null, clip); - } - return done; - } - - @Override - public void drawLine(int x1, int y1, int x2, int y2) { - if (mP == null) { - mP = new Paint(); - } - mC.drawLine(x1, y1, x2, y2, mP); - } - - @Override - public void drawOval(int x, int y, int width, int height) { - if (mP == null) { - mP = new Paint(); - } - mP.setStyle(Paint.Style.STROKE); - mC.drawOval(new RectF(x, y, x + width, y + height), mP); - } - - @Override - public void drawPolygon(int[] xpoints, int[] ypoints, int npoints) { - if (mP == null) { - mP = new Paint(); - } - mC.drawLine(xpoints[npoints - 1], ypoints[npoints - 1], xpoints[0], - ypoints[0], mP); - for (int i = 0; i < npoints - 1; i++) { - mC.drawLine(xpoints[i], ypoints[i], xpoints[i + 1], - ypoints[i + 1], mP); - } - } - - @Override - public void drawPolyline(int[] xpoints, int[] ypoints, int npoints) { - for (int i = 0; i < npoints - 1; i++) { - drawLine(xpoints[i], ypoints[i], xpoints[i + 1], ypoints[i + 1]); - } - - } - - @Override - public void drawRoundRect(int x, int y, int width, int height, - int arcWidth, int arcHeight) { - if (mP == null) { - mP = new Paint(); - } - mC.drawRoundRect(new RectF(x, y, width, height), arcWidth, - arcHeight, mP); - } - - @Override - public void fillArc(int x, int y, int width, int height, int sa, int ea) { - if (mP == null) { - mP = new Paint(); - } - - Paint.Style tmp = mP.getStyle(); - mP.setStyle(Paint.Style.FILL_AND_STROKE); - mC.drawArc(new RectF(x, y, x + width, y + height), 360 - (sa + ea), - ea, true, mP); - - mP.setStyle(tmp); - } - - @Override - public void fillOval(int x, int y, int width, int height) { - if (mP == null) { - mP = new Paint(); - } - Paint.Style tmp = mP.getStyle(); - mP.setStyle(Paint.Style.FILL); - mC.drawOval(new RectF(x, y, x + width, y + height), mP); - mP.setStyle(tmp); - } - - @Override - public void fillPolygon(int[] xpoints, int[] ypoints, int npoints) { - if (mP == null) { - mP = new Paint(); - } - Paint.Style tmp = mP.getStyle(); - mC.save(); // (CLIP_SAVE_FLAG); - - mP.setStyle(Paint.Style.FILL); - - GeneralPath filledPolygon = new GeneralPath( - GeneralPath.WIND_EVEN_ODD, npoints); - filledPolygon.moveTo(xpoints[0], ypoints[0]); - for (int index = 1; index < xpoints.length; index++) { - filledPolygon.lineTo(xpoints[index], ypoints[index]); - } - filledPolygon.closePath(); - Path path = getPath(filledPolygon); - mC.clipPath(path); - mC.drawPath(path, mP); - - mP.setStyle(tmp); - mC.restore(); - } - - @Override - public void fillRect(int x, int y, int width, int height) { - if (mP == null) { - mP = new Paint(); - } - Paint.Style tmp = mP.getStyle(); - mP.setStyle(Paint.Style.FILL); - mC.drawRect(new Rect(x, y, x + width, y + height), mP); - mP.setStyle(tmp); - } - - @Override - public void drawRect(int x, int y, int width, int height) { - int[] xpoints = { x, x, x + width, x + width }; - int[] ypoints = { y, y + height, y + height, y }; - drawPolygon(xpoints, ypoints, 4); - } - - @Override - public void fillRoundRect(int x, int y, int width, int height, - int arcWidth, int arcHeight) { - if (mP == null) { - mP = new Paint(); - } - mP.setStyle(Paint.Style.FILL); - mC.drawRoundRect(new RectF(x, y, x + width, y + height), arcWidth, - arcHeight, mP); - } - - @Override - public Shape getClip() { - return mCurrClip; - } - - @Override - public Rectangle getClipBounds() { - Rect r = mC.getClipBounds(); - return new Rectangle(r.left, r.top, r.width(), r.height()); - } - - @Override - public Color getColor() { - if (mP != null) { - return new Color(mP.getColor()); - } - return null; - } - - @Override - public Font getFont() { - return mFnt; - } - - @Override - public FontMetrics getFontMetrics(Font font) { - mFm = new FontMetricsImpl(font); - return mFm; - } - - @Override - public void setClip(int x, int y, int width, int height) { - int cl[] = {-1, x, y, -2, x, y + width, -2, x + height, y + width, -2, x + height, y}; - mCurrClip = new Area(createShape(cl)); - mC.clipRect(x, y, x + width, y + height, Region.Op.REPLACE); - - } - - @Override - public void setClip(Shape clip) { - mCurrClip = new Area(clip); - mC.clipPath(getPath(clip), Region.Op.REPLACE); - } - - @Override - public void setColor(Color c) { - if (mP == null) { - mP = new Paint(); - } - if (c == null) { - c = Color.decode("#00000000"); - } - mP.setColor(c.getRGB()); - } - - /** - * Font mapping: - * - * Family: - * - * Android AWT - * ------------------------------------- - * serif Serif / TimesRoman - * sans-serif SansSerif / Helvetica - * monospace Monospaced / Courier - * - * Style: - * - * Android AWT - * ------------------------------------- - * normal Plain - * bold bold - * italic italic - * - */ - @Override - public void setFont(Font font) { - if (font == null) { - return; - } - if (mP == null) { - mP = new Paint(); - } - - mFnt = font; - Typeface tf = null; - int sty = font.getStyle(); - String nam = font.getName(); - String aF = ""; - if (nam != null) { - if (nam.equalsIgnoreCase("Serif") - || nam.equalsIgnoreCase("TimesRoman")) { - aF = "serif"; - } else if (nam.equalsIgnoreCase("SansSerif") - || nam.equalsIgnoreCase("Helvetica")) { - aF = "sans-serif"; - } else if (nam.equalsIgnoreCase("Monospaced") - || nam.equalsIgnoreCase("Courier")) { - aF = "monospace"; - } - } - - switch (sty) { - case Font.PLAIN: - tf = Typeface.create(aF, Typeface.NORMAL); - break; - case Font.BOLD: - tf = Typeface.create(aF, Typeface.BOLD); - break; - case Font.ITALIC: - tf = Typeface.create(aF, Typeface.ITALIC); - break; - case Font.BOLD | Font.ITALIC: - tf = Typeface.create(aF, Typeface.BOLD_ITALIC); - break; - default: - tf = Typeface.DEFAULT; - } - - mP.setTextSize(font.getSize()); - mP.setTypeface(tf); - } - - @Override - public void drawBytes(byte[] data, int offset, int length, int x, int y) { - drawString(new String(data, offset, length), x, y); - } - - @Override - public void drawPolygon(Polygon p) { - drawPolygon(p.xpoints, p.ypoints, p.npoints); - } - - @Override - public void fillPolygon(Polygon p) { - fillPolygon(p.xpoints, p.ypoints, p.npoints); - } - - @Override - public Rectangle getClipBounds(Rectangle r) { - Shape clip = getClip(); - if (clip != null) { - Rectangle b = clip.getBounds(); - r.x = b.x; - r.y = b.y; - r.width = b.width; - r.height = b.height; - } - return r; - } - - @Override - public boolean hitClip(int x, int y, int width, int height) { - return getClipBounds().intersects(new Rectangle(x, y, width, height)); - } - - @Override - public void drawChars(char[] data, int offset, int length, int x, int y) { - mC.drawText(data, offset, length, x, y, mP); - } - - @Override - public void setPaintMode() { - if (mP == null) { - mP = new Paint(); - } - mP.setXfermode(null); - } - - @Override - public void setXORMode(Color color) { - if (mP == null) { - mP = new Paint(); - } - mP.setXfermode(new PixelXorXfermode(color.getRGB())); - } - - @Override - public void fill3DRect(int x, int y, int width, int height, boolean raised) { - Color color = getColor(); - Color colorUp, colorDown; - if (raised) { - colorUp = color.brighter(); - colorDown = color.darker(); - setColor(color); - } else { - colorUp = color.darker(); - colorDown = color.brighter(); - setColor(colorUp); - } - - width--; - height--; - fillRect(x+1, y+1, width-1, height-1); - - setColor(colorUp); - fillRect(x, y, width, 1); - fillRect(x, y+1, 1, height); - - setColor(colorDown); - fillRect(x+width, y, 1, height); - fillRect(x+1, y+height, width, 1); - } - - @Override - public void draw3DRect(int x, int y, int width, int height, boolean raised) { - Color color = getColor(); - Color colorUp, colorDown; - if (raised) { - colorUp = color.brighter(); - colorDown = color.darker(); - } else { - colorUp = color.darker(); - colorDown = color.brighter(); - } - - setColor(colorUp); - fillRect(x, y, width, 1); - fillRect(x, y+1, 1, height); - - setColor(colorDown); - fillRect(x+width, y, 1, height); - fillRect(x+1, y+height, width, 1); - } - - public void copyArea(Canvas canvas, int sx, int sy, int width, int height, int dx, int dy) { - sx += getTransform().getTranslateX(); - sy += getTransform().getTranslateY(); - - // NativeUtils.nativeScrollRect(canvas, new Rect(sx, sy, sx + width, sy + height), dx, dy); - } -} diff --git a/app/src/main/java/com/android/internal/awt/AndroidGraphicsConfiguration.java b/app/src/main/java/com/android/internal/awt/AndroidGraphicsConfiguration.java deleted file mode 100644 index 0c888cd2d..000000000 --- a/app/src/main/java/com/android/internal/awt/AndroidGraphicsConfiguration.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright 2007, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.internal.awt; - -import com.android.internal.awt.AndroidGraphics2D; - -import java.awt.GraphicsConfiguration; -import java.awt.GraphicsDevice; -import java.awt.Rectangle; -import java.awt.geom.AffineTransform; -import java.awt.image.BufferedImage; -import java.awt.image.ColorModel; -import java.awt.image.VolatileImage; - -import android.graphics.Canvas; - -public class AndroidGraphicsConfiguration extends GraphicsConfiguration { - - @Override - public BufferedImage createCompatibleImage(int width, int height) { - // TODO Auto-generated method stub - return null; - } - - @Override - public BufferedImage createCompatibleImage(int width, int height, - int transparency) { - // TODO Auto-generated method stub - return null; - } - - @Override - public VolatileImage createCompatibleVolatileImage(int width, int height) { - // TODO Auto-generated method stub - return null; - } - - @Override - public VolatileImage createCompatibleVolatileImage(int width, int height, - int transparency) { - // TODO Auto-generated method stub - return null; - } - - @Override - public Rectangle getBounds() { - Canvas c = AndroidGraphics2D.getAndroidCanvas(); - if(c != null) - return new Rectangle(0, 0, c.getWidth(), c.getHeight()); - return null; - } - - @Override - public ColorModel getColorModel() { - // TODO Auto-generated method stub - return null; - } - - @Override - public ColorModel getColorModel(int transparency) { - // TODO Auto-generated method stub - return null; - } - - @Override - public AffineTransform getDefaultTransform() { - return new AffineTransform(); - } - - @Override - public GraphicsDevice getDevice() { - // TODO Auto-generated method stub - return null; - } - - @Override - public AffineTransform getNormalizingTransform() { - // TODO Auto-generated method stub - return null; - } - -} diff --git a/app/src/main/java/com/android/internal/awt/AndroidGraphicsFactory.java b/app/src/main/java/com/android/internal/awt/AndroidGraphicsFactory.java deleted file mode 100644 index ca255b559..000000000 --- a/app/src/main/java/com/android/internal/awt/AndroidGraphicsFactory.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright 2007, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.internal.awt; - -import java.awt.Font; -import java.awt.FontMetrics; -import java.awt.Graphics2D; -import java.awt.GraphicsEnvironment; -import java.awt.peer.FontPeer; - -import org.apache.harmony.awt.gl.MultiRectArea; -import org.apache.harmony.awt.gl.font.AndroidFont; -import org.apache.harmony.awt.gl.font.FontManager; -import org.apache.harmony.awt.gl.font.FontMetricsImpl; -import org.apache.harmony.awt.gl.font.AndroidFontManager; -import org.apache.harmony.awt.wtk.NativeWindow; -import org.apache.harmony.awt.wtk.WindowFactory; -import org.apache.harmony.awt.gl.CommonGraphics2DFactory; - -import android.graphics.Canvas; -import android.graphics.Paint; -import android.content.Context; - -public class AndroidGraphicsFactory extends CommonGraphics2DFactory { - - public GraphicsEnvironment createGraphicsEnvironment(WindowFactory wf) { - // TODO Auto-generated method stub - return null; - } - - public Font embedFont(String fontFilePath) { - // TODO Auto-generated method stub - return null; - } - - public FontManager getFontManager() { - return AndroidFontManager.inst; - } - - public FontMetrics getFontMetrics(Font font) { - return new FontMetricsImpl(font); - } - - public FontPeer getFontPeer(Font font) { - //return getFontManager().getFontPeer(font.getName(), font.getStyle(), font.getSize()); - return new AndroidFont(font.getName(), font.getStyle(), font.getSize()); - } - - public Graphics2D getGraphics2D(NativeWindow win, int translateX, - int translateY, MultiRectArea clip) { - // TODO Auto-generated method stub - return null; - } - - public Graphics2D getGraphics2D(NativeWindow win, int translateX, - int translateY, int width, int height) { - // TODO Auto-generated method stub - return null; - } - - public Graphics2D getGraphics2D(Context ctx, Canvas c, Paint p) { - return AndroidGraphics2D.getInstance(ctx, c, p); - } - - public Graphics2D getGraphics2D(Canvas c, Paint p) { - throw new RuntimeException("Not supported!"); - } - - public Graphics2D getGraphics2D() { - return AndroidGraphics2D.getInstance(); - } - -} diff --git a/app/src/main/java/com/android/internal/awt/AndroidImageDecoder.java b/app/src/main/java/com/android/internal/awt/AndroidImageDecoder.java deleted file mode 100644 index 81b2e1a8c..000000000 --- a/app/src/main/java/com/android/internal/awt/AndroidImageDecoder.java +++ /dev/null @@ -1,274 +0,0 @@ -/* - * Copyright 2007, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.internal.awt; - -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; - -import java.awt.Transparency; -import java.awt.color.ColorSpace; -//import java.awt.image.BufferedImage; -import java.awt.image.ColorModel; -import java.awt.image.ComponentColorModel; -import java.awt.image.DataBuffer; -import java.awt.image.DirectColorModel; -import java.awt.image.ImageConsumer; -import java.awt.image.IndexColorModel; -import java.io.IOException; -import java.io.InputStream; -import java.util.Hashtable; - -import org.apache.harmony.awt.gl.image.DecodingImageSource; -import org.apache.harmony.awt.gl.image.ImageDecoder; -import org.apache.harmony.awt.internal.nls.Messages; - -public class AndroidImageDecoder extends ImageDecoder { - - private static final int hintflags = - ImageConsumer.SINGLEFRAME | // PNG is a static image - ImageConsumer.TOPDOWNLEFTRIGHT | // This order is only one possible - ImageConsumer.COMPLETESCANLINES; // Don't deliver incomplete scanlines - - // Each pixel is a grayscale sample. - private static final int PNG_COLOR_TYPE_GRAY = 0; - // Each pixel is an R,G,B triple. - private static final int PNG_COLOR_TYPE_RGB = 2; - // Each pixel is a palette index, a PLTE chunk must appear. - private static final int PNG_COLOR_TYPE_PLTE = 3; - // Each pixel is a grayscale sample, followed by an alpha sample. - private static final int PNG_COLOR_TYPE_GRAY_ALPHA = 4; - // Each pixel is an R,G,B triple, followed by an alpha sample. - private static final int PNG_COLOR_TYPE_RGBA = 6; - - private static final int NB_OF_LINES_PER_CHUNK = 1; // 0 = full image - - Bitmap bm; // The image as decoded by Android - - // Header information - int imageWidth; // Image size - int imageHeight; - int colorType; // One of the PNG_ constants from above - int bitDepth; // Number of bits per color - byte cmap[]; // The color palette for index color models - ColorModel model; // The corresponding AWT color model - - boolean transferInts; // Is transfer of type int or byte? - int dataElementsPerPixel; - - // Buffers for decoded image data - byte byteOut[]; - int intOut[]; - - - public AndroidImageDecoder(DecodingImageSource src, InputStream is) { - super(src, is); - dataElementsPerPixel = 1; - } - - @Override - /** - * All the decoding is done in Android - * - * AWT???: Method returns only once the image is completly - * decoded; decoding is not done asynchronously - */ - public void decodeImage() throws IOException { - try { - bm = BitmapFactory.decodeStream(inputStream); - if (bm == null) { - throw new IOException("Input stream empty and no image cached"); - } - - // Check size - imageWidth = bm.getWidth(); - imageHeight = bm.getHeight(); - if (imageWidth < 0 || imageHeight < 0 ) { - throw new RuntimeException("Illegal image size: " - + imageWidth + ", " + imageHeight); - } - - // We got the image fully decoded; now send all image data to AWT - setDimensions(imageWidth, imageHeight); - model = createColorModel(); - setColorModel(model); - setHints(hintflags); - setProperties(new Hashtable()); // Empty - sendPixels(NB_OF_LINES_PER_CHUNK != 0 ? NB_OF_LINES_PER_CHUNK : imageHeight); - imageComplete(ImageConsumer.STATICIMAGEDONE); - } catch (IOException e) { - throw e; - } catch (RuntimeException e) { - imageComplete(ImageConsumer.IMAGEERROR); - throw e; - } finally { - closeStream(); - } - } - - /** - * Create the AWT color model - * - * ???AWT: Android Bitmaps are always of type: ARGB-8888-Direct color model - * - * However, we leave the code here for a more powerfull decoder - * that returns a native model, and the conversion is then handled - * in AWT. With such a decoder, we would need to get the colorType, - * the bitDepth, (and the color palette for an index color model) - * from the image and construct the correct color model here. - */ - private ColorModel createColorModel() { - ColorModel cm = null; - int bmModel = 5; // TODO This doesn't exist: bm.getColorModel(); - cmap = null; - - switch (bmModel) { - // A1_MODEL - case 1: - colorType = PNG_COLOR_TYPE_GRAY; - bitDepth = 1; - break; - - // A8_MODEL - case 2: - colorType = PNG_COLOR_TYPE_GRAY_ALPHA; - bitDepth = 8; - break; - - // INDEX8_MODEL - // RGB_565_MODEL - // ARGB_8888_MODEL - case 3: - case 4: - case 5: - colorType = bm.hasAlpha() ? PNG_COLOR_TYPE_RGBA : PNG_COLOR_TYPE_RGB; - bitDepth = 8; - break; - - default: - // awt.3C=Unknown PNG color type - throw new IllegalArgumentException(Messages.getString("awt.3C")); //$NON-NLS-1$ - } - - switch (colorType) { - - case PNG_COLOR_TYPE_GRAY: { - if (bitDepth != 8 && bitDepth != 4 && bitDepth != 2 && bitDepth != 1) { - // awt.3C=Unknown PNG color type - throw new IllegalArgumentException(Messages.getString("awt.3C")); //$NON-NLS-1$ - } - - // Create gray color model - int numEntries = 1 << bitDepth; - int scaleFactor = 255 / (numEntries-1); - byte comps[] = new byte[numEntries]; - for (int i = 0; i < numEntries; i++) { - comps[i] = (byte) (i * scaleFactor); - } - cm = new IndexColorModel(bitDepth, numEntries, comps, comps, comps); - - transferInts = false; - break; - } - - case PNG_COLOR_TYPE_RGB: { - if (bitDepth != 8) { - // awt.3C=Unknown PNG color type - throw new IllegalArgumentException(Messages.getString("awt.3C")); //$NON-NLS-1$ - } - - cm = new DirectColorModel(24, 0xff0000, 0xFF00, 0xFF); - - transferInts = true; - break; - } - - case PNG_COLOR_TYPE_PLTE: { - if (bitDepth != 8 && bitDepth != 4 && bitDepth != 2 && bitDepth != 1) { - // awt.3C=Unknown PNG color type - throw new IllegalArgumentException(Messages.getString("awt.3C")); //$NON-NLS-1$ - } - - if (cmap == null) { - throw new IllegalStateException("Palette color type is not supported"); - } - - cm = new IndexColorModel(bitDepth, cmap.length / 3, cmap, 0, false); - - transferInts = false; - break; - } - - case PNG_COLOR_TYPE_GRAY_ALPHA: { - if (bitDepth != 8) { - // awt.3C=Unknown PNG color type - throw new IllegalArgumentException(Messages.getString("awt.3C")); //$NON-NLS-1$ - } - - cm = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_GRAY), - true, false, - Transparency.TRANSLUCENT, - DataBuffer.TYPE_BYTE); - - transferInts = false; - dataElementsPerPixel = 2; - break; - } - - case PNG_COLOR_TYPE_RGBA: { - if (bitDepth != 8) { - // awt.3C=Unknown PNG color type - throw new IllegalArgumentException(Messages.getString("awt.3C")); //$NON-NLS-1$ - } - - cm = ColorModel.getRGBdefault(); - - transferInts = true; - break; - } - default: - // awt.3C=Unknown PNG color type - throw new IllegalArgumentException(Messages.getString("awt.3C")); //$NON-NLS-1$ - } - - return cm; - } - - private void sendPixels(int nbOfLinesPerChunk) { - int w = imageWidth; - int h = imageHeight; - int n = 1; - if (nbOfLinesPerChunk > 0 && nbOfLinesPerChunk <= h) { - n = nbOfLinesPerChunk; - } - - if (transferInts) { - // Create output buffer - intOut = new int[w * n]; - for (int yi = 0; yi < h; yi += n) { - // Last chunk might contain less liness - if (n > 1 && h - yi < n ) { - n = h - yi; - } - bm.getPixels(intOut, 0, w, 0, yi, w, n); - setPixels(0, yi, w, n, model, intOut, 0, w); - } - } else { - // Android bitmaps always store ints (ARGB-8888 direct model) - throw new RuntimeException("Byte transfer not supported"); - } - } - -} diff --git a/app/src/main/java/com/android/internal/awt/AndroidJavaBlitter.java b/app/src/main/java/com/android/internal/awt/AndroidJavaBlitter.java deleted file mode 100644 index 423b534cb..000000000 --- a/app/src/main/java/com/android/internal/awt/AndroidJavaBlitter.java +++ /dev/null @@ -1,536 +0,0 @@ -/* - * Copyright 2007, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.internal.awt; - -import android.graphics.Bitmap; -import android.graphics.Canvas; -import android.graphics.Matrix; -import android.graphics.Paint; -import org.apache.harmony.awt.gl.MultiRectArea; -import org.apache.harmony.awt.gl.Surface; -import org.apache.harmony.awt.gl.XORComposite; -import org.apache.harmony.awt.gl.render.Blitter; - -import java.awt.*; -import java.awt.geom.AffineTransform; -import java.awt.geom.Rectangle2D; -import java.awt.image.ColorModel; -import java.awt.image.DataBuffer; -import java.awt.image.DataBufferInt; -import java.awt.image.Raster; -import java.awt.image.WritableRaster; - -public class AndroidJavaBlitter implements Blitter { - - private Canvas canvas; - private Paint paint; - private int colorCache; - - public AndroidJavaBlitter(Canvas c) { - this.canvas = c; - this.paint = new Paint(); - this.paint.setStrokeWidth(1); - } - - /** - * Instead of multiplication and division we are using values from - * Lookup tables. - */ - static byte mulLUT[][]; // Lookup table for multiplication - static byte divLUT[][]; // Lookup table for division - - static{ - mulLUT = new byte[256][256]; - for(int i = 0; i < 256; i++){ - for(int j = 0; j < 256; j++){ - mulLUT[i][j] = (byte)((float)(i * j)/255 + 0.5f); - } - } - divLUT = new byte[256][256]; - for(int i = 1; i < 256; i++){ - for(int j = 0; j < i; j++){ - divLUT[i][j] = (byte)(((float)j / 255) / ((float)i/ 255) * 255 + 0.5f); - } - for(int j = i; j < 256; j++){ - divLUT[i][j] = (byte)255; - } - } - } - - final static int AlphaCompositeMode = 1; - final static int XORMode = 2; - - public void blit(int srcX, int srcY, Surface srcSurf, int dstX, int dstY, - Surface dstSurf, int width, int height, AffineTransform sysxform, - AffineTransform xform, Composite comp, Color bgcolor, - MultiRectArea clip) { - - if(xform == null){ - blit(srcX, srcY, srcSurf, dstX, dstY, dstSurf, width, height, - sysxform, comp, bgcolor, clip); - }else{ - double scaleX = xform.getScaleX(); - double scaleY = xform.getScaleY(); - double scaledX = dstX / scaleX; - double scaledY = dstY / scaleY; - AffineTransform at = new AffineTransform(); - at.setToTranslation(scaledX, scaledY); - xform.concatenate(at); - sysxform.concatenate(xform); - blit(srcX, srcY, srcSurf, 0, 0, dstSurf, width, height, - sysxform, comp, bgcolor, clip); - } - - } - - public void blit(int srcX, int srcY, Surface srcSurf, int dstX, int dstY, - Surface dstSurf, int width, int height, AffineTransform sysxform, - Composite comp, Color bgcolor, MultiRectArea clip) { - - if(sysxform == null) { - sysxform = new AffineTransform(); - } - int type = sysxform.getType(); - switch(type){ - case AffineTransform.TYPE_TRANSLATION: - dstX += sysxform.getTranslateX(); - dstY += sysxform.getTranslateY(); - case AffineTransform.TYPE_IDENTITY: - simpleBlit(srcX, srcY, srcSurf, dstX, dstY, dstSurf, - width, height, comp, bgcolor, clip); - break; - default: - int srcW = srcSurf.getWidth(); - int srcH = srcSurf.getHeight(); - - int w = srcX + width < srcW ? width : srcW - srcX; - int h = srcY + height < srcH ? height : srcH - srcY; - - ColorModel srcCM = srcSurf.getColorModel(); - Raster srcR = srcSurf.getRaster().createChild(srcX, srcY, - w, h, 0, 0, null); - - ColorModel dstCM = dstSurf.getColorModel(); - WritableRaster dstR = dstSurf.getRaster(); - - transformedBlit(srcCM, srcR, 0, 0, dstCM, dstR, dstX, dstY, w, h, - sysxform, comp, bgcolor, clip); - - } - } - - public void simpleBlit(int srcX, int srcY, Surface srcSurf, int dstX, int dstY, - Surface dstSurf, int width, int height, Composite comp, - Color bgcolor, MultiRectArea clip) { - - // TODO It's possible, though unlikely that we might encounter non-int[] - // data buffers. In this case the following code needs to have several - // branches that take this into account. - data = (DataBufferInt)srcSurf.getRaster().getDataBuffer(); - int[] pixels = data.getData(); - if (!srcSurf.getColorModel().hasAlpha()) { - // This wouldn't be necessary if Android supported RGB_888. - for (int i = 0; i < pixels.length; i++) { - pixels[i] = pixels[i] | 0xff000000; - } - } - bmap = Bitmap.createBitmap(pixels, width, height, Bitmap.Config.ARGB_8888); - canvas.drawBitmap(bmap, dstX, dstY, paint); - } - - public void blit(int srcX, int srcY, Surface srcSurf, int dstX, int dstY, - Surface dstSurf, int width, int height, Composite comp, - Color bgcolor, MultiRectArea clip) { - - javaBlt(srcX, srcY, srcSurf.getWidth(), srcSurf.getHeight(), - srcSurf.getColorModel(), srcSurf.getRaster(), dstX, dstY, - dstSurf.getWidth(), dstSurf.getHeight(), - dstSurf.getColorModel(), dstSurf.getRaster(), - width, height, comp, bgcolor, clip); - - } - - public void javaBlt(int srcX, int srcY, int srcW, int srcH, - ColorModel srcCM, Raster srcRast, int dstX, int dstY, - int dstW, int dstH, ColorModel dstCM, WritableRaster dstRast, - int width, int height, Composite comp, Color bgcolor, - MultiRectArea clip){ - - int srcX2 = srcW - 1; - int srcY2 = srcH - 1; - int dstX2 = dstW - 1; - int dstY2 = dstH - 1; - - if(srcX < 0){ - width += srcX; - srcX = 0; - } - if(srcY < 0){ - height += srcY; - srcY = 0; - } - - if(dstX < 0){ - width += dstX; - srcX -= dstX; - dstX = 0; - } - if(dstY < 0){ - height += dstY; - srcY -= dstY; - dstY = 0; - } - - if(srcX > srcX2 || srcY > srcY2) { - return; - } - if(dstX > dstX2 || dstY > dstY2) { - return; - } - - if(srcX + width > srcX2) { - width = srcX2 - srcX + 1; - } - if(srcY + height > srcY2) { - height = srcY2 - srcY + 1; - } - if(dstX + width > dstX2) { - width = dstX2 - dstX + 1; - } - if(dstY + height > dstY2) { - height = dstY2 - dstY + 1; - } - - if(width <= 0 || height <= 0) { - return; - } - - int clipRects[]; - if(clip != null) { - clipRects = clip.rect; - } else { - clipRects = new int[]{5, 0, 0, dstW - 1, dstH - 1}; - } - - boolean isAlphaComp = false; - int rule = 0; - float alpha = 0; - boolean isXORComp = false; - Color xorcolor = null; - CompositeContext cont = null; - - if(comp instanceof AlphaComposite){ - isAlphaComp = true; - AlphaComposite ac = (AlphaComposite) comp; - rule = ac.getRule(); - alpha = ac.getAlpha(); - }else if(comp instanceof XORComposite){ - isXORComp = true; - XORComposite xcomp = (XORComposite) comp; - xorcolor = xcomp.getXORColor(); - }else{ - cont = comp.createContext(srcCM, dstCM, null); - } - - for(int i = 1; i < clipRects[0]; i += 4){ - int _sx = srcX; - int _sy = srcY; - - int _dx = dstX; - int _dy = dstY; - - int _w = width; - int _h = height; - - int cx = clipRects[i]; // Clipping left top X - int cy = clipRects[i + 1]; // Clipping left top Y - int cx2 = clipRects[i + 2]; // Clipping right bottom X - int cy2 = clipRects[i + 3]; // Clipping right bottom Y - - if(_dx > cx2 || _dy > cy2 || dstX2 < cx || dstY2 < cy) { - continue; - } - - if(cx > _dx){ - int shx = cx - _dx; - _w -= shx; - _dx = cx; - _sx += shx; - } - - if(cy > _dy){ - int shy = cy - _dy; - _h -= shy; - _dy = cy; - _sy += shy; - } - - if(_dx + _w > cx2 + 1){ - _w = cx2 - _dx + 1; - } - - if(_dy + _h > cy2 + 1){ - _h = cy2 - _dy + 1; - } - - if(_sx > srcX2 || _sy > srcY2) { - continue; - } - - if(isAlphaComp){ - alphaCompose(_sx, _sy, srcCM, srcRast, _dx, _dy, - dstCM, dstRast, _w, _h, rule, alpha, bgcolor); - }else if(isXORComp){ - xorCompose(_sx, _sy, srcCM, srcRast, _dx, _dy, - dstCM, dstRast, _w, _h, xorcolor); - }else{ - Raster sr = srcRast.createChild(_sx, _sy, _w, _h, 0, 0, null); - WritableRaster dr = dstRast.createWritableChild(_dx, _dy, - _w, _h, 0, 0, null); - cont.compose(sr, dr, dr); - } - } - - } - - DataBufferInt data; - Bitmap bmap, bmp; - - void alphaCompose(int srcX, int srcY, ColorModel srcCM, Raster srcRast, - int dstX, int dstY, ColorModel dstCM, WritableRaster dstRast, - int width, int height, int rule, float alpha, Color bgcolor){ - - Object srcPixel = getTransferArray(srcRast, 1); - data = (DataBufferInt)srcRast.getDataBuffer(); - int pix[] = data.getData(); - bmap = Bitmap.createBitmap(pix, width, height, Bitmap.Config.RGB_565); - canvas.drawBitmap(bmap, dstX, dstY, paint); - } - - void render(int[] img, int x, int y, int width, int height) { - canvas.drawBitmap(Bitmap.createBitmap(img, width, height, Bitmap.Config.ARGB_8888), x, y, paint); - } - - void xorCompose(int srcX, int srcY, ColorModel srcCM, Raster srcRast, - int dstX, int dstY, ColorModel dstCM, WritableRaster dstRast, - int width, int height, Color xorcolor){ - - data = (DataBufferInt)srcRast.getDataBuffer(); - int pix[] = data.getData(); - bmap = Bitmap.createBitmap(pix, width, height, Bitmap.Config.RGB_565); - canvas.drawBitmap(bmap, dstX, dstY, paint); - } - - private void transformedBlit(ColorModel srcCM, Raster srcR, int srcX, int srcY, - ColorModel dstCM, WritableRaster dstR, int dstX, int dstY, - int width, int height, AffineTransform at, Composite comp, - Color bgcolor, MultiRectArea clip) { - - data = (DataBufferInt)srcR.getDataBuffer(); - int[] pixels = data.getData(); - if (!srcCM.hasAlpha()) { - // This wouldn't be necessary if Android supported RGB_888. - for (int i = 0; i < pixels.length; i++) { - pixels[i] = pixels[i] | 0xff000000; - } - } - bmap = Bitmap.createBitmap(pixels, width, height, Bitmap.Config.ARGB_8888); - - Matrix tm = new Matrix(); - tm.setConcat(canvas.getMatrix(), AndroidGraphics2D.createMatrixObj(at)); - if(at.getType() > 1) { - bmp = Bitmap.createBitmap(bmap, 0, 0, width, height, tm, true); - } else { - bmp = Bitmap.createBitmap(bmap, 0, 0, width, height, tm, false); - } - canvas.drawBitmap(bmp, dstX + (float)at.getTranslateX(), dstY + (float)at.getTranslateY(), paint); - } - - private Rectangle2D getBounds2D(AffineTransform at, Rectangle r) { - int x = r.x; - int y = r.y; - int width = r.width; - int height = r.height; - - float[] corners = { - x, y, - x + width, y, - x + width, y + height, - x, y + height - }; - - at.transform(corners, 0, corners, 0, 4); - - Rectangle2D.Float bounds = new Rectangle2D.Float(corners[0], corners[1], 0 , 0); - bounds.add(corners[2], corners[3]); - bounds.add(corners[4], corners[5]); - bounds.add(corners[6], corners[7]); - - return bounds; - } - - private int compose(int srcRGB, boolean isSrcAlphaPre, - int dstRGB, boolean dstHasAlpha, boolean isDstAlphaPre, - int rule, int srcConstAlpha){ - - int sa, sr, sg, sb, da, dr, dg, db; - - sa = (srcRGB >> 24) & 0xff; - sr = (srcRGB >> 16) & 0xff; - sg = (srcRGB >> 8) & 0xff; - sb = srcRGB & 0xff; - - if(isSrcAlphaPre){ - sa = mulLUT[srcConstAlpha][sa] & 0xff; - sr = mulLUT[srcConstAlpha][sr] & 0xff; - sg = mulLUT[srcConstAlpha][sg] & 0xff; - sb = mulLUT[srcConstAlpha][sb] & 0xff; - }else{ - sa = mulLUT[srcConstAlpha][sa] & 0xff; - sr = mulLUT[sa][sr] & 0xff; - sg = mulLUT[sa][sg] & 0xff; - sb = mulLUT[sa][sb] & 0xff; - } - - da = (dstRGB >> 24) & 0xff; - dr = (dstRGB >> 16) & 0xff; - dg = (dstRGB >> 8) & 0xff; - db = dstRGB & 0xff; - - if(!isDstAlphaPre){ - dr = mulLUT[da][dr] & 0xff; - dg = mulLUT[da][dg] & 0xff; - db = mulLUT[da][db] & 0xff; - } - - int Fs = 0; - int Fd = 0; - switch(rule){ - case AlphaComposite.CLEAR: - break; - - case AlphaComposite.DST: - Fd = 255; - break; - - case AlphaComposite.DST_ATOP: - Fs = 255 - da; - Fd = sa; - break; - - case AlphaComposite.DST_IN: - Fd = sa; - break; - - case AlphaComposite.DST_OUT: - Fd = 255 - sa; - break; - - case AlphaComposite.DST_OVER: - Fs = 255 - da; - Fd = 255; - break; - - case AlphaComposite.SRC: - Fs = 255; - break; - - case AlphaComposite.SRC_ATOP: - Fs = da; - Fd = 255 - sa; - break; - - case AlphaComposite.SRC_IN: - Fs = da; - break; - - case AlphaComposite.SRC_OUT: - Fs = 255 - da; - break; - - case AlphaComposite.SRC_OVER: - Fs = 255; - Fd = 255 - sa; - break; - - case AlphaComposite.XOR: - Fs = 255 - da; - Fd = 255 - sa; - break; - } - dr = (mulLUT[sr][Fs] & 0xff) + (mulLUT[dr][Fd] & 0xff); - dg = (mulLUT[sg][Fs] & 0xff) + (mulLUT[dg][Fd] & 0xff); - db = (mulLUT[sb][Fs] & 0xff) + (mulLUT[db][Fd] & 0xff); - - da = (mulLUT[sa][Fs] & 0xff) + (mulLUT[da][Fd] & 0xff); - - if(!isDstAlphaPre){ - if(da != 255){ - dr = divLUT[da][dr] & 0xff; - dg = divLUT[da][dg] & 0xff; - db = divLUT[da][db] & 0xff; - } - } - if(!dstHasAlpha) { - da = 0xff; - } - dstRGB = (da << 24) | (dr << 16) | (dg << 8) | db; - - return dstRGB; - - } - - /** - * Allocate an array that can be use to store the result for a - * Raster.getDataElements call. - * @param raster Raster (type) where the getDataElements call will be made. - * @param nbPixels How many pixels to store in the array at most - * @return the result array or null - */ - private Object getTransferArray(Raster raster, int nbPixels) { - int transferType = raster.getTransferType(); - int nbDataElements = raster.getSampleModel().getNumDataElements(); - int n = nbDataElements * nbPixels; - switch (transferType) { - case DataBuffer.TYPE_BYTE: - return new byte[n]; - case DataBuffer.TYPE_SHORT: - case DataBuffer.TYPE_USHORT: - return new short[n]; - case DataBuffer.TYPE_INT: - return new int[n]; - case DataBuffer.TYPE_FLOAT: - return new float[n]; - case DataBuffer.TYPE_DOUBLE: - return new double[n]; - case DataBuffer.TYPE_UNDEFINED: - default: - return null; - } - } - - /** - * Draw a pixel - */ - private void dot(int x, int y, int clr) { - if (colorCache != clr) { - paint.setColor(clr); - colorCache = clr; - } - canvas.drawLine(x, y, x + 1, y + 1, paint); - } -} diff --git a/app/src/main/java/com/android/internal/awt/AndroidNativeEventQueue.java b/app/src/main/java/com/android/internal/awt/AndroidNativeEventQueue.java deleted file mode 100644 index fc3061457..000000000 --- a/app/src/main/java/com/android/internal/awt/AndroidNativeEventQueue.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright 2007, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.internal.awt; - -import org.apache.harmony.awt.wtk.NativeEventQueue; - -public class AndroidNativeEventQueue extends NativeEventQueue { - - private Object eventMonitor; - - public AndroidNativeEventQueue() { - super(); - eventMonitor = getEventMonitor(); - } - - @Override - public void awake() { - synchronized (eventMonitor) { - eventMonitor.notify(); - } - } - - @Override - public void dispatchEvent() { - //???AWT - System.out.println(getClass()+": empty method called"); - } - - @Override - public long getJavaWindow() { - //???AWT - System.out.println(getClass()+": empty method called"); - return 0; - } - - @Override - public void performLater(Task task) { - //???AWT - System.out.println(getClass()+": empty method called"); - } - - @Override - public void performTask(Task task) { - //???AWT - System.out.println(getClass()+": empty method called"); - } - - @Override - public boolean waitEvent() { - while (isEmpty() ) { - synchronized (eventMonitor) { - try { - eventMonitor.wait(1000); - } catch (InterruptedException ignore) { - } - } - } - return false; - } - -} diff --git a/app/src/main/java/com/android/internal/awt/AndroidWTK.java b/app/src/main/java/com/android/internal/awt/AndroidWTK.java deleted file mode 100644 index 1609d119e..000000000 --- a/app/src/main/java/com/android/internal/awt/AndroidWTK.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright 2007, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.internal.awt; - -import java.awt.GraphicsDevice; - -import org.apache.harmony.awt.wtk.CursorFactory; -import org.apache.harmony.awt.wtk.GraphicsFactory; -import org.apache.harmony.awt.wtk.NativeEventQueue; -import org.apache.harmony.awt.wtk.NativeIM; -import org.apache.harmony.awt.wtk.NativeMouseInfo; -import org.apache.harmony.awt.wtk.NativeRobot; -import org.apache.harmony.awt.wtk.SystemProperties; -import org.apache.harmony.awt.wtk.WTK; -import org.apache.harmony.awt.wtk.WindowFactory; - -public class AndroidWTK extends WTK { - - private AndroidGraphicsFactory mAgf; - private AndroidNativeEventQueue mAneq; - - @Override - public CursorFactory getCursorFactory() { - // TODO Auto-generated method stub - return null; - } - - @Override - public GraphicsFactory getGraphicsFactory() { - if(mAgf == null) { - mAgf = new AndroidGraphicsFactory(); - } - return mAgf; - } - - @Override - public NativeEventQueue getNativeEventQueue() { - if(mAneq == null) { - mAneq = new AndroidNativeEventQueue(); - } - return mAneq; - } - - @Override - public NativeIM getNativeIM() { - // TODO Auto-generated method stub - return null; - } - - @Override - public NativeMouseInfo getNativeMouseInfo() { - // TODO Auto-generated method stub - return null; - } - - @Override - public NativeRobot getNativeRobot(GraphicsDevice screen) { - // TODO Auto-generated method stub - return null; - } - - @Override - public SystemProperties getSystemProperties() { - // TODO Auto-generated method stub - return null; - } - - @Override - public WindowFactory getWindowFactory() { - // TODO Auto-generated method stub - return null; - } - -} diff --git a/app/src/main/java/com/android/internal/awt/AwtFactory.java b/app/src/main/java/com/android/internal/awt/AwtFactory.java deleted file mode 100644 index 6e667b234..000000000 --- a/app/src/main/java/com/android/internal/awt/AwtFactory.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright 2007, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.internal.awt; - -import java.awt.Graphics2D; -import java.awt.Toolkit; - -import org.apache.harmony.awt.wtk.GraphicsFactory; - -import android.graphics.Canvas; -import android.graphics.Paint; - -public class AwtFactory { - - private static GraphicsFactory gf; - - /** - * Use this method to get acces to AWT drawing primitives and to - * render into the surface area of a Android widget. Origin and - * clip of the returned graphics object are the same as in the - * corresponding Android widget. - * - * @param c Canvas of the android widget to draw into - * @param p The default drawing parameters such as font, - * stroke, foreground and background colors, etc. - * @return The AWT Graphics object that makes all AWT - * drawing primitives available in the androind world. - */ - public static Graphics2D getAwtGraphics(Canvas c, Paint p) { - // AWT?? TODO: test it! - if (null == gf) { - Toolkit tk = Toolkit.getDefaultToolkit(); - gf = tk.getGraphicsFactory(); - } - return gf.getGraphics2D(c, p); - } - -} diff --git a/app/src/main/java/com/android/internal/awt/ImageOutputStreamWrapper.java b/app/src/main/java/com/android/internal/awt/ImageOutputStreamWrapper.java deleted file mode 100644 index 92185fde3..000000000 --- a/app/src/main/java/com/android/internal/awt/ImageOutputStreamWrapper.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright 2007, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.internal.awt; - -import java.io.IOException; -import java.io.OutputStream; - -import javax.imageio.stream.ImageOutputStream; - -public class ImageOutputStreamWrapper extends OutputStream { - - protected ImageOutputStream mIos; - - private byte[] mBuff; - - public ImageOutputStreamWrapper(ImageOutputStream ios) { - if (null == ios) { - throw new IllegalArgumentException("ImageOutputStream must not be null"); - } - this.mIos = ios; - this.mBuff = new byte[1]; - } - - public ImageOutputStream getImageOutputStream() { - return mIos; - } - - @Override - public void write(int oneByte) throws IOException { - mBuff[0] = (byte)oneByte; - mIos.write(mBuff, 0, 1); - } - - public void write(byte[] b) throws IOException { - mIos.write(b, 0, b.length); - } - - public void write(byte[] b, int off, int len) throws IOException { - mIos.write(b, off, len); - } - - public void flush() throws IOException { - mIos.flush(); - } - - public void close() throws IOException { - if (mIos == null) { - throw new IOException("Stream already closed"); - } - mIos = null; - } -} diff --git a/app/src/main/java/com/android/internal/awt/NullGraphics2D.java b/app/src/main/java/com/android/internal/awt/NullGraphics2D.java deleted file mode 100644 index b181c1eec..000000000 --- a/app/src/main/java/com/android/internal/awt/NullGraphics2D.java +++ /dev/null @@ -1,456 +0,0 @@ -package com.android.internal.awt; - -import java.awt.*; -import java.text.*; -import java.awt.image.renderable.*; -import java.awt.font.*; -import java.awt.image.*; -import java.awt.RenderingHints.*; -import java.util.*; -import java.awt.geom.*; - -public class NullGraphics2D extends Graphics2D -{ - - @Override - public void clearRect(int x, int y, int width, int height) - { - // TODO: Implement this method - } - - @Override - public void clipRect(int x, int y, int width, int height) - { - // TODO: Implement this method - } - - @Override - public void copyArea(int sx, int sy, int width, int height, int dx, int dy) - { - // TODO: Implement this method - } - - @Override - public Graphics create() - { - return this; - } - - @Override - public void dispose() - { - // TODO: Implement this method - } - - @Override - public void drawArc(int x, int y, int width, int height, int sa, int ea) - { - // TODO: Implement this method - } - - @Override - public boolean drawImage(Image img, int x, int y, Color bgcolor, ImageObserver observer) - { - // TODO: Implement this method - return false; - } - - @Override - public boolean drawImage(Image img, int x, int y, ImageObserver observer) - { - // TODO: Implement this method - return false; - } - - @Override - public boolean drawImage(Image img, int x, int y, int width, int height, Color bgcolor, ImageObserver observer) - { - // TODO: Implement this method - return false; - } - - @Override - public boolean drawImage(Image img, int x, int y, int width, int height, ImageObserver observer) - { - // TODO: Implement this method - return false; - } - - @Override - public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2, Color bgcolor, ImageObserver observer) - { - // TODO: Implement this method - return false; - } - - @Override - public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2, ImageObserver observer) - { - // TODO: Implement this method - return false; - } - - @Override - public void drawLine(int x1, int y1, int x2, int y2) - { - // TODO: Implement this method - } - - @Override - public void drawOval(int x, int y, int width, int height) - { - // TODO: Implement this method - } - - @Override - public void drawPolygon(int[] xpoints, int[] ypoints, int npoints) - { - // TODO: Implement this method - } - - @Override - public void drawPolyline(int[] xpoints, int[] ypoints, int npoints) - { - // TODO: Implement this method - } - - @Override - public void drawRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight) - { - // TODO: Implement this method - } - - @Override - public void fillArc(int x, int y, int width, int height, int sa, int ea) - { - // TODO: Implement this method - } - - @Override - public void fillOval(int x, int y, int width, int height) - { - // TODO: Implement this method - } - - @Override - public void fillPolygon(int[] xpoints, int[] ypoints, int npoints) - { - // TODO: Implement this method - } - - @Override - public void fillRect(int x, int y, int width, int height) - { - // TODO: Implement this method - } - - @Override - public void fillRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight) - { - // TODO: Implement this method - } - - @Override - public Shape getClip() - { - // TODO: Implement this method - return null; - } - - @Override - public Rectangle getClipBounds() - { - // TODO: Implement this method - return null; - } - - @Override - public Color getColor() - { - return Color.BLACK; - } - - @Override - public Font getFont() - { - // TODO: Implement this method - return Font.decode(null); - } - - @Override - public FontMetrics getFontMetrics(Font font) - { - // TODO: Implement this method - return new FontMetrics(getFont()){}; - } - - @Override - public void setClip(int x, int y, int width, int height) - { - // TODO: Implement this method - } - - @Override - public void setClip(Shape clip) - { - // TODO: Implement this method - } - - @Override - public void setColor(Color c) - { - // TODO: Implement this method - } - - @Override - public void setFont(Font font) - { - // TODO: Implement this method - } - - @Override - public void setPaintMode() - { - // TODO: Implement this method - } - - @Override - public void setXORMode(Color color) - { - // TODO: Implement this method - } - - @Override - public void addRenderingHints(Map hints) - { - // TODO: Implement this method - } - - @Override - public void clip(Shape s) - { - // TODO: Implement this method - } - - @Override - public void draw(Shape s) - { - // TODO: Implement this method - } - - @Override - public void drawGlyphVector(GlyphVector g, float x, float y) - { - // TODO: Implement this method - } - - @Override - public void drawImage(BufferedImage img, BufferedImageOp op, int x, int y) - { - // TODO: Implement this method - } - - @Override - public boolean drawImage(Image img, AffineTransform xform, ImageObserver obs) - { - // TODO: Implement this method - return false; - } - - @Override - public void drawRenderableImage(RenderableImage img, AffineTransform xform) - { - // TODO: Implement this method - } - - @Override - public void drawRenderedImage(RenderedImage img, AffineTransform xform) - { - // TODO: Implement this method - } - - @Override - public void drawString(AttributedCharacterIterator iterator, float x, float y) - { - // TODO: Implement this method - } - - @Override - public void drawString(AttributedCharacterIterator iterator, int x, int y) - { - // TODO: Implement this method - } - - @Override - public void drawString(String s, float x, float y) - { - // TODO: Implement this method - } - - @Override - public void drawString(String str, int x, int y) - { - // TODO: Implement this method - } - - @Override - public void fill(Shape s) - { - // TODO: Implement this method - } - - @Override - public Color getBackground() - { - // TODO: Implement this method - return null; - } - - @Override - public Composite getComposite() - { - // TODO: Implement this method - return null; - } - - @Override - public GraphicsConfiguration getDeviceConfiguration() - { - // TODO: Implement this method - return null; - } - - @Override - public FontRenderContext getFontRenderContext() - { - // TODO: Implement this method - return null; - } - - @Override - public Paint getPaint() - { - // TODO: Implement this method - return null; - } - - @Override - public Object getRenderingHint(RenderingHints.Key key) - { - // TODO: Implement this method - return null; - } - - @Override - public RenderingHints getRenderingHints() - { - // TODO: Implement this method - return null; - } - - @Override - public Stroke getStroke() - { - // TODO: Implement this method - return null; - } - - @Override - public AffineTransform getTransform() - { - // TODO: Implement this method - return null; - } - - @Override - public boolean hit(Rectangle rect, Shape s, boolean onStroke) - { - // TODO: Implement this method - return false; - } - - @Override - public void rotate(double theta) - { - // TODO: Implement this method - } - - @Override - public void rotate(double theta, double x, double y) - { - // TODO: Implement this method - } - - @Override - public void scale(double sx, double sy) - { - // TODO: Implement this method - } - - @Override - public void setBackground(Color color) - { - // TODO: Implement this method - } - - @Override - public void setComposite(Composite comp) - { - // TODO: Implement this method - } - - @Override - public void setPaint(Paint paint) - { - // TODO: Implement this method - } - - @Override - public void setRenderingHint(RenderingHints.Key key, Object value) - { - // TODO: Implement this method - } - - @Override - public void setRenderingHints(Map hints) - { - // TODO: Implement this method - } - - @Override - public void setStroke(Stroke s) - { - // TODO: Implement this method - } - - @Override - public void setTransform(AffineTransform Tx) - { - // TODO: Implement this method - } - - @Override - public void shear(double shx, double shy) - { - // TODO: Implement this method - } - - @Override - public void transform(AffineTransform Tx) - { - // TODO: Implement this method - } - - @Override - public void translate(double tx, double ty) - { - // TODO: Implement this method - } - - @Override - public void translate(int x, int y) - { - // TODO: Implement this method - } - -} diff --git a/app/src/main/java/com/kdt/handleview/ActionPopupWindow.java b/app/src/main/java/com/kdt/handleview/ActionPopupWindow.java index 27ecdb9c2..df3cec116 100644 --- a/app/src/main/java/com/kdt/handleview/ActionPopupWindow.java +++ b/app/src/main/java/com/kdt/handleview/ActionPopupWindow.java @@ -171,10 +171,14 @@ public class ActionPopupWindow extends PinnedPopupWindow implements OnClickListe } else { properties.lwjglKeycode = AndroidLWJGLKeycode.getKeyIndex(spinnerKeycode.getSelectedItemPosition()) - 2; properties.name = editName.getText().toString(); + if (properties.lwjglKeycode < 0) { + properties.name = ControlButton.getSpecialButtons()[properties.lwjglKeycode + 2].name; + } properties.hidden = checkHidden.isChecked(); mHandleView.mView.updateProperties(); - + mHandleView.mView.setModified(true); + dialog.dismiss(); } } @@ -192,6 +196,8 @@ public class ActionPopupWindow extends PinnedPopupWindow implements OnClickListe { ControlsLayout layout = ((ControlsLayout) mHandleView.mView.getParent()); layout.removeControlButton(mHandleView.mView); + + mHandleView.mView.setModified(true); } }); alert.setNegativeButton(android.R.string.cancel, null); diff --git a/app/src/main/java/com/pojavdx/dex/Annotation.java b/app/src/main/java/com/pojavdx/dex/Annotation.java deleted file mode 100644 index bcfe4619a..000000000 --- a/app/src/main/java/com/pojavdx/dex/Annotation.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.pojavdx.dex; - -import static com.pojavdx.dex.EncodedValueReader.ENCODED_ANNOTATION; - -/** - * An annotation. - */ -public final class Annotation implements Comparable { - private final Dex dex; - private final byte visibility; - private final EncodedValue encodedAnnotation; - - public Annotation(Dex dex, byte visibility, EncodedValue encodedAnnotation) { - this.dex = dex; - this.visibility = visibility; - this.encodedAnnotation = encodedAnnotation; - } - - public byte getVisibility() { - return visibility; - } - - public EncodedValueReader getReader() { - return new EncodedValueReader(encodedAnnotation, ENCODED_ANNOTATION); - } - - public int getTypeIndex() { - EncodedValueReader reader = getReader(); - reader.readAnnotation(); - return reader.getAnnotationType(); - } - - public void writeTo(Dex.Section out) { - out.writeByte(visibility); - encodedAnnotation.writeTo(out); - } - - @Override - public int compareTo(Annotation other) { - return encodedAnnotation.compareTo(other.encodedAnnotation); - } - - @Override - public String toString() { - return dex == null - ? visibility + " " + getTypeIndex() - : visibility + " " + dex.typeNames().get(getTypeIndex()); - } -} diff --git a/app/src/main/java/com/pojavdx/dex/CallSiteId.java b/app/src/main/java/com/pojavdx/dex/CallSiteId.java deleted file mode 100644 index d884c821b..000000000 --- a/app/src/main/java/com/pojavdx/dex/CallSiteId.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.pojavdx.dex; - -import com.pojavdx.dex.Dex.Section; -import com.pojavdx.dex.util.Unsigned; - -/** - * A call_site_id_item: https://source.android.com/devices/tech/dalvik/dex-format#call-site-id-item - */ -public class CallSiteId implements Comparable { - - private final Dex dex; - private final int offset; - - public CallSiteId(Dex dex, int offset) { - this.dex = dex; - this.offset = offset; - } - - @Override - public int compareTo(CallSiteId o) { - return Unsigned.compare(offset, o.offset); - } - - public int getCallSiteOffset() { - return offset; - } - - public void writeTo(Section out) { - out.writeInt(offset); - } - - @Override - public String toString() { - if (dex == null) { - return String.valueOf(offset); - } - return dex.protoIds().get(offset).toString(); - } -} diff --git a/app/src/main/java/com/pojavdx/dex/ClassData.java b/app/src/main/java/com/pojavdx/dex/ClassData.java deleted file mode 100644 index 0938fb9bb..000000000 --- a/app/src/main/java/com/pojavdx/dex/ClassData.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.pojavdx.dex; - -public final class ClassData { - private final Field[] staticFields; - private final Field[] instanceFields; - private final Method[] directMethods; - private final Method[] virtualMethods; - - public ClassData(Field[] staticFields, Field[] instanceFields, - Method[] directMethods, Method[] virtualMethods) { - this.staticFields = staticFields; - this.instanceFields = instanceFields; - this.directMethods = directMethods; - this.virtualMethods = virtualMethods; - } - - public Field[] getStaticFields() { - return staticFields; - } - - public Field[] getInstanceFields() { - return instanceFields; - } - - public Method[] getDirectMethods() { - return directMethods; - } - - public Method[] getVirtualMethods() { - return virtualMethods; - } - - public Field[] allFields() { - Field[] result = new Field[staticFields.length + instanceFields.length]; - net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(staticFields, 0, result, 0, staticFields.length); - net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(instanceFields, 0, result, staticFields.length, instanceFields.length); - return result; - } - - public Method[] allMethods() { - Method[] result = new Method[directMethods.length + virtualMethods.length]; - net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(directMethods, 0, result, 0, directMethods.length); - net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(virtualMethods, 0, result, directMethods.length, virtualMethods.length); - return result; - } - - public static class Field { - private final int fieldIndex; - private final int accessFlags; - - public Field(int fieldIndex, int accessFlags) { - this.fieldIndex = fieldIndex; - this.accessFlags = accessFlags; - } - - public int getFieldIndex() { - return fieldIndex; - } - - public int getAccessFlags() { - return accessFlags; - } - } - - public static class Method { - private final int methodIndex; - private final int accessFlags; - private final int codeOffset; - - public Method(int methodIndex, int accessFlags, int codeOffset) { - this.methodIndex = methodIndex; - this.accessFlags = accessFlags; - this.codeOffset = codeOffset; - } - - public int getMethodIndex() { - return methodIndex; - } - - public int getAccessFlags() { - return accessFlags; - } - - public int getCodeOffset() { - return codeOffset; - } - } -} diff --git a/app/src/main/java/com/pojavdx/dex/ClassDef.java b/app/src/main/java/com/pojavdx/dex/ClassDef.java deleted file mode 100644 index 9211ad75e..000000000 --- a/app/src/main/java/com/pojavdx/dex/ClassDef.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.pojavdx.dex; - -/** - * A type definition. - */ -public final class ClassDef { - public static final int NO_INDEX = -1; - private final Dex buffer; - private final int offset; - private final int typeIndex; - private final int accessFlags; - private final int supertypeIndex; - private final int interfacesOffset; - private final int sourceFileIndex; - private final int annotationsOffset; - private final int classDataOffset; - private final int staticValuesOffset; - - public ClassDef(Dex buffer, int offset, int typeIndex, int accessFlags, - int supertypeIndex, int interfacesOffset, int sourceFileIndex, - int annotationsOffset, int classDataOffset, int staticValuesOffset) { - this.buffer = buffer; - this.offset = offset; - this.typeIndex = typeIndex; - this.accessFlags = accessFlags; - this.supertypeIndex = supertypeIndex; - this.interfacesOffset = interfacesOffset; - this.sourceFileIndex = sourceFileIndex; - this.annotationsOffset = annotationsOffset; - this.classDataOffset = classDataOffset; - this.staticValuesOffset = staticValuesOffset; - } - - public int getOffset() { - return offset; - } - - public int getTypeIndex() { - return typeIndex; - } - - public int getSupertypeIndex() { - return supertypeIndex; - } - - public int getInterfacesOffset() { - return interfacesOffset; - } - - public short[] getInterfaces() { - return buffer.readTypeList(interfacesOffset).getTypes(); - } - - public int getAccessFlags() { - return accessFlags; - } - - public int getSourceFileIndex() { - return sourceFileIndex; - } - - public int getAnnotationsOffset() { - return annotationsOffset; - } - - public int getClassDataOffset() { - return classDataOffset; - } - - public int getStaticValuesOffset() { - return staticValuesOffset; - } - - @Override - public String toString() { - if (buffer == null) { - return typeIndex + " " + supertypeIndex; - } - - StringBuilder result = new StringBuilder(); - result.append(buffer.typeNames().get(typeIndex)); - if (supertypeIndex != NO_INDEX) { - result.append(" extends ").append(buffer.typeNames().get(supertypeIndex)); - } - return result.toString(); - } -} diff --git a/app/src/main/java/com/pojavdx/dex/Code.java b/app/src/main/java/com/pojavdx/dex/Code.java deleted file mode 100644 index 5da975465..000000000 --- a/app/src/main/java/com/pojavdx/dex/Code.java +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.pojavdx.dex; - -public final class Code { - private final int registersSize; - private final int insSize; - private final int outsSize; - private final int debugInfoOffset; - private final short[] instructions; - private final Try[] tries; - private final CatchHandler[] catchHandlers; - - public Code(int registersSize, int insSize, int outsSize, int debugInfoOffset, - short[] instructions, Try[] tries, CatchHandler[] catchHandlers) { - this.registersSize = registersSize; - this.insSize = insSize; - this.outsSize = outsSize; - this.debugInfoOffset = debugInfoOffset; - this.instructions = instructions; - this.tries = tries; - this.catchHandlers = catchHandlers; - } - - public int getRegistersSize() { - return registersSize; - } - - public int getInsSize() { - return insSize; - } - - public int getOutsSize() { - return outsSize; - } - - public int getDebugInfoOffset() { - return debugInfoOffset; - } - - public short[] getInstructions() { - return instructions; - } - - public Try[] getTries() { - return tries; - } - - public CatchHandler[] getCatchHandlers() { - return catchHandlers; - } - - public static class Try { - final int startAddress; - final int instructionCount; - final int catchHandlerIndex; - - Try(int startAddress, int instructionCount, int catchHandlerIndex) { - this.startAddress = startAddress; - this.instructionCount = instructionCount; - this.catchHandlerIndex = catchHandlerIndex; - } - - public int getStartAddress() { - return startAddress; - } - - public int getInstructionCount() { - return instructionCount; - } - - /** - * Returns this try's catch handler index. Note that - * this is distinct from the its catch handler offset. - */ - public int getCatchHandlerIndex() { - return catchHandlerIndex; - } - } - - public static class CatchHandler { - final int[] typeIndexes; - final int[] addresses; - final int catchAllAddress; - final int offset; - - public CatchHandler(int[] typeIndexes, int[] addresses, int catchAllAddress, int offset) { - this.typeIndexes = typeIndexes; - this.addresses = addresses; - this.catchAllAddress = catchAllAddress; - this.offset = offset; - } - - public int[] getTypeIndexes() { - return typeIndexes; - } - - public int[] getAddresses() { - return addresses; - } - - public int getCatchAllAddress() { - return catchAllAddress; - } - - public int getOffset() { - return offset; - } - } -} diff --git a/app/src/main/java/com/pojavdx/dex/Dex.java b/app/src/main/java/com/pojavdx/dex/Dex.java deleted file mode 100644 index 25c7b84c8..000000000 --- a/app/src/main/java/com/pojavdx/dex/Dex.java +++ /dev/null @@ -1,819 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.pojavdx.dex; - -import com.pojavdx.dex.Code.CatchHandler; -import com.pojavdx.dex.Code.Try; -import com.pojavdx.dex.MethodHandle.MethodHandleType; -import com.pojavdx.dex.util.ByteInput; -import com.pojavdx.dex.util.ByteOutput; -import com.pojavdx.dex.util.FileUtils; -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.UTFDataFormatException; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.util.AbstractList; -import java.util.Collections; -import java.util.Iterator; -import java.util.List; -import java.util.NoSuchElementException; -import java.util.RandomAccess; -import java.util.zip.Adler32; -import java.util.zip.ZipEntry; -import java.util.zip.ZipFile; - -/** - * The bytes of a dex file in memory for reading and writing. All int offsets - * are unsigned. - */ -public final class Dex { - private static final int CHECKSUM_OFFSET = 8; - private static final int CHECKSUM_SIZE = 4; - private static final int SIGNATURE_OFFSET = CHECKSUM_OFFSET + CHECKSUM_SIZE; - private static final int SIGNATURE_SIZE = 20; - // Provided as a convenience to avoid a memory allocation to benefit Dalvik. - // Note: libcore.util.EmptyArray cannot be accessed when this code isn't run on Dalvik. - static final short[] EMPTY_SHORT_ARRAY = new short[0]; - - private ByteBuffer data; - private final TableOfContents tableOfContents = new TableOfContents(); - private int nextSectionStart = 0; - private final StringTable strings = new StringTable(); - private final TypeIndexToDescriptorIndexTable typeIds = new TypeIndexToDescriptorIndexTable(); - private final TypeIndexToDescriptorTable typeNames = new TypeIndexToDescriptorTable(); - private final ProtoIdTable protoIds = new ProtoIdTable(); - private final FieldIdTable fieldIds = new FieldIdTable(); - private final MethodIdTable methodIds = new MethodIdTable(); - - /** - * Creates a new dex that reads from {@code data}. It is an error to modify - * {@code data} after using it to create a dex buffer. - */ - public Dex(byte[] data) throws IOException { - this(ByteBuffer.wrap(data)); - } - - private Dex(ByteBuffer data) throws IOException { - this.data = data; - this.data.order(ByteOrder.LITTLE_ENDIAN); - this.tableOfContents.readFrom(this); - } - - /** - * Creates a new empty dex of the specified size. - */ - public Dex(int byteCount) throws IOException { - this.data = ByteBuffer.wrap(new byte[byteCount]); - this.data.order(ByteOrder.LITTLE_ENDIAN); - } - - /** - * Creates a new dex buffer of the dex in {@code in}, and closes {@code in}. - */ - public Dex(InputStream in) throws IOException { - try { - loadFrom(in); - } finally { - in.close(); - } - } - - /** - * Creates a new dex buffer from the dex file {@code file}. - */ - public Dex(File file) throws IOException { - if (FileUtils.hasArchiveSuffix(file.getName())) { - ZipFile zipFile = new ZipFile(file); - ZipEntry entry = zipFile.getEntry(DexFormat.DEX_IN_JAR_NAME); - if (entry != null) { - try (InputStream inputStream = zipFile.getInputStream(entry)) { - loadFrom(inputStream); - } - zipFile.close(); - } else { - throw new DexException("Expected " + DexFormat.DEX_IN_JAR_NAME + " in " + file); - } - } else if (file.getName().endsWith(".dex")) { - try (InputStream inputStream = new FileInputStream(file)) { - loadFrom(inputStream); - } - } else { - throw new DexException("unknown output extension: " + file); - } - } - - /** - * It is the caller's responsibility to close {@code in}. - */ - private void loadFrom(InputStream in) throws IOException { - ByteArrayOutputStream bytesOut = new ByteArrayOutputStream(); - byte[] buffer = new byte[8192]; - - int count; - while ((count = in.read(buffer)) != -1) { - bytesOut.write(buffer, 0, count); - } - - this.data = ByteBuffer.wrap(bytesOut.toByteArray()); - this.data.order(ByteOrder.LITTLE_ENDIAN); - this.tableOfContents.readFrom(this); - } - - private static void checkBounds(int index, int length) { - if (index < 0 || index >= length) { - throw new IndexOutOfBoundsException("index:" + index + ", length=" + length); - } - } - - public void writeTo(OutputStream out) throws IOException { - byte[] buffer = new byte[8192]; - ByteBuffer data = this.data.duplicate(); // positioned ByteBuffers aren't thread safe - data.clear(); - while (data.hasRemaining()) { - int count = Math.min(buffer.length, data.remaining()); - data.get(buffer, 0, count); - out.write(buffer, 0, count); - } - } - - public void writeTo(File dexOut) throws IOException { - try (OutputStream out = new FileOutputStream(dexOut)) { - writeTo(out); - } - } - - public TableOfContents getTableOfContents() { - return tableOfContents; - } - - public Section open(int position) { - if (position < 0 || position >= data.capacity()) { - throw new IllegalArgumentException("position=" + position - + " length=" + data.capacity()); - } - ByteBuffer sectionData = data.duplicate(); - sectionData.order(ByteOrder.LITTLE_ENDIAN); // necessary? - sectionData.position(position); - sectionData.limit(data.capacity()); - return new Section("section", sectionData); - } - - public Section appendSection(int maxByteCount, String name) { - if ((maxByteCount & 3) != 0) { - throw new IllegalStateException("Not four byte aligned!"); - } - int limit = nextSectionStart + maxByteCount; - ByteBuffer sectionData = data.duplicate(); - sectionData.order(ByteOrder.LITTLE_ENDIAN); // necessary? - sectionData.position(nextSectionStart); - sectionData.limit(limit); - Section result = new Section(name, sectionData); - nextSectionStart = limit; - return result; - } - - public int getLength() { - return data.capacity(); - } - - public int getNextSectionStart() { - return nextSectionStart; - } - - /** - * Returns a copy of the the bytes of this dex. - */ - public byte[] getBytes() { - ByteBuffer data = this.data.duplicate(); // positioned ByteBuffers aren't thread safe - byte[] result = new byte[data.capacity()]; - data.position(0); - data.get(result); - return result; - } - - public List strings() { - return strings; - } - - public List typeIds() { - return typeIds; - } - - public List typeNames() { - return typeNames; - } - - public List protoIds() { - return protoIds; - } - - public List fieldIds() { - return fieldIds; - } - - public List methodIds() { - return methodIds; - } - - public Iterable classDefs() { - return new ClassDefIterable(); - } - - public TypeList readTypeList(int offset) { - if (offset == 0) { - return TypeList.EMPTY; - } - return open(offset).readTypeList(); - } - - public ClassData readClassData(ClassDef classDef) { - int offset = classDef.getClassDataOffset(); - if (offset == 0) { - throw new IllegalArgumentException("offset == 0"); - } - return open(offset).readClassData(); - } - - public Code readCode(ClassData.Method method) { - int offset = method.getCodeOffset(); - if (offset == 0) { - throw new IllegalArgumentException("offset == 0"); - } - return open(offset).readCode(); - } - - /** - * Returns the signature of all but the first 32 bytes of this dex. The - * first 32 bytes of dex files are not specified to be included in the - * signature. - */ - public byte[] computeSignature() throws IOException { - MessageDigest digest; - try { - digest = MessageDigest.getInstance("SHA-1"); - } catch (NoSuchAlgorithmException e) { - throw new AssertionError(); - } - byte[] buffer = new byte[8192]; - ByteBuffer data = this.data.duplicate(); // positioned ByteBuffers aren't thread safe - data.limit(data.capacity()); - data.position(SIGNATURE_OFFSET + SIGNATURE_SIZE); - while (data.hasRemaining()) { - int count = Math.min(buffer.length, data.remaining()); - data.get(buffer, 0, count); - digest.update(buffer, 0, count); - } - return digest.digest(); - } - - /** - * Returns the checksum of all but the first 12 bytes of {@code dex}. - */ - public int computeChecksum() throws IOException { - Adler32 adler32 = new Adler32(); - byte[] buffer = new byte[8192]; - ByteBuffer data = this.data.duplicate(); // positioned ByteBuffers aren't thread safe - data.limit(data.capacity()); - data.position(CHECKSUM_OFFSET + CHECKSUM_SIZE); - while (data.hasRemaining()) { - int count = Math.min(buffer.length, data.remaining()); - data.get(buffer, 0, count); - adler32.update(buffer, 0, count); - } - return (int) adler32.getValue(); - } - - /** - * Generates the signature and checksum of the dex file {@code out} and - * writes them to the file. - */ - public void writeHashes() throws IOException { - open(SIGNATURE_OFFSET).write(computeSignature()); - open(CHECKSUM_OFFSET).writeInt(computeChecksum()); - } - - /** - * Look up a descriptor index from a type index. Cheaper than: - * {@code open(tableOfContents.typeIds.off + (index * SizeOf.TYPE_ID_ITEM)).readInt();} - */ - public int descriptorIndexFromTypeIndex(int typeIndex) { - checkBounds(typeIndex, tableOfContents.typeIds.size); - int position = tableOfContents.typeIds.off + (SizeOf.TYPE_ID_ITEM * typeIndex); - return data.getInt(position); - } - - - public final class Section implements ByteInput, ByteOutput { - private final String name; - private final ByteBuffer data; - private final int initialPosition; - - private Section(String name, ByteBuffer data) { - this.name = name; - this.data = data; - this.initialPosition = data.position(); - } - - public int getPosition() { - return data.position(); - } - - public int readInt() { - return data.getInt(); - } - - public short readShort() { - return data.getShort(); - } - - public int readUnsignedShort() { - return readShort() & 0xffff; - } - - @Override - public byte readByte() { - return data.get(); - } - - public byte[] readByteArray(int length) { - byte[] result = new byte[length]; - data.get(result); - return result; - } - - public short[] readShortArray(int length) { - if (length == 0) { - return EMPTY_SHORT_ARRAY; - } - short[] result = new short[length]; - for (int i = 0; i < length; i++) { - result[i] = readShort(); - } - return result; - } - - public int readUleb128() { - return Leb128.readUnsignedLeb128(this); - } - - public int readUleb128p1() { - return Leb128.readUnsignedLeb128(this) - 1; - } - - public int readSleb128() { - return Leb128.readSignedLeb128(this); - } - - public void writeUleb128p1(int i) { - writeUleb128(i + 1); - } - - public TypeList readTypeList() { - int size = readInt(); - short[] types = readShortArray(size); - alignToFourBytes(); - return new TypeList(Dex.this, types); - } - - public String readString() { - int offset = readInt(); - int savedPosition = data.position(); - int savedLimit = data.limit(); - data.position(offset); - data.limit(data.capacity()); - try { - int expectedLength = readUleb128(); - String result = Mutf8.decode(this, new char[expectedLength]); - if (result.length() != expectedLength) { - throw new DexException("Declared length " + expectedLength - + " doesn't match decoded length of " + result.length()); - } - return result; - } catch (UTFDataFormatException e) { - throw new DexException(e); - } finally { - data.position(savedPosition); - data.limit(savedLimit); - } - } - - public FieldId readFieldId() { - int declaringClassIndex = readUnsignedShort(); - int typeIndex = readUnsignedShort(); - int nameIndex = readInt(); - return new FieldId(Dex.this, declaringClassIndex, typeIndex, nameIndex); - } - - public MethodId readMethodId() { - int declaringClassIndex = readUnsignedShort(); - int protoIndex = readUnsignedShort(); - int nameIndex = readInt(); - return new MethodId(Dex.this, declaringClassIndex, protoIndex, nameIndex); - } - - public ProtoId readProtoId() { - int shortyIndex = readInt(); - int returnTypeIndex = readInt(); - int parametersOffset = readInt(); - return new ProtoId(Dex.this, shortyIndex, returnTypeIndex, parametersOffset); - } - - public CallSiteId readCallSiteId() { - int offset = readInt(); - return new CallSiteId(Dex.this, offset); - } - - public MethodHandle readMethodHandle() { - MethodHandleType methodHandleType = MethodHandleType.fromValue(readUnsignedShort()); - int unused1 = readUnsignedShort(); - int fieldOrMethodId = readUnsignedShort(); - int unused2 = readUnsignedShort(); - return new MethodHandle(Dex.this, methodHandleType, unused1, fieldOrMethodId, unused2); - } - - public ClassDef readClassDef() { - int offset = getPosition(); - int type = readInt(); - int accessFlags = readInt(); - int supertype = readInt(); - int interfacesOffset = readInt(); - int sourceFileIndex = readInt(); - int annotationsOffset = readInt(); - int classDataOffset = readInt(); - int staticValuesOffset = readInt(); - return new ClassDef(Dex.this, offset, type, accessFlags, supertype, - interfacesOffset, sourceFileIndex, annotationsOffset, classDataOffset, - staticValuesOffset); - } - - private Code readCode() { - int registersSize = readUnsignedShort(); - int insSize = readUnsignedShort(); - int outsSize = readUnsignedShort(); - int triesSize = readUnsignedShort(); - int debugInfoOffset = readInt(); - int instructionsSize = readInt(); - short[] instructions = readShortArray(instructionsSize); - Try[] tries; - CatchHandler[] catchHandlers; - if (triesSize > 0) { - if (instructions.length % 2 == 1) { - readShort(); // padding - } - - /* - * We can't read the tries until we've read the catch handlers. - * Unfortunately they're in the opposite order in the dex file - * so we need to read them out-of-order. - */ - Section triesSection = open(data.position()); - skip(triesSize * SizeOf.TRY_ITEM); - catchHandlers = readCatchHandlers(); - tries = triesSection.readTries(triesSize, catchHandlers); - } else { - tries = new Try[0]; - catchHandlers = new CatchHandler[0]; - } - return new Code(registersSize, insSize, outsSize, debugInfoOffset, instructions, - tries, catchHandlers); - } - - private CatchHandler[] readCatchHandlers() { - int baseOffset = data.position(); - int catchHandlersSize = readUleb128(); - CatchHandler[] result = new CatchHandler[catchHandlersSize]; - for (int i = 0; i < catchHandlersSize; i++) { - int offset = data.position() - baseOffset; - result[i] = readCatchHandler(offset); - } - return result; - } - - private Try[] readTries(int triesSize, CatchHandler[] catchHandlers) { - Try[] result = new Try[triesSize]; - for (int i = 0; i < triesSize; i++) { - int startAddress = readInt(); - int instructionCount = readUnsignedShort(); - int handlerOffset = readUnsignedShort(); - int catchHandlerIndex = findCatchHandlerIndex(catchHandlers, handlerOffset); - result[i] = new Try(startAddress, instructionCount, catchHandlerIndex); - } - return result; - } - - private int findCatchHandlerIndex(CatchHandler[] catchHandlers, int offset) { - for (int i = 0; i < catchHandlers.length; i++) { - CatchHandler catchHandler = catchHandlers[i]; - if (catchHandler.getOffset() == offset) { - return i; - } - } - throw new IllegalArgumentException(); - } - - private CatchHandler readCatchHandler(int offset) { - int size = readSleb128(); - int handlersCount = Math.abs(size); - int[] typeIndexes = new int[handlersCount]; - int[] addresses = new int[handlersCount]; - for (int i = 0; i < handlersCount; i++) { - typeIndexes[i] = readUleb128(); - addresses[i] = readUleb128(); - } - int catchAllAddress = size <= 0 ? readUleb128() : -1; - return new CatchHandler(typeIndexes, addresses, catchAllAddress, offset); - } - - private ClassData readClassData() { - int staticFieldsSize = readUleb128(); - int instanceFieldsSize = readUleb128(); - int directMethodsSize = readUleb128(); - int virtualMethodsSize = readUleb128(); - ClassData.Field[] staticFields = readFields(staticFieldsSize); - ClassData.Field[] instanceFields = readFields(instanceFieldsSize); - ClassData.Method[] directMethods = readMethods(directMethodsSize); - ClassData.Method[] virtualMethods = readMethods(virtualMethodsSize); - return new ClassData(staticFields, instanceFields, directMethods, virtualMethods); - } - - private ClassData.Field[] readFields(int count) { - ClassData.Field[] result = new ClassData.Field[count]; - int fieldIndex = 0; - for (int i = 0; i < count; i++) { - fieldIndex += readUleb128(); // field index diff - int accessFlags = readUleb128(); - result[i] = new ClassData.Field(fieldIndex, accessFlags); - } - return result; - } - - private ClassData.Method[] readMethods(int count) { - ClassData.Method[] result = new ClassData.Method[count]; - int methodIndex = 0; - for (int i = 0; i < count; i++) { - methodIndex += readUleb128(); // method index diff - int accessFlags = readUleb128(); - int codeOff = readUleb128(); - result[i] = new ClassData.Method(methodIndex, accessFlags, codeOff); - } - return result; - } - - /** - * Returns a byte array containing the bytes from {@code start} to this - * section's current position. - */ - private byte[] getBytesFrom(int start) { - int end = data.position(); - byte[] result = new byte[end - start]; - data.position(start); - data.get(result); - return result; - } - - public Annotation readAnnotation() { - byte visibility = readByte(); - int start = data.position(); - new EncodedValueReader(this, EncodedValueReader.ENCODED_ANNOTATION).skipValue(); - return new Annotation(Dex.this, visibility, new EncodedValue(getBytesFrom(start))); - } - - public EncodedValue readEncodedArray() { - int start = data.position(); - new EncodedValueReader(this, EncodedValueReader.ENCODED_ARRAY).skipValue(); - return new EncodedValue(getBytesFrom(start)); - } - - public void skip(int count) { - if (count < 0) { - throw new IllegalArgumentException(); - } - data.position(data.position() + count); - } - - /** - * Skips bytes until the position is aligned to a multiple of 4. - */ - public void alignToFourBytes() { - data.position((data.position() + 3) & ~3); - } - - /** - * Writes 0x00 until the position is aligned to a multiple of 4. - */ - public void alignToFourBytesWithZeroFill() { - while ((data.position() & 3) != 0) { - data.put((byte) 0); - } - } - - public void assertFourByteAligned() { - if ((data.position() & 3) != 0) { - throw new IllegalStateException("Not four byte aligned!"); - } - } - - public void write(byte[] bytes) { - this.data.put(bytes); - } - - @Override - public void writeByte(int b) { - data.put((byte) b); - } - - public void writeShort(short i) { - data.putShort(i); - } - - public void writeUnsignedShort(int i) { - short s = (short) i; - if (i != (s & 0xffff)) { - throw new IllegalArgumentException("Expected an unsigned short: " + i); - } - writeShort(s); - } - - public void write(short[] shorts) { - for (short s : shorts) { - writeShort(s); - } - } - - public void writeInt(int i) { - data.putInt(i); - } - - public void writeUleb128(int i) { - try { - Leb128.writeUnsignedLeb128(this, i); - } catch (ArrayIndexOutOfBoundsException e) { - throw new DexException("Section limit " + data.limit() + " exceeded by " + name); - } - } - - public void writeSleb128(int i) { - try { - Leb128.writeSignedLeb128(this, i); - } catch (ArrayIndexOutOfBoundsException e) { - throw new DexException("Section limit " + data.limit() + " exceeded by " + name); - } - } - - public void writeStringData(String value) { - try { - int length = value.length(); - writeUleb128(length); - write(Mutf8.encode(value)); - writeByte(0); - } catch (UTFDataFormatException e) { - throw new AssertionError(); - } - } - - public void writeTypeList(TypeList typeList) { - short[] types = typeList.getTypes(); - writeInt(types.length); - for (short type : types) { - writeShort(type); - } - alignToFourBytesWithZeroFill(); - } - - /** - * Returns the number of bytes used by this section. - */ - public int used() { - return data.position() - initialPosition; - } - } - - private final class StringTable extends AbstractList implements RandomAccess { - @Override - public String get(int index) { - checkBounds(index, tableOfContents.stringIds.size); - return open(tableOfContents.stringIds.off + (index * SizeOf.STRING_ID_ITEM)) - .readString(); - } - @Override - public int size() { - return tableOfContents.stringIds.size; - } - } - - private final class TypeIndexToDescriptorIndexTable extends AbstractList - implements RandomAccess { - @Override - public Integer get(int index) { - return descriptorIndexFromTypeIndex(index); - } - @Override - public int size() { - return tableOfContents.typeIds.size; - } - } - - private final class TypeIndexToDescriptorTable extends AbstractList - implements RandomAccess { - @Override - public String get(int index) { - return strings.get(descriptorIndexFromTypeIndex(index)); - } - @Override - public int size() { - return tableOfContents.typeIds.size; - } - } - - private final class ProtoIdTable extends AbstractList implements RandomAccess { - @Override - public ProtoId get(int index) { - checkBounds(index, tableOfContents.protoIds.size); - return open(tableOfContents.protoIds.off + (SizeOf.PROTO_ID_ITEM * index)) - .readProtoId(); - } - @Override - public int size() { - return tableOfContents.protoIds.size; - } - } - - private final class FieldIdTable extends AbstractList implements RandomAccess { - @Override - public FieldId get(int index) { - checkBounds(index, tableOfContents.fieldIds.size); - return open(tableOfContents.fieldIds.off + (SizeOf.MEMBER_ID_ITEM * index)) - .readFieldId(); - } - @Override - public int size() { - return tableOfContents.fieldIds.size; - } - } - - private final class MethodIdTable extends AbstractList implements RandomAccess { - @Override - public MethodId get(int index) { - checkBounds(index, tableOfContents.methodIds.size); - return open(tableOfContents.methodIds.off + (SizeOf.MEMBER_ID_ITEM * index)) - .readMethodId(); - } - @Override - public int size() { - return tableOfContents.methodIds.size; - } - } - - private final class ClassDefIterator implements Iterator { - private final Dex.Section in = open(tableOfContents.classDefs.off); - private int count = 0; - - @Override - public boolean hasNext() { - return count < tableOfContents.classDefs.size; - } - @Override - public ClassDef next() { - if (!hasNext()) { - throw new NoSuchElementException(); - } - count++; - return in.readClassDef(); - } - @Override - public void remove() { - throw new UnsupportedOperationException(); - } - } - - private final class ClassDefIterable implements Iterable { - @Override - public Iterator iterator() { - return !tableOfContents.classDefs.exists() - ? Collections.emptySet().iterator() - : new ClassDefIterator(); - } - } -} diff --git a/app/src/main/java/com/pojavdx/dex/DexException.java b/app/src/main/java/com/pojavdx/dex/DexException.java deleted file mode 100644 index a8408b86b..000000000 --- a/app/src/main/java/com/pojavdx/dex/DexException.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.pojavdx.dex; - -import com.pojavdx.dex.util.ExceptionWithContext; - -/** - * Thrown when there's a format problem reading, writing, or generally - * processing a dex file. - */ -public class DexException extends ExceptionWithContext { - public DexException(String message) { - super(message); - } - - public DexException(Throwable cause) { - super(cause); - } -} diff --git a/app/src/main/java/com/pojavdx/dex/DexFormat.java b/app/src/main/java/com/pojavdx/dex/DexFormat.java deleted file mode 100644 index 4369b792e..000000000 --- a/app/src/main/java/com/pojavdx/dex/DexFormat.java +++ /dev/null @@ -1,180 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.pojavdx.dex; - -/** - * Constants that show up in and are otherwise related to {@code .dex} - * files, and helper methods for same. - */ -public final class DexFormat { - private DexFormat() {} - - /** API level to target in order to allow spaces in SimpleName */ - public static final int API_SPACES_IN_SIMPLE_NAME = 10000; - - /** API level to target in order to generate const-method-handle and const-method-type */ - public static final int API_CONST_METHOD_HANDLE = 28; - - /** API level to target in order to generate invoke-polymorphic and invoke-custom */ - public static final int API_METHOD_HANDLES = 26; - - /** API level to target in order to define default and static interface methods */ - public static final int API_DEFINE_INTERFACE_METHODS = 24; - - /** API level to target in order to invoke default and static interface methods */ - public static final int API_INVOKE_INTERFACE_METHODS = 24; - - /** API level at which the invocation of static interface methods is permitted by dx. - * This value has been determined experimentally by testing on different VM versions. */ - public static final int API_INVOKE_STATIC_INTERFACE_METHODS = 21; - - /** API level to target in order to suppress extended opcode usage */ - public static final int API_NO_EXTENDED_OPCODES = 13; - - /** - * API level to target in order to produce the most modern file - * format - */ - public static final int API_CURRENT = API_CONST_METHOD_HANDLE; - - /** dex file version number for API level 10000 and earlier */ - public static final String VERSION_FOR_API_10000 = "040"; - - /** dex file version number for API level 28 and earlier */ - public static final String VERSION_FOR_API_28 = "039"; - - /** dex file version number for API level 26 and earlier */ - public static final String VERSION_FOR_API_26 = "038"; - - /** dex file version number for API level 24 and earlier */ - public static final String VERSION_FOR_API_24 = "037"; - - /** dex file version number for API level 13 and earlier */ - public static final String VERSION_FOR_API_13 = "035"; - - /** - * Dex file version number for dalvik. - *

- * Note: Dex version 36 was loadable in some versions of Dalvik but was never fully supported or - * completed and is not considered a valid dex file format. - *

- */ - public static final String VERSION_CURRENT = VERSION_FOR_API_28; - - /** - * file name of the primary {@code .dex} file inside an - * application or library {@code .jar} file - */ - public static final String DEX_IN_JAR_NAME = "classes.dex"; - - /** common prefix for all dex file "magic numbers" */ - public static final String MAGIC_PREFIX = "dex\n"; - - /** common suffix for all dex file "magic numbers" */ - public static final String MAGIC_SUFFIX = "\0"; - - /** - * value used to indicate endianness of file contents - */ - public static final int ENDIAN_TAG = 0x12345678; - - /** - * Maximum addressable field or method index. - * The largest addressable member is 0xffff, in the "instruction formats" spec as field@CCCC or - * meth@CCCC. - */ - public static /* final */ int MAX_MEMBER_IDX = 0x2222; // 0xFFFF - - /** - * Maximum addressable type index. - * The largest addressable type is 0xffff, in the "instruction formats" spec as type@CCCC. - */ - public static /* final */ int MAX_TYPE_IDX = 0x2222; // 65535 - - /** - * Returns the API level corresponding to the given magic number, - * or {@code -1} if the given array is not a well-formed dex file - * magic number. - * - * @param magic array of bytes containing DEX file magic string - * @return API level corresponding to magic string if valid, -1 otherwise. - */ - public static int magicToApi(byte[] magic) { - if (magic.length != 8) { - return -1; - } - - if ((magic[0] != 'd') || (magic[1] != 'e') || (magic[2] != 'x') || (magic[3] != '\n') || - (magic[7] != '\0')) { - return -1; - } - - String version = "" + ((char) magic[4]) + ((char) magic[5]) +((char) magic[6]); - - if (version.equals(VERSION_FOR_API_13)) { - return API_NO_EXTENDED_OPCODES; - } else if (version.equals(VERSION_FOR_API_24)) { - return API_DEFINE_INTERFACE_METHODS; - } else if (version.equals(VERSION_FOR_API_26)) { - return API_METHOD_HANDLES; - } else if (version.equals(VERSION_FOR_API_28)) { - return API_CONST_METHOD_HANDLE; - } else if (version.equals(VERSION_FOR_API_10000)) { - return API_SPACES_IN_SIMPLE_NAME; - } else if (version.equals(VERSION_CURRENT)) { - return API_CURRENT; - } - - return -1; - } - - /** - * Returns the magic number corresponding to the given target API level. - * - * @param targetApiLevel level of API (minimum supported value 13). - * @return Magic string corresponding to API level supplied. - */ - public static String apiToMagic(int targetApiLevel) { - String version; - - if (targetApiLevel >= API_CURRENT) { - version = VERSION_CURRENT; - } else if (targetApiLevel >= API_SPACES_IN_SIMPLE_NAME) { - version = VERSION_FOR_API_10000; - } else if (targetApiLevel >= API_CONST_METHOD_HANDLE) { - version = VERSION_FOR_API_28; - } else if (targetApiLevel >= API_METHOD_HANDLES) { - version = VERSION_FOR_API_26; - } else if (targetApiLevel >= API_DEFINE_INTERFACE_METHODS) { - version = VERSION_FOR_API_24; - } else { - version = VERSION_FOR_API_13; - } - - return MAGIC_PREFIX + version + MAGIC_SUFFIX; - } - - /** - * Checks whether a DEX file magic string is supported. - * @param magic string from DEX file - * @return - */ - public static boolean isSupportedDexMagic(byte[] magic) { - int api = magicToApi(magic); - return api > 0; - } -} diff --git a/app/src/main/java/com/pojavdx/dex/DexIndexOverflowException.java b/app/src/main/java/com/pojavdx/dex/DexIndexOverflowException.java deleted file mode 100644 index c40d0eddb..000000000 --- a/app/src/main/java/com/pojavdx/dex/DexIndexOverflowException.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.pojavdx.dex; - -/** - * Thrown when there's an index overflow writing a dex file. - */ -public final class DexIndexOverflowException extends DexException { - public DexIndexOverflowException(String message) { - super(message); - } - - public DexIndexOverflowException(Throwable cause) { - super(cause); - } -} diff --git a/app/src/main/java/com/pojavdx/dex/EncodedValue.java b/app/src/main/java/com/pojavdx/dex/EncodedValue.java deleted file mode 100644 index c528e1703..000000000 --- a/app/src/main/java/com/pojavdx/dex/EncodedValue.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.pojavdx.dex; - -import com.pojavdx.dex.util.ByteArrayByteInput; -import com.pojavdx.dex.util.ByteInput; - -/** - * An encoded value or array. - */ -public final class EncodedValue implements Comparable { - private final byte[] data; - - public EncodedValue(byte[] data) { - this.data = data; - } - - public ByteInput asByteInput() { - return new ByteArrayByteInput(data); - } - - public byte[] getBytes() { - return data; - } - - public void writeTo(Dex.Section out) { - out.write(data); - } - - @Override - public int compareTo(EncodedValue other) { - int size = Math.min(data.length, other.data.length); - for (int i = 0; i < size; i++) { - if (data[i] != other.data[i]) { - return (data[i] & 0xff) - (other.data[i] & 0xff); - } - } - return data.length - other.data.length; - } - - @Override - public String toString() { - return Integer.toHexString(data[0] & 0xff) + "...(" + data.length + ")"; - } -} diff --git a/app/src/main/java/com/pojavdx/dex/EncodedValueCodec.java b/app/src/main/java/com/pojavdx/dex/EncodedValueCodec.java deleted file mode 100644 index 63070517d..000000000 --- a/app/src/main/java/com/pojavdx/dex/EncodedValueCodec.java +++ /dev/null @@ -1,187 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.pojavdx.dex; - -import com.pojavdx.dex.util.ByteInput; -import com.pojavdx.dex.util.ByteOutput; - -/** - * Read and write {@code encoded_value} primitives. - */ -public final class EncodedValueCodec { - private EncodedValueCodec() { - } - - /** - * Writes a signed integral to {@code out}. - */ - public static void writeSignedIntegralValue(ByteOutput out, int type, long value) { - /* - * Figure out how many bits are needed to represent the value, - * including a sign bit: The bit count is subtracted from 65 - * and not 64 to account for the sign bit. The xor operation - * has the effect of leaving non-negative values alone and - * unary complementing negative values (so that a leading zero - * count always returns a useful number for our present - * purpose). - */ - int requiredBits = 65 - Long.numberOfLeadingZeros(value ^ (value >> 63)); - - // Round up the requiredBits to a number of bytes. - int requiredBytes = (requiredBits + 0x07) >> 3; - - /* - * Write the header byte, which includes the type and - * requiredBytes - 1. - */ - out.writeByte(type | ((requiredBytes - 1) << 5)); - - // Write the value, per se. - while (requiredBytes > 0) { - out.writeByte((byte) value); - value >>= 8; - requiredBytes--; - } - } - - /** - * Writes an unsigned integral to {@code out}. - */ - public static void writeUnsignedIntegralValue(ByteOutput out, int type, long value) { - // Figure out how many bits are needed to represent the value. - int requiredBits = 64 - Long.numberOfLeadingZeros(value); - if (requiredBits == 0) { - requiredBits = 1; - } - - // Round up the requiredBits to a number of bytes. - int requiredBytes = (requiredBits + 0x07) >> 3; - - /* - * Write the header byte, which includes the type and - * requiredBytes - 1. - */ - out.writeByte(type | ((requiredBytes - 1) << 5)); - - // Write the value, per se. - while (requiredBytes > 0) { - out.writeByte((byte) value); - value >>= 8; - requiredBytes--; - } - } - - /** - * Writes a right-zero-extended value to {@code out}. - */ - public static void writeRightZeroExtendedValue(ByteOutput out, int type, long value) { - // Figure out how many bits are needed to represent the value. - int requiredBits = 64 - Long.numberOfTrailingZeros(value); - if (requiredBits == 0) { - requiredBits = 1; - } - - // Round up the requiredBits to a number of bytes. - int requiredBytes = (requiredBits + 0x07) >> 3; - - // Scootch the first bits to be written down to the low-order bits. - value >>= 64 - (requiredBytes * 8); - - /* - * Write the header byte, which includes the type and - * requiredBytes - 1. - */ - out.writeByte(type | ((requiredBytes - 1) << 5)); - - // Write the value, per se. - while (requiredBytes > 0) { - out.writeByte((byte) value); - value >>= 8; - requiredBytes--; - } - } - - /** - * Read a signed integer. - * - * @param zwidth byte count minus one - */ - public static int readSignedInt(ByteInput in, int zwidth) { - int result = 0; - for (int i = zwidth; i >= 0; i--) { - result = (result >>> 8) | ((in.readByte() & 0xff) << 24); - } - result >>= (3 - zwidth) * 8; - return result; - } - - /** - * Read an unsigned integer. - * - * @param zwidth byte count minus one - * @param fillOnRight true to zero fill on the right; false on the left - */ - public static int readUnsignedInt(ByteInput in, int zwidth, boolean fillOnRight) { - int result = 0; - if (!fillOnRight) { - for (int i = zwidth; i >= 0; i--) { - result = (result >>> 8) | ((in.readByte() & 0xff) << 24); - } - result >>>= (3 - zwidth) * 8; - } else { - for (int i = zwidth; i >= 0; i--) { - result = (result >>> 8) | ((in.readByte() & 0xff) << 24); - } - } - return result; - } - - /** - * Read a signed long. - * - * @param zwidth byte count minus one - */ - public static long readSignedLong(ByteInput in, int zwidth) { - long result = 0; - for (int i = zwidth; i >= 0; i--) { - result = (result >>> 8) | ((in.readByte() & 0xffL) << 56); - } - result >>= (7 - zwidth) * 8; - return result; - } - - /** - * Read an unsigned long. - * - * @param zwidth byte count minus one - * @param fillOnRight true to zero fill on the right; false on the left - */ - public static long readUnsignedLong(ByteInput in, int zwidth, boolean fillOnRight) { - long result = 0; - if (!fillOnRight) { - for (int i = zwidth; i >= 0; i--) { - result = (result >>> 8) | ((in.readByte() & 0xffL) << 56); - } - result >>>= (7 - zwidth) * 8; - } else { - for (int i = zwidth; i >= 0; i--) { - result = (result >>> 8) | ((in.readByte() & 0xffL) << 56); - } - } - return result; - } -} diff --git a/app/src/main/java/com/pojavdx/dex/EncodedValueReader.java b/app/src/main/java/com/pojavdx/dex/EncodedValueReader.java deleted file mode 100644 index 7290968c8..000000000 --- a/app/src/main/java/com/pojavdx/dex/EncodedValueReader.java +++ /dev/null @@ -1,307 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.pojavdx.dex; - -import com.pojavdx.dex.util.ByteInput; - -/** - * Pull parser for encoded values. - */ -public final class EncodedValueReader { - public static final int ENCODED_BYTE = 0x00; - public static final int ENCODED_SHORT = 0x02; - public static final int ENCODED_CHAR = 0x03; - public static final int ENCODED_INT = 0x04; - public static final int ENCODED_LONG = 0x06; - public static final int ENCODED_FLOAT = 0x10; - public static final int ENCODED_DOUBLE = 0x11; - public static final int ENCODED_METHOD_TYPE = 0x15; - public static final int ENCODED_METHOD_HANDLE = 0x16; - public static final int ENCODED_STRING = 0x17; - public static final int ENCODED_TYPE = 0x18; - public static final int ENCODED_FIELD = 0x19; - public static final int ENCODED_ENUM = 0x1b; - public static final int ENCODED_METHOD = 0x1a; - public static final int ENCODED_ARRAY = 0x1c; - public static final int ENCODED_ANNOTATION = 0x1d; - public static final int ENCODED_NULL = 0x1e; - public static final int ENCODED_BOOLEAN = 0x1f; - - /** placeholder type if the type is not yet known */ - private static final int MUST_READ = -1; - - protected final ByteInput in; - private int type = MUST_READ; - private int annotationType; - private int arg; - - public EncodedValueReader(ByteInput in) { - this.in = in; - } - - public EncodedValueReader(EncodedValue in) { - this(in.asByteInput()); - } - - /** - * Creates a new encoded value reader whose only value is the specified - * known type. This is useful for encoded values without a type prefix, - * such as class_def_item's encoded_array or annotation_item's - * encoded_annotation. - */ - public EncodedValueReader(ByteInput in, int knownType) { - this.in = in; - this.type = knownType; - } - - public EncodedValueReader(EncodedValue in, int knownType) { - this(in.asByteInput(), knownType); - } - - /** - * Returns the type of the next value to read. - */ - public int peek() { - if (type == MUST_READ) { - int argAndType = in.readByte() & 0xff; - type = argAndType & 0x1f; - arg = (argAndType & 0xe0) >> 5; - } - return type; - } - - /** - * Begins reading the elements of an array, returning the array's size. The - * caller must follow up by calling a read method for each element in the - * array. For example, this reads a byte array:
   {@code
-     *   int arraySize = readArray();
-     *   for (int i = 0, i < arraySize; i++) {
-     *     readByte();
-     *   }
-     * }
- */ - public int readArray() { - checkType(ENCODED_ARRAY); - type = MUST_READ; - return Leb128.readUnsignedLeb128(in); - } - - /** - * Begins reading the fields of an annotation, returning the number of - * fields. The caller must follow up by making alternating calls to {@link - * #readAnnotationName()} and another read method. For example, this reads - * an annotation whose fields are all bytes:
   {@code
-     *   int fieldCount = readAnnotation();
-     *   int annotationType = getAnnotationType();
-     *   for (int i = 0; i < fieldCount; i++) {
-     *       readAnnotationName();
-     *       readByte();
-     *   }
-     * }
- */ - public int readAnnotation() { - checkType(ENCODED_ANNOTATION); - type = MUST_READ; - annotationType = Leb128.readUnsignedLeb128(in); - return Leb128.readUnsignedLeb128(in); - } - - /** - * Returns the type of the annotation just returned by {@link - * #readAnnotation()}. This method's value is undefined unless the most - * recent call was to {@link #readAnnotation()}. - */ - public int getAnnotationType() { - return annotationType; - } - - public int readAnnotationName() { - return Leb128.readUnsignedLeb128(in); - } - - public byte readByte() { - checkType(ENCODED_BYTE); - type = MUST_READ; - return (byte) EncodedValueCodec.readSignedInt(in, arg); - } - - public short readShort() { - checkType(ENCODED_SHORT); - type = MUST_READ; - return (short) EncodedValueCodec.readSignedInt(in, arg); - } - - public char readChar() { - checkType(ENCODED_CHAR); - type = MUST_READ; - return (char) EncodedValueCodec.readUnsignedInt(in, arg, false); - } - - public int readInt() { - checkType(ENCODED_INT); - type = MUST_READ; - return EncodedValueCodec.readSignedInt(in, arg); - } - - public long readLong() { - checkType(ENCODED_LONG); - type = MUST_READ; - return EncodedValueCodec.readSignedLong(in, arg); - } - - public float readFloat() { - checkType(ENCODED_FLOAT); - type = MUST_READ; - return Float.intBitsToFloat(EncodedValueCodec.readUnsignedInt(in, arg, true)); - } - - public double readDouble() { - checkType(ENCODED_DOUBLE); - type = MUST_READ; - return Double.longBitsToDouble(EncodedValueCodec.readUnsignedLong(in, arg, true)); - } - - public int readMethodType() { - checkType(ENCODED_METHOD_TYPE); - type = MUST_READ; - return EncodedValueCodec.readUnsignedInt(in, arg, false); - } - - public int readMethodHandle() { - checkType(ENCODED_METHOD_HANDLE); - type = MUST_READ; - return EncodedValueCodec.readUnsignedInt(in, arg, false); - } - - public int readString() { - checkType(ENCODED_STRING); - type = MUST_READ; - return EncodedValueCodec.readUnsignedInt(in, arg, false); - } - - public int readType() { - checkType(ENCODED_TYPE); - type = MUST_READ; - return EncodedValueCodec.readUnsignedInt(in, arg, false); - } - - public int readField() { - checkType(ENCODED_FIELD); - type = MUST_READ; - return EncodedValueCodec.readUnsignedInt(in, arg, false); - } - - public int readEnum() { - checkType(ENCODED_ENUM); - type = MUST_READ; - return EncodedValueCodec.readUnsignedInt(in, arg, false); - } - - public int readMethod() { - checkType(ENCODED_METHOD); - type = MUST_READ; - return EncodedValueCodec.readUnsignedInt(in, arg, false); - } - - public void readNull() { - checkType(ENCODED_NULL); - type = MUST_READ; - } - - public boolean readBoolean() { - checkType(ENCODED_BOOLEAN); - type = MUST_READ; - return arg != 0; - } - - /** - * Skips a single value, including its nested values if it is an array or - * annotation. - */ - public void skipValue() { - switch (peek()) { - case ENCODED_BYTE: - readByte(); - break; - case ENCODED_SHORT: - readShort(); - break; - case ENCODED_CHAR: - readChar(); - break; - case ENCODED_INT: - readInt(); - break; - case ENCODED_LONG: - readLong(); - break; - case ENCODED_FLOAT: - readFloat(); - break; - case ENCODED_DOUBLE: - readDouble(); - break; - case ENCODED_METHOD_TYPE: - readMethodType(); - break; - case ENCODED_METHOD_HANDLE: - readMethodHandle(); - break; - case ENCODED_STRING: - readString(); - break; - case ENCODED_TYPE: - readType(); - break; - case ENCODED_FIELD: - readField(); - break; - case ENCODED_ENUM: - readEnum(); - break; - case ENCODED_METHOD: - readMethod(); - break; - case ENCODED_ARRAY: - for (int i = 0, size = readArray(); i < size; i++) { - skipValue(); - } - break; - case ENCODED_ANNOTATION: - for (int i = 0, size = readAnnotation(); i < size; i++) { - readAnnotationName(); - skipValue(); - } - break; - case ENCODED_NULL: - readNull(); - break; - case ENCODED_BOOLEAN: - readBoolean(); - break; - default: - throw new DexException("Unexpected type: " + Integer.toHexString(type)); - } - } - - private void checkType(int expected) { - if (peek() != expected) { - throw new IllegalStateException( - String.format("Expected %x but was %x", expected, peek())); - } - } -} diff --git a/app/src/main/java/com/pojavdx/dex/FieldId.java b/app/src/main/java/com/pojavdx/dex/FieldId.java deleted file mode 100644 index 8a3b43a25..000000000 --- a/app/src/main/java/com/pojavdx/dex/FieldId.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.pojavdx.dex; - -import com.pojavdx.dex.util.Unsigned; - -public final class FieldId implements Comparable { - private final Dex dex; - private final int declaringClassIndex; - private final int typeIndex; - private final int nameIndex; - - public FieldId(Dex dex, int declaringClassIndex, int typeIndex, int nameIndex) { - this.dex = dex; - this.declaringClassIndex = declaringClassIndex; - this.typeIndex = typeIndex; - this.nameIndex = nameIndex; - } - - public int getDeclaringClassIndex() { - return declaringClassIndex; - } - - public int getTypeIndex() { - return typeIndex; - } - - public int getNameIndex() { - return nameIndex; - } - - @Override - public int compareTo(FieldId other) { - if (declaringClassIndex != other.declaringClassIndex) { - return Unsigned.compare(declaringClassIndex, other.declaringClassIndex); - } - if (nameIndex != other.nameIndex) { - return Unsigned.compare(nameIndex, other.nameIndex); - } - return Unsigned.compare(typeIndex, other.typeIndex); // should always be 0 - } - - public void writeTo(Dex.Section out) { - out.writeUnsignedShort(declaringClassIndex); - out.writeUnsignedShort(typeIndex); - out.writeInt(nameIndex); - } - - @Override - public String toString() { - if (dex == null) { - return declaringClassIndex + " " + typeIndex + " " + nameIndex; - } - return dex.typeNames().get(typeIndex) + "." + dex.strings().get(nameIndex); - } -} diff --git a/app/src/main/java/com/pojavdx/dex/Leb128.java b/app/src/main/java/com/pojavdx/dex/Leb128.java deleted file mode 100644 index 6bb923c21..000000000 --- a/app/src/main/java/com/pojavdx/dex/Leb128.java +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.pojavdx.dex; - -import com.pojavdx.dex.util.ByteInput; -import com.pojavdx.dex.util.ByteOutput; - -/** - * Reads and writes DWARFv3 LEB 128 signed and unsigned integers. See DWARF v3 - * section 7.6. - */ -public final class Leb128 { - private Leb128() { - } - - /** - * Gets the number of bytes in the unsigned LEB128 encoding of the - * given value. - * - * @param value the value in question - * @return its write size, in bytes - */ - public static int unsignedLeb128Size(int value) { - // TODO: This could be much cleverer. - - int remaining = value >> 7; - int count = 0; - - while (remaining != 0) { - remaining >>= 7; - count++; - } - - return count + 1; - } - - /** - * Reads an signed integer from {@code in}. - */ - public static int readSignedLeb128(ByteInput in) { - int result = 0; - int cur; - int count = 0; - int signBits = -1; - - do { - cur = in.readByte() & 0xff; - result |= (cur & 0x7f) << (count * 7); - signBits <<= 7; - count++; - } while (((cur & 0x80) == 0x80) && count < 5); - - if ((cur & 0x80) == 0x80) { - throw new DexException("invalid LEB128 sequence"); - } - - // Sign extend if appropriate - if (((signBits >> 1) & result) != 0 ) { - result |= signBits; - } - - return result; - } - - /** - * Reads an unsigned integer from {@code in}. - */ - public static int readUnsignedLeb128(ByteInput in) { - int result = 0; - int cur; - int count = 0; - - do { - cur = in.readByte() & 0xff; - result |= (cur & 0x7f) << (count * 7); - count++; - } while (((cur & 0x80) == 0x80) && count < 5); - - if ((cur & 0x80) == 0x80) { - throw new DexException("invalid LEB128 sequence"); - } - - return result; - } - - /** - * Writes {@code value} as an unsigned integer to {@code out}, starting at - * {@code offset}. Returns the number of bytes written. - */ - public static void writeUnsignedLeb128(ByteOutput out, int value) { - int remaining = value >>> 7; - - while (remaining != 0) { - out.writeByte((byte) ((value & 0x7f) | 0x80)); - value = remaining; - remaining >>>= 7; - } - - out.writeByte((byte) (value & 0x7f)); - } - - /** - * Writes {@code value} as a signed integer to {@code out}, starting at - * {@code offset}. Returns the number of bytes written. - */ - public static void writeSignedLeb128(ByteOutput out, int value) { - int remaining = value >> 7; - boolean hasMore = true; - int end = ((value & Integer.MIN_VALUE) == 0) ? 0 : -1; - - while (hasMore) { - hasMore = (remaining != end) - || ((remaining & 1) != ((value >> 6) & 1)); - - out.writeByte((byte) ((value & 0x7f) | (hasMore ? 0x80 : 0))); - value = remaining; - remaining >>= 7; - } - } -} diff --git a/app/src/main/java/com/pojavdx/dex/MethodHandle.java b/app/src/main/java/com/pojavdx/dex/MethodHandle.java deleted file mode 100644 index 31d11b055..000000000 --- a/app/src/main/java/com/pojavdx/dex/MethodHandle.java +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.pojavdx.dex; - -import com.pojavdx.dex.Dex.Section; -import com.pojavdx.dex.util.Unsigned; - -/** - * A method_handle_item: - * https://source.android.com/devices/tech/dalvik/dex-format#method-handle-item - */ -public class MethodHandle implements Comparable { - - /** - * A method handle type code: - * https://source.android.com/devices/tech/dalvik/dex-format#method-handle-type-codes - */ - public enum MethodHandleType { - METHOD_HANDLE_TYPE_STATIC_PUT(0x00), - METHOD_HANDLE_TYPE_STATIC_GET(0x01), - METHOD_HANDLE_TYPE_INSTANCE_PUT(0x02), - METHOD_HANDLE_TYPE_INSTANCE_GET(0x03), - METHOD_HANDLE_TYPE_INVOKE_STATIC(0x04), - METHOD_HANDLE_TYPE_INVOKE_INSTANCE(0x05), - METHOD_HANDLE_TYPE_INVOKE_DIRECT(0x06), - METHOD_HANDLE_TYPE_INVOKE_CONSTRUCTOR(0x07), - METHOD_HANDLE_TYPE_INVOKE_INTERFACE(0x08); - - private final int value; - - MethodHandleType(int value) { - this.value = value; - } - - static MethodHandleType fromValue(int value) { - for (MethodHandleType methodHandleType : values()) { - if (methodHandleType.value == value) { - return methodHandleType; - } - } - throw new IllegalArgumentException(String.valueOf(value)); - } - - public boolean isField() { - switch (this) { - case METHOD_HANDLE_TYPE_STATIC_PUT: - case METHOD_HANDLE_TYPE_STATIC_GET: - case METHOD_HANDLE_TYPE_INSTANCE_PUT: - case METHOD_HANDLE_TYPE_INSTANCE_GET: - return true; - default: - return false; - } - } - } - - private final Dex dex; - private final MethodHandleType methodHandleType; - private final int unused1; - private final int fieldOrMethodId; - private final int unused2; - - public MethodHandle( - Dex dex, - MethodHandleType methodHandleType, - int unused1, - int fieldOrMethodId, - int unused2) { - this.dex = dex; - this.methodHandleType = methodHandleType; - this.unused1 = unused1; - this.fieldOrMethodId = fieldOrMethodId; - this.unused2 = unused2; - } - - @Override - public int compareTo(MethodHandle o) { - if (methodHandleType != o.methodHandleType) { - return methodHandleType.compareTo(o.methodHandleType); - } - return Unsigned.compare(fieldOrMethodId, o.fieldOrMethodId); - } - - public MethodHandleType getMethodHandleType() { - return methodHandleType; - } - - public int getUnused1() { - return unused1; - } - - public int getFieldOrMethodId() { - return fieldOrMethodId; - } - - public int getUnused2() { - return unused2; - } - - public void writeTo(Section out) { - out.writeUnsignedShort(methodHandleType.value); - out.writeUnsignedShort(unused1); - out.writeUnsignedShort(fieldOrMethodId); - out.writeUnsignedShort(unused2); - } - - @Override - public String toString() { - if (dex == null) { - return methodHandleType + " " + fieldOrMethodId; - } - return methodHandleType - + " " - + (methodHandleType.isField() - ? dex.fieldIds().get(fieldOrMethodId) - : dex.methodIds().get(fieldOrMethodId)); - } -} diff --git a/app/src/main/java/com/pojavdx/dex/MethodId.java b/app/src/main/java/com/pojavdx/dex/MethodId.java deleted file mode 100644 index 1c7534554..000000000 --- a/app/src/main/java/com/pojavdx/dex/MethodId.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.pojavdx.dex; - -import com.pojavdx.dex.util.Unsigned; - -public final class MethodId implements Comparable { - private final Dex dex; - private final int declaringClassIndex; - private final int protoIndex; - private final int nameIndex; - - public MethodId(Dex dex, int declaringClassIndex, int protoIndex, int nameIndex) { - this.dex = dex; - this.declaringClassIndex = declaringClassIndex; - this.protoIndex = protoIndex; - this.nameIndex = nameIndex; - } - - public int getDeclaringClassIndex() { - return declaringClassIndex; - } - - public int getProtoIndex() { - return protoIndex; - } - - public int getNameIndex() { - return nameIndex; - } - - @Override - public int compareTo(MethodId other) { - if (declaringClassIndex != other.declaringClassIndex) { - return Unsigned.compare(declaringClassIndex, other.declaringClassIndex); - } - if (nameIndex != other.nameIndex) { - return Unsigned.compare(nameIndex, other.nameIndex); - } - return Unsigned.compare(protoIndex, other.protoIndex); - } - - public void writeTo(Dex.Section out) { - out.writeUnsignedShort(declaringClassIndex); - out.writeUnsignedShort(protoIndex); - out.writeInt(nameIndex); - } - - @Override - public String toString() { - if (dex == null) { - return declaringClassIndex + " " + protoIndex + " " + nameIndex; - } - return dex.typeNames().get(declaringClassIndex) - + "." + dex.strings().get(nameIndex) - + dex.readTypeList(dex.protoIds().get(protoIndex).getParametersOffset()); - } -} diff --git a/app/src/main/java/com/pojavdx/dex/Mutf8.java b/app/src/main/java/com/pojavdx/dex/Mutf8.java deleted file mode 100644 index 97d254795..000000000 --- a/app/src/main/java/com/pojavdx/dex/Mutf8.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.pojavdx.dex; - -import com.pojavdx.dex.util.ByteInput; -import java.io.UTFDataFormatException; - -/** - * Modified UTF-8 as described in the dex file format spec. - */ -public final class Mutf8 { - private Mutf8() {} - - /** - * Decodes bytes from {@code in} into {@code out} until a delimiter 0x00 is - * encountered. Returns a new string containing the decoded characters. - */ - public static String decode(ByteInput in, char[] out) throws UTFDataFormatException { - int s = 0; - while (true) { - char a = (char) (in.readByte() & 0xff); - if (a == 0) { - return new String(out, 0, s); - } - out[s] = a; - if (a < '\u0080') { - s++; - } else if ((a & 0xe0) == 0xc0) { - int b = in.readByte() & 0xff; - if ((b & 0xC0) != 0x80) { - throw new UTFDataFormatException("bad second byte"); - } - out[s++] = (char) (((a & 0x1F) << 6) | (b & 0x3F)); - } else if ((a & 0xf0) == 0xe0) { - int b = in.readByte() & 0xff; - int c = in.readByte() & 0xff; - if (((b & 0xC0) != 0x80) || ((c & 0xC0) != 0x80)) { - throw new UTFDataFormatException("bad second or third byte"); - } - out[s++] = (char) (((a & 0x0F) << 12) | ((b & 0x3F) << 6) | (c & 0x3F)); - } else { - throw new UTFDataFormatException("bad byte"); - } - } - } - - /** - * Returns the number of bytes the modified UTF8 representation of 's' would take. - */ - private static long countBytes(String s, boolean shortLength) throws UTFDataFormatException { - long result = 0; - final int length = s.length(); - for (int i = 0; i < length; ++i) { - char ch = s.charAt(i); - if (ch != 0 && ch <= 127) { // U+0000 uses two bytes. - ++result; - } else if (ch <= 2047) { - result += 2; - } else { - result += 3; - } - if (shortLength && result > 65535) { - throw new UTFDataFormatException("String more than 65535 UTF bytes long"); - } - } - return result; - } - - /** - * Encodes the modified UTF-8 bytes corresponding to {@code s} into {@code - * dst}, starting at {@code offset}. - */ - public static void encode(byte[] dst, int offset, String s) { - final int length = s.length(); - for (int i = 0; i < length; i++) { - char ch = s.charAt(i); - if (ch != 0 && ch <= 127) { // U+0000 uses two bytes. - dst[offset++] = (byte) ch; - } else if (ch <= 2047) { - dst[offset++] = (byte) (0xc0 | (0x1f & (ch >> 6))); - dst[offset++] = (byte) (0x80 | (0x3f & ch)); - } else { - dst[offset++] = (byte) (0xe0 | (0x0f & (ch >> 12))); - dst[offset++] = (byte) (0x80 | (0x3f & (ch >> 6))); - dst[offset++] = (byte) (0x80 | (0x3f & ch)); - } - } - } - - /** - * Returns an array containing the modified UTF-8 form of {@code s}. - */ - public static byte[] encode(String s) throws UTFDataFormatException { - int utfCount = (int) countBytes(s, true); - byte[] result = new byte[utfCount]; - encode(result, 0, s); - return result; - } -} diff --git a/app/src/main/java/com/pojavdx/dex/ProtoId.java b/app/src/main/java/com/pojavdx/dex/ProtoId.java deleted file mode 100644 index e32204839..000000000 --- a/app/src/main/java/com/pojavdx/dex/ProtoId.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.pojavdx.dex; - -import com.pojavdx.dex.util.Unsigned; - -public final class ProtoId implements Comparable { - private final Dex dex; - private final int shortyIndex; - private final int returnTypeIndex; - private final int parametersOffset; - - public ProtoId(Dex dex, int shortyIndex, int returnTypeIndex, int parametersOffset) { - this.dex = dex; - this.shortyIndex = shortyIndex; - this.returnTypeIndex = returnTypeIndex; - this.parametersOffset = parametersOffset; - } - - @Override - public int compareTo(ProtoId other) { - if (returnTypeIndex != other.returnTypeIndex) { - return Unsigned.compare(returnTypeIndex, other.returnTypeIndex); - } - return Unsigned.compare(parametersOffset, other.parametersOffset); - } - - public int getShortyIndex() { - return shortyIndex; - } - - public int getReturnTypeIndex() { - return returnTypeIndex; - } - - public int getParametersOffset() { - return parametersOffset; - } - - public void writeTo(Dex.Section out) { - out.writeInt(shortyIndex); - out.writeInt(returnTypeIndex); - out.writeInt(parametersOffset); - } - - @Override - public String toString() { - if (dex == null) { - return shortyIndex + " " + returnTypeIndex + " " + parametersOffset; - } - - return dex.strings().get(shortyIndex) - + ": " + dex.typeNames().get(returnTypeIndex) - + " " + dex.readTypeList(parametersOffset); - } -} diff --git a/app/src/main/java/com/pojavdx/dex/SizeOf.java b/app/src/main/java/com/pojavdx/dex/SizeOf.java deleted file mode 100644 index 7ad3d3a2b..000000000 --- a/app/src/main/java/com/pojavdx/dex/SizeOf.java +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.pojavdx.dex; - -public final class SizeOf { - private SizeOf() {} - - public static final int UBYTE = 1; - public static final int USHORT = 2; - public static final int UINT = 4; - - public static final int SIGNATURE = UBYTE * 20; - - /** - * magic ubyte[8] - * checksum uint - * signature ubyte[20] - * file_size uint - * header_size uint - * endian_tag uint - * link_size uint - * link_off uint - * map_off uint - * string_ids_size uint - * string_ids_off uint - * type_ids_size uint - * type_ids_off uint - * proto_ids_size uint - * proto_ids_off uint - * field_ids_size uint - * field_ids_off uint - * method_ids_size uint - * method_ids_off uint - * class_defs_size uint - * class_defs_off uint - * data_size uint - * data_off uint - */ - public static final int HEADER_ITEM = (8 * UBYTE) + UINT + SIGNATURE + (20 * UINT); // 0x70 - - /** - * string_data_off uint - */ - public static final int STRING_ID_ITEM = UINT; - - /** - * descriptor_idx uint - */ - public static final int TYPE_ID_ITEM = UINT; - - /** - * type_idx ushort - */ - public static final int TYPE_ITEM = USHORT; - - /** - * shorty_idx uint - * return_type_idx uint - * return_type_idx uint - */ - public static final int PROTO_ID_ITEM = UINT + UINT + UINT; - - /** - * class_idx ushort - * type_idx/proto_idx ushort - * name_idx uint - */ - public static final int MEMBER_ID_ITEM = USHORT + USHORT + UINT; - - /** - * class_idx uint - * access_flags uint - * superclass_idx uint - * interfaces_off uint - * source_file_idx uint - * annotations_off uint - * class_data_off uint - * static_values_off uint - */ - public static final int CLASS_DEF_ITEM = 8 * UINT; - - /** - * type ushort - * unused ushort - * size uint - * offset uint - */ - public static final int MAP_ITEM = USHORT + USHORT + UINT + UINT; - - /** - * start_addr uint - * insn_count ushort - * handler_off ushort - */ - public static final int TRY_ITEM = UINT + USHORT + USHORT; - - /** - * call_site_off uint - */ - public static final int CALL_SITE_ID_ITEM = UINT; - - /** - * method_handle_type ushort - * unused ushort - * field_or_method_id ushort - * unused ushort - */ - public static final int METHOD_HANDLE_ITEM = USHORT + USHORT + USHORT + USHORT; -} diff --git a/app/src/main/java/com/pojavdx/dex/TableOfContents.java b/app/src/main/java/com/pojavdx/dex/TableOfContents.java deleted file mode 100644 index 77a7a6dee..000000000 --- a/app/src/main/java/com/pojavdx/dex/TableOfContents.java +++ /dev/null @@ -1,246 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.pojavdx.dex; - -import java.io.IOException; -import java.io.UnsupportedEncodingException; -import java.util.Arrays; - -/** - * The file header and map. - */ -public final class TableOfContents { - - /* - * TODO: factor out ID constants. - */ - - public final Section header = new Section(0x0000); - public final Section stringIds = new Section(0x0001); - public final Section typeIds = new Section(0x0002); - public final Section protoIds = new Section(0x0003); - public final Section fieldIds = new Section(0x0004); - public final Section methodIds = new Section(0x0005); - public final Section classDefs = new Section(0x0006); - public final Section callSiteIds = new Section(0x0007); - public final Section methodHandles = new Section(0x0008); - public final Section mapList = new Section(0x1000); - public final Section typeLists = new Section(0x1001); - public final Section annotationSetRefLists = new Section(0x1002); - public final Section annotationSets = new Section(0x1003); - public final Section classDatas = new Section(0x2000); - public final Section codes = new Section(0x2001); - public final Section stringDatas = new Section(0x2002); - public final Section debugInfos = new Section(0x2003); - public final Section annotations = new Section(0x2004); - public final Section encodedArrays = new Section(0x2005); - public final Section annotationsDirectories = new Section(0x2006); - public final Section[] sections = { - header, stringIds, typeIds, protoIds, fieldIds, methodIds, classDefs, mapList, callSiteIds, - methodHandles, typeLists, annotationSetRefLists, annotationSets, classDatas, codes, - stringDatas, debugInfos, annotations, encodedArrays, annotationsDirectories - }; - - public int apiLevel; - public int checksum; - public byte[] signature; - public int fileSize; - public int linkSize; - public int linkOff; - public int dataSize; - public int dataOff; - - public TableOfContents() { - signature = new byte[20]; - } - - public void readFrom(Dex dex) throws IOException { - readHeader(dex.open(0)); - readMap(dex.open(mapList.off)); - computeSizesFromOffsets(); - } - - private void readHeader(Dex.Section headerIn) throws UnsupportedEncodingException { - byte[] magic = headerIn.readByteArray(8); - - if (!DexFormat.isSupportedDexMagic(magic)) { - String msg = - String.format("Unexpected magic: [0x%02x, 0x%02x, 0x%02x, 0x%02x, " - + "0x%02x, 0x%02x, 0x%02x, 0x%02x]", - magic[0], magic[1], magic[2], magic[3], - magic[4], magic[5], magic[6], magic[7]); - throw new DexException(msg); - } - - apiLevel = DexFormat.magicToApi(magic); - checksum = headerIn.readInt(); - signature = headerIn.readByteArray(20); - fileSize = headerIn.readInt(); - int headerSize = headerIn.readInt(); - if (headerSize != SizeOf.HEADER_ITEM) { - throw new DexException("Unexpected header: 0x" + Integer.toHexString(headerSize)); - } - int endianTag = headerIn.readInt(); - if (endianTag != DexFormat.ENDIAN_TAG) { - throw new DexException("Unexpected endian tag: 0x" + Integer.toHexString(endianTag)); - } - linkSize = headerIn.readInt(); - linkOff = headerIn.readInt(); - mapList.off = headerIn.readInt(); - if (mapList.off == 0) { - throw new DexException("Cannot merge dex files that do not contain a map"); - } - stringIds.size = headerIn.readInt(); - stringIds.off = headerIn.readInt(); - typeIds.size = headerIn.readInt(); - typeIds.off = headerIn.readInt(); - protoIds.size = headerIn.readInt(); - protoIds.off = headerIn.readInt(); - fieldIds.size = headerIn.readInt(); - fieldIds.off = headerIn.readInt(); - methodIds.size = headerIn.readInt(); - methodIds.off = headerIn.readInt(); - classDefs.size = headerIn.readInt(); - classDefs.off = headerIn.readInt(); - dataSize = headerIn.readInt(); - dataOff = headerIn.readInt(); - } - - private void readMap(Dex.Section in) throws IOException { - int mapSize = in.readInt(); - Section previous = null; - for (int i = 0; i < mapSize; i++) { - short type = in.readShort(); - in.readShort(); // unused - Section section = getSection(type); - int size = in.readInt(); - int offset = in.readInt(); - - if ((section.size != 0 && section.size != size) - || (section.off != -1 && section.off != offset)) { - throw new DexException("Unexpected map value for 0x" + Integer.toHexString(type)); - } - - section.size = size; - section.off = offset; - - if (previous != null && previous.off > section.off) { - throw new DexException("Map is unsorted at " + previous + ", " + section); - } - - previous = section; - } - Arrays.sort(sections); - } - - public void computeSizesFromOffsets() { - int end = dataOff + dataSize; - for (int i = sections.length - 1; i >= 0; i--) { - Section section = sections[i]; - if (section.off == -1) { - continue; - } - if (section.off > end) { - throw new DexException("Map is unsorted at " + section); - } - section.byteCount = end - section.off; - end = section.off; - } - } - - private Section getSection(short type) { - for (Section section : sections) { - if (section.type == type) { - return section; - } - } - throw new IllegalArgumentException("No such map item: " + type); - } - - public void writeHeader(Dex.Section out, int api) throws IOException { - out.write(DexFormat.apiToMagic(api).getBytes("UTF-8")); - out.writeInt(checksum); - out.write(signature); - out.writeInt(fileSize); - out.writeInt(SizeOf.HEADER_ITEM); - out.writeInt(DexFormat.ENDIAN_TAG); - out.writeInt(linkSize); - out.writeInt(linkOff); - out.writeInt(mapList.off); - out.writeInt(stringIds.size); - out.writeInt(stringIds.off); - out.writeInt(typeIds.size); - out.writeInt(typeIds.off); - out.writeInt(protoIds.size); - out.writeInt(protoIds.off); - out.writeInt(fieldIds.size); - out.writeInt(fieldIds.off); - out.writeInt(methodIds.size); - out.writeInt(methodIds.off); - out.writeInt(classDefs.size); - out.writeInt(classDefs.off); - out.writeInt(dataSize); - out.writeInt(dataOff); - } - - public void writeMap(Dex.Section out) throws IOException { - int count = 0; - for (Section section : sections) { - if (section.exists()) { - count++; - } - } - - out.writeInt(count); - for (Section section : sections) { - if (section.exists()) { - out.writeShort(section.type); - out.writeShort((short) 0); - out.writeInt(section.size); - out.writeInt(section.off); - } - } - } - - public static class Section implements Comparable
{ - public final short type; - public int size = 0; - public int off = -1; - public int byteCount = 0; - - public Section(int type) { - this.type = (short) type; - } - - public boolean exists() { - return size > 0; - } - - @Override - public int compareTo(Section section) { - if (off != section.off) { - return off < section.off ? -1 : 1; - } - return 0; - } - - @Override - public String toString() { - return String.format("Section[type=%#x,off=%#x,size=%#x]", type, off, size); - } - } -} diff --git a/app/src/main/java/com/pojavdx/dex/TypeList.java b/app/src/main/java/com/pojavdx/dex/TypeList.java deleted file mode 100644 index 07cf8f8c5..000000000 --- a/app/src/main/java/com/pojavdx/dex/TypeList.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.pojavdx.dex; - -import com.pojavdx.dex.util.Unsigned; - -public final class TypeList implements Comparable { - - public static final TypeList EMPTY = new TypeList(null, Dex.EMPTY_SHORT_ARRAY); - - private final Dex dex; - private final short[] types; - - public TypeList(Dex dex, short[] types) { - this.dex = dex; - this.types = types; - } - - public short[] getTypes() { - return types; - } - - @Override - public int compareTo(TypeList other) { - for (int i = 0; i < types.length && i < other.types.length; i++) { - if (types[i] != other.types[i]) { - return Unsigned.compare(types[i], other.types[i]); - } - } - return Unsigned.compare(types.length, other.types.length); - } - - @Override - public String toString() { - StringBuilder result = new StringBuilder(); - result.append("("); - for (int i = 0, typesLength = types.length; i < typesLength; i++) { - result.append(dex != null ? dex.typeNames().get(types[i]) : types[i]); - } - result.append(")"); - return result.toString(); - } -} diff --git a/app/src/main/java/com/pojavdx/dex/util/ByteArrayByteInput.java b/app/src/main/java/com/pojavdx/dex/util/ByteArrayByteInput.java deleted file mode 100644 index d5a296327..000000000 --- a/app/src/main/java/com/pojavdx/dex/util/ByteArrayByteInput.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.pojavdx.dex.util; - -public final class ByteArrayByteInput implements ByteInput { - - private final byte[] bytes; - private int position; - - public ByteArrayByteInput(byte... bytes) { - this.bytes = bytes; - } - - @Override - public byte readByte() { - return bytes[position++]; - } -} diff --git a/app/src/main/java/com/pojavdx/dex/util/ByteInput.java b/app/src/main/java/com/pojavdx/dex/util/ByteInput.java deleted file mode 100644 index 003040986..000000000 --- a/app/src/main/java/com/pojavdx/dex/util/ByteInput.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.pojavdx.dex.util; - -/** - * A byte source. - */ -public interface ByteInput { - - /** - * Returns a byte. - * - * @throws IndexOutOfBoundsException if all bytes have been read. - */ - byte readByte(); -} diff --git a/app/src/main/java/com/pojavdx/dex/util/ByteOutput.java b/app/src/main/java/com/pojavdx/dex/util/ByteOutput.java deleted file mode 100644 index 45759e1d4..000000000 --- a/app/src/main/java/com/pojavdx/dex/util/ByteOutput.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.pojavdx.dex.util; - -/** - * A byte sink. - */ -public interface ByteOutput { - - /** - * Writes a byte. - * - * @throws IndexOutOfBoundsException if all bytes have been written. - */ - void writeByte(int i); -} diff --git a/app/src/main/java/com/pojavdx/dex/util/ExceptionWithContext.java b/app/src/main/java/com/pojavdx/dex/util/ExceptionWithContext.java deleted file mode 100644 index ed09b0679..000000000 --- a/app/src/main/java/com/pojavdx/dex/util/ExceptionWithContext.java +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.pojavdx.dex.util; - -import java.io.PrintStream; -import java.io.PrintWriter; - -/** - * Exception which carries around structured context. - */ -public class ExceptionWithContext extends RuntimeException { - /** {@code non-null;} human-oriented context of the exception */ - private StringBuffer context; - - /** - * Augments the given exception with the given context, and return the - * result. The result is either the given exception if it was an - * {@link ExceptionWithContext}, or a newly-constructed exception if it - * was not. - * - * @param ex {@code non-null;} the exception to augment - * @param str {@code non-null;} context to add - * @return {@code non-null;} an appropriate instance - */ - public static ExceptionWithContext withContext(Throwable ex, String str) { - ExceptionWithContext ewc; - - if (ex instanceof ExceptionWithContext) { - ewc = (ExceptionWithContext) ex; - } else { - ewc = new ExceptionWithContext(ex); - } - - ewc.addContext(str); - return ewc; - } - - /** - * Constructs an instance. - * - * @param message human-oriented message - */ - public ExceptionWithContext(String message) { - this(message, null); - } - - /** - * Constructs an instance. - * - * @param cause {@code null-ok;} exception that caused this one - */ - public ExceptionWithContext(Throwable cause) { - this(null, cause); - } - - /** - * Constructs an instance. - * - * @param message human-oriented message - * @param cause {@code null-ok;} exception that caused this one - */ - public ExceptionWithContext(String message, Throwable cause) { - super((message != null) ? message : - (cause != null) ? cause.getMessage() : null, - cause); - - if (cause instanceof ExceptionWithContext) { - String ctx = ((ExceptionWithContext) cause).context.toString(); - context = new StringBuffer(ctx.length() + 200); - context.append(ctx); - } else { - context = new StringBuffer(200); - } - } - - /** {@inheritDoc} */ - @Override - public void printStackTrace(PrintStream out) { - super.printStackTrace(out); - out.println(context); - } - - /** {@inheritDoc} */ - @Override - public void printStackTrace(PrintWriter out) { - super.printStackTrace(out); - out.println(context); - } - - /** - * Adds a line of context to this instance. - * - * @param str {@code non-null;} new context - */ - public void addContext(String str) { - if (str == null) { - throw new NullPointerException("str == null"); - } - - context.append(str); - if (!str.endsWith("\n")) { - context.append('\n'); - } - } - - /** - * Gets the context. - * - * @return {@code non-null;} the context - */ - public String getContext() { - return context.toString(); - } - - /** - * Prints the message and context. - * - * @param out {@code non-null;} where to print to - */ - public void printContext(PrintStream out) { - out.println(getMessage()); - out.print(context); - } - - /** - * Prints the message and context. - * - * @param out {@code non-null;} where to print to - */ - public void printContext(PrintWriter out) { - out.println(getMessage()); - out.print(context); - } -} diff --git a/app/src/main/java/com/pojavdx/dex/util/FileUtils.java b/app/src/main/java/com/pojavdx/dex/util/FileUtils.java deleted file mode 100644 index 59beb1f88..000000000 --- a/app/src/main/java/com/pojavdx/dex/util/FileUtils.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.pojavdx.dex.util; - -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; - -/** - * File I/O utilities. - */ -public final class FileUtils { - private FileUtils() { - } - - /** - * Reads the named file, translating {@link IOException} to a - * {@link RuntimeException} of some sort. - * - * @param fileName {@code non-null;} name of the file to read - * @return {@code non-null;} contents of the file - */ - public static byte[] readFile(String fileName) { - File file = new File(fileName); - return readFile(file); - } - - /** - * Reads the given file, translating {@link IOException} to a - * {@link RuntimeException} of some sort. - * - * @param file {@code non-null;} the file to read - * @return {@code non-null;} contents of the file - */ - public static byte[] readFile(File file) { - if (!file.exists()) { - throw new RuntimeException(file + ": file not found"); - } - - if (!file.isFile()) { - throw new RuntimeException(file + ": not a file"); - } - - if (!file.canRead()) { - throw new RuntimeException(file + ": file not readable"); - } - - long longLength = file.length(); - int length = (int) longLength; - if (length != longLength) { - throw new RuntimeException(file + ": file too long"); - } - - byte[] result = new byte[length]; - - try { - FileInputStream in = new FileInputStream(file); - int at = 0; - while (length > 0) { - int amt = in.read(result, at, length); - if (amt == -1) { - throw new RuntimeException(file + ": unexpected EOF"); - } - at += amt; - length -= amt; - } - in.close(); - } catch (IOException ex) { - throw new RuntimeException(file + ": trouble reading", ex); - } - - return result; - } - - /** - * Returns true if {@code fileName} names a .zip, .jar, or .apk. - */ - public static boolean hasArchiveSuffix(String fileName) { - return fileName.endsWith(".zip") - || fileName.endsWith(".jar") - || fileName.endsWith(".apk"); - } -} diff --git a/app/src/main/java/com/pojavdx/dex/util/Unsigned.java b/app/src/main/java/com/pojavdx/dex/util/Unsigned.java deleted file mode 100644 index f05f3d3a0..000000000 --- a/app/src/main/java/com/pojavdx/dex/util/Unsigned.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.pojavdx.dex.util; - -/** - * Unsigned arithmetic over Java's signed types. - */ -public final class Unsigned { - private Unsigned() {} - - public static int compare(short ushortA, short ushortB) { - if (ushortA == ushortB) { - return 0; - } - int a = ushortA & 0xFFFF; - int b = ushortB & 0xFFFF; - return a < b ? -1 : 1; - } - - public static int compare(int uintA, int uintB) { - if (uintA == uintB) { - return 0; - } - long a = uintA & 0xFFFFFFFFL; - long b = uintB & 0xFFFFFFFFL; - return a < b ? -1 : 1; - } -} diff --git a/app/src/main/java/com/pojavdx/dx/Version.java b/app/src/main/java/com/pojavdx/dx/Version.java deleted file mode 100644 index 7bba22f61..000000000 --- a/app/src/main/java/com/pojavdx/dx/Version.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.pojavdx.dx; - -/** - * Version number for dx. - */ -public class Version { - /** {@code non-null;} version string */ - public static final String VERSION = "1.16"; -} diff --git a/app/src/main/java/com/pojavdx/dx/cf/attrib/AttAnnotationDefault.java b/app/src/main/java/com/pojavdx/dx/cf/attrib/AttAnnotationDefault.java deleted file mode 100644 index fe447c6b8..000000000 --- a/app/src/main/java/com/pojavdx/dx/cf/attrib/AttAnnotationDefault.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.pojavdx.dx.cf.attrib; - -import com.pojavdx.dx.rop.cst.Constant; - -/** - * Attribute class for {@code AnnotationDefault} attributes. - */ -public final class AttAnnotationDefault extends BaseAttribute { - /** {@code non-null;} attribute name for attributes of this type */ - public static final String ATTRIBUTE_NAME = "AnnotationDefault"; - - /** {@code non-null;} the annotation default value */ - private final Constant value; - - /** {@code >= 0;} attribute data length in the original classfile (not - * including the attribute header) */ - private final int byteLength; - - /** - * Constructs an instance. - * - * @param value {@code non-null;} the annotation default value - * @param byteLength {@code >= 0;} attribute data length in the original - * classfile (not including the attribute header) - */ - public AttAnnotationDefault(Constant value, int byteLength) { - super(ATTRIBUTE_NAME); - - if (value == null) { - throw new NullPointerException("value == null"); - } - - this.value = value; - this.byteLength = byteLength; - } - - /** {@inheritDoc} */ - @Override - public int byteLength() { - // Add six for the standard attribute header. - return byteLength + 6; - } - - /** - * Gets the annotation default value. - * - * @return {@code non-null;} the value - */ - public Constant getValue() { - return value; - } -} diff --git a/app/src/main/java/com/pojavdx/dx/cf/attrib/AttBootstrapMethods.java b/app/src/main/java/com/pojavdx/dx/cf/attrib/AttBootstrapMethods.java deleted file mode 100644 index b281565ed..000000000 --- a/app/src/main/java/com/pojavdx/dx/cf/attrib/AttBootstrapMethods.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.pojavdx.dx.cf.attrib; - -import com.pojavdx.dx.cf.code.BootstrapMethodsList; - -/** - * Attribute class for standard {@code AttBootstrapMethods} attributes. - */ -public class AttBootstrapMethods extends BaseAttribute { - /** {@code non-null;} attribute name for attributes of this type */ - public static final String ATTRIBUTE_NAME = "BootstrapMethods"; - - private static final int ATTRIBUTE_HEADER_BYTES = 8; - private static final int BOOTSTRAP_METHOD_BYTES = 4; - private static final int BOOTSTRAP_ARGUMENT_BYTES = 2; - - private final BootstrapMethodsList bootstrapMethods; - - private final int byteLength; - - public AttBootstrapMethods(BootstrapMethodsList bootstrapMethods) { - super(ATTRIBUTE_NAME); - this.bootstrapMethods = bootstrapMethods; - - int bytes = ATTRIBUTE_HEADER_BYTES + bootstrapMethods.size() * BOOTSTRAP_METHOD_BYTES; - for (int i = 0; i < bootstrapMethods.size(); ++i) { - int numberOfArguments = bootstrapMethods.get(i).getBootstrapMethodArguments().size(); - bytes += numberOfArguments * BOOTSTRAP_ARGUMENT_BYTES; - } - this.byteLength = bytes; - } - - @Override - public int byteLength() { - return byteLength; - } - - /** - * Get the bootstrap methods present in attribute. - * @return bootstrap methods list - */ - public BootstrapMethodsList getBootstrapMethods() { - return bootstrapMethods; - } -} diff --git a/app/src/main/java/com/pojavdx/dx/cf/attrib/AttCode.java b/app/src/main/java/com/pojavdx/dx/cf/attrib/AttCode.java deleted file mode 100644 index d8a91355f..000000000 --- a/app/src/main/java/com/pojavdx/dx/cf/attrib/AttCode.java +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.pojavdx.dx.cf.attrib; - -import com.pojavdx.dx.cf.code.ByteCatchList; -import com.pojavdx.dx.cf.code.BytecodeArray; -import com.pojavdx.dx.cf.iface.AttributeList; -import com.pojavdx.dx.util.MutabilityException; - -/** - * Attribute class for standard {@code Code} attributes. - */ -public final class AttCode extends BaseAttribute { - /** {@code non-null;} attribute name for attributes of this type */ - public static final String ATTRIBUTE_NAME = "Code"; - - /** {@code >= 0;} the stack size */ - private final int maxStack; - - /** {@code >= 0;} the number of locals */ - private final int maxLocals; - - /** {@code non-null;} array containing the bytecode per se */ - private final BytecodeArray code; - - /** {@code non-null;} the exception table */ - private final ByteCatchList catches; - - /** {@code non-null;} the associated list of attributes */ - private final AttributeList attributes; - - /** - * Constructs an instance. - * - * @param maxStack {@code >= 0;} the stack size - * @param maxLocals {@code >= 0;} the number of locals - * @param code {@code non-null;} array containing the bytecode per se - * @param catches {@code non-null;} the exception table - * @param attributes {@code non-null;} the associated list of attributes - */ - public AttCode(int maxStack, int maxLocals, BytecodeArray code, - ByteCatchList catches, AttributeList attributes) { - super(ATTRIBUTE_NAME); - - if (maxStack < 0) { - throw new IllegalArgumentException("maxStack < 0"); - } - - if (maxLocals < 0) { - throw new IllegalArgumentException("maxLocals < 0"); - } - - if (code == null) { - throw new NullPointerException("code == null"); - } - - try { - if (catches.isMutable()) { - throw new MutabilityException("catches.isMutable()"); - } - } catch (NullPointerException ex) { - // Translate the exception. - throw new NullPointerException("catches == null"); - } - - try { - if (attributes.isMutable()) { - throw new MutabilityException("attributes.isMutable()"); - } - } catch (NullPointerException ex) { - // Translate the exception. - throw new NullPointerException("attributes == null"); - } - - this.maxStack = maxStack; - this.maxLocals = maxLocals; - this.code = code; - this.catches = catches; - this.attributes = attributes; - } - - @Override - public int byteLength() { - return 10 + code.byteLength() + catches.byteLength() + - attributes.byteLength(); - } - - /** - * Gets the maximum stack size. - * - * @return {@code >= 0;} the maximum stack size - */ - public int getMaxStack() { - return maxStack; - } - - /** - * Gets the number of locals. - * - * @return {@code >= 0;} the number of locals - */ - public int getMaxLocals() { - return maxLocals; - } - - /** - * Gets the bytecode array. - * - * @return {@code non-null;} the bytecode array - */ - public BytecodeArray getCode() { - return code; - } - - /** - * Gets the exception table. - * - * @return {@code non-null;} the exception table - */ - public ByteCatchList getCatches() { - return catches; - } - - /** - * Gets the associated attribute list. - * - * @return {@code non-null;} the attribute list - */ - public AttributeList getAttributes() { - return attributes; - } -} diff --git a/app/src/main/java/com/pojavdx/dx/cf/attrib/AttConstantValue.java b/app/src/main/java/com/pojavdx/dx/cf/attrib/AttConstantValue.java deleted file mode 100644 index 0fd68a552..000000000 --- a/app/src/main/java/com/pojavdx/dx/cf/attrib/AttConstantValue.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.pojavdx.dx.cf.attrib; - -import com.pojavdx.dx.rop.cst.CstDouble; -import com.pojavdx.dx.rop.cst.CstFloat; -import com.pojavdx.dx.rop.cst.CstInteger; -import com.pojavdx.dx.rop.cst.CstLong; -import com.pojavdx.dx.rop.cst.CstString; -import com.pojavdx.dx.rop.cst.TypedConstant; - -/** - * Attribute class for standard {@code ConstantValue} attributes. - */ -public final class AttConstantValue extends BaseAttribute { - /** {@code non-null;} attribute name for attributes of this type */ - public static final String ATTRIBUTE_NAME = "ConstantValue"; - - /** {@code non-null;} the constant value */ - private final TypedConstant constantValue; - - /** - * Constructs an instance. - * - * @param constantValue {@code non-null;} the constant value, which must - * be an instance of one of: {@code CstString}, - * {@code CstInteger}, {@code CstLong}, - * {@code CstFloat}, or {@code CstDouble} - */ - public AttConstantValue(TypedConstant constantValue) { - super(ATTRIBUTE_NAME); - - if (!((constantValue instanceof CstString) || - (constantValue instanceof CstInteger) || - (constantValue instanceof CstLong) || - (constantValue instanceof CstFloat) || - (constantValue instanceof CstDouble))) { - if (constantValue == null) { - throw new NullPointerException("constantValue == null"); - } - throw new IllegalArgumentException("bad type for constantValue"); - } - - this.constantValue = constantValue; - } - - /** {@inheritDoc} */ - @Override - public int byteLength() { - return 8; - } - - /** - * Gets the constant value of this instance. The returned value - * is an instance of one of: {@code CstString}, - * {@code CstInteger}, {@code CstLong}, - * {@code CstFloat}, or {@code CstDouble}. - * - * @return {@code non-null;} the constant value - */ - public TypedConstant getConstantValue() { - return constantValue; - } -} diff --git a/app/src/main/java/com/pojavdx/dx/cf/attrib/AttDeprecated.java b/app/src/main/java/com/pojavdx/dx/cf/attrib/AttDeprecated.java deleted file mode 100644 index 9233f61ad..000000000 --- a/app/src/main/java/com/pojavdx/dx/cf/attrib/AttDeprecated.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.pojavdx.dx.cf.attrib; - -/** - * Attribute class for standard {@code Deprecated} attributes. - */ -public final class AttDeprecated extends BaseAttribute { - /** {@code non-null;} attribute name for attributes of this type */ - public static final String ATTRIBUTE_NAME = "Deprecated"; - - /** - * Constructs an instance. - */ - public AttDeprecated() { - super(ATTRIBUTE_NAME); - } - - /** {@inheritDoc} */ - @Override - public int byteLength() { - return 6; - } -} diff --git a/app/src/main/java/com/pojavdx/dx/cf/attrib/AttEnclosingMethod.java b/app/src/main/java/com/pojavdx/dx/cf/attrib/AttEnclosingMethod.java deleted file mode 100644 index 3d3d3676d..000000000 --- a/app/src/main/java/com/pojavdx/dx/cf/attrib/AttEnclosingMethod.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.pojavdx.dx.cf.attrib; - -import com.pojavdx.dx.rop.cst.CstNat; -import com.pojavdx.dx.rop.cst.CstType; - -/** - * Attribute class for standards-track {@code EnclosingMethod} - * attributes. - */ -public final class AttEnclosingMethod extends BaseAttribute { - /** {@code non-null;} attribute name for attributes of this type */ - public static final String ATTRIBUTE_NAME = "EnclosingMethod"; - - /** {@code non-null;} the innermost enclosing class */ - private final CstType type; - - /** {@code null-ok;} the name-and-type of the innermost enclosing method, if any */ - private final CstNat method; - - /** - * Constructs an instance. - * - * @param type {@code non-null;} the innermost enclosing class - * @param method {@code null-ok;} the name-and-type of the innermost enclosing - * method, if any - */ - public AttEnclosingMethod(CstType type, CstNat method) { - super(ATTRIBUTE_NAME); - - if (type == null) { - throw new NullPointerException("type == null"); - } - - this.type = type; - this.method = method; - } - - /** {@inheritDoc} */ - @Override - public int byteLength() { - return 10; - } - - /** - * Gets the innermost enclosing class. - * - * @return {@code non-null;} the innermost enclosing class - */ - public CstType getEnclosingClass() { - return type; - } - - /** - * Gets the name-and-type of the innermost enclosing method, if - * any. - * - * @return {@code null-ok;} the name-and-type of the innermost enclosing - * method, if any - */ - public CstNat getMethod() { - return method; - } -} diff --git a/app/src/main/java/com/pojavdx/dx/cf/attrib/AttExceptions.java b/app/src/main/java/com/pojavdx/dx/cf/attrib/AttExceptions.java deleted file mode 100644 index e4544e918..000000000 --- a/app/src/main/java/com/pojavdx/dx/cf/attrib/AttExceptions.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.pojavdx.dx.cf.attrib; - -import com.pojavdx.dx.rop.type.TypeList; -import com.pojavdx.dx.util.MutabilityException; - -/** - * Attribute class for standard {@code Exceptions} attributes. - */ -public final class AttExceptions extends BaseAttribute { - /** {@code non-null;} attribute name for attributes of this type */ - public static final String ATTRIBUTE_NAME = "Exceptions"; - - /** {@code non-null;} list of exception classes */ - private final TypeList exceptions; - - /** - * Constructs an instance. - * - * @param exceptions {@code non-null;} list of classes, presumed but not - * verified to be subclasses of {@code Throwable} - */ - public AttExceptions(TypeList exceptions) { - super(ATTRIBUTE_NAME); - - try { - if (exceptions.isMutable()) { - throw new MutabilityException("exceptions.isMutable()"); - } - } catch (NullPointerException ex) { - // Translate the exception. - throw new NullPointerException("exceptions == null"); - } - - this.exceptions = exceptions; - } - - /** {@inheritDoc} */ - @Override - public int byteLength() { - return 8 + exceptions.size() * 2; - } - - /** - * Gets the list of classes associated with this instance. In - * general, these classes are not pre-verified to be subclasses of - * {@code Throwable}. - * - * @return {@code non-null;} the list of classes - */ - public TypeList getExceptions() { - return exceptions; - } -} diff --git a/app/src/main/java/com/pojavdx/dx/cf/attrib/AttInnerClasses.java b/app/src/main/java/com/pojavdx/dx/cf/attrib/AttInnerClasses.java deleted file mode 100644 index 07361e9cf..000000000 --- a/app/src/main/java/com/pojavdx/dx/cf/attrib/AttInnerClasses.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.pojavdx.dx.cf.attrib; - -import com.pojavdx.dx.util.MutabilityException; - -/** - * Attribute class for standard {@code InnerClasses} attributes. - */ -public final class AttInnerClasses extends BaseAttribute { - /** {@code non-null;} attribute name for attributes of this type */ - public static final String ATTRIBUTE_NAME = "InnerClasses"; - - /** {@code non-null;} list of inner class entries */ - private final InnerClassList innerClasses; - - /** - * Constructs an instance. - * - * @param innerClasses {@code non-null;} list of inner class entries - */ - public AttInnerClasses(InnerClassList innerClasses) { - super(ATTRIBUTE_NAME); - - try { - if (innerClasses.isMutable()) { - throw new MutabilityException("innerClasses.isMutable()"); - } - } catch (NullPointerException ex) { - // Translate the exception. - throw new NullPointerException("innerClasses == null"); - } - - this.innerClasses = innerClasses; - } - - /** {@inheritDoc} */ - @Override - public int byteLength() { - return 8 + innerClasses.size() * 8; - } - - /** - * Gets the list of "inner class" entries associated with this instance. - * - * @return {@code non-null;} the list - */ - public InnerClassList getInnerClasses() { - return innerClasses; - } -} diff --git a/app/src/main/java/com/pojavdx/dx/cf/attrib/AttLineNumberTable.java b/app/src/main/java/com/pojavdx/dx/cf/attrib/AttLineNumberTable.java deleted file mode 100644 index 7f4457bee..000000000 --- a/app/src/main/java/com/pojavdx/dx/cf/attrib/AttLineNumberTable.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.pojavdx.dx.cf.attrib; - -import com.pojavdx.dx.cf.code.LineNumberList; -import com.pojavdx.dx.util.MutabilityException; - -/** - * Attribute class for standard {@code LineNumberTable} attributes. - */ -public final class AttLineNumberTable extends BaseAttribute { - /** {@code non-null;} attribute name for attributes of this type */ - public static final String ATTRIBUTE_NAME = "LineNumberTable"; - - /** {@code non-null;} list of line number entries */ - private final LineNumberList lineNumbers; - - /** - * Constructs an instance. - * - * @param lineNumbers {@code non-null;} list of line number entries - */ - public AttLineNumberTable(LineNumberList lineNumbers) { - super(ATTRIBUTE_NAME); - - try { - if (lineNumbers.isMutable()) { - throw new MutabilityException("lineNumbers.isMutable()"); - } - } catch (NullPointerException ex) { - // Translate the exception. - throw new NullPointerException("lineNumbers == null"); - } - - this.lineNumbers = lineNumbers; - } - - /** {@inheritDoc} */ - @Override - public int byteLength() { - return 8 + 4 * lineNumbers.size(); - } - - /** - * Gets the list of "line number" entries associated with this instance. - * - * @return {@code non-null;} the list - */ - public LineNumberList getLineNumbers() { - return lineNumbers; - } -} diff --git a/app/src/main/java/com/pojavdx/dx/cf/attrib/AttLocalVariableTable.java b/app/src/main/java/com/pojavdx/dx/cf/attrib/AttLocalVariableTable.java deleted file mode 100644 index 183110aeb..000000000 --- a/app/src/main/java/com/pojavdx/dx/cf/attrib/AttLocalVariableTable.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.pojavdx.dx.cf.attrib; - -import com.pojavdx.dx.cf.code.LocalVariableList; - -/** - * Attribute class for standard {@code LocalVariableTable} attributes. - */ -public final class AttLocalVariableTable extends BaseLocalVariables { - /** {@code non-null;} attribute name for attributes of this type */ - public static final String ATTRIBUTE_NAME = "LocalVariableTable"; - - /** - * Constructs an instance. - * - * @param localVariables {@code non-null;} list of local variable entries - */ - public AttLocalVariableTable(LocalVariableList localVariables) { - super(ATTRIBUTE_NAME, localVariables); - } -} diff --git a/app/src/main/java/com/pojavdx/dx/cf/attrib/AttLocalVariableTypeTable.java b/app/src/main/java/com/pojavdx/dx/cf/attrib/AttLocalVariableTypeTable.java deleted file mode 100644 index 6358f3b92..000000000 --- a/app/src/main/java/com/pojavdx/dx/cf/attrib/AttLocalVariableTypeTable.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.pojavdx.dx.cf.attrib; - -import com.pojavdx.dx.cf.code.LocalVariableList; - -/** - * Attribute class for standard {@code LocalVariableTypeTable} attributes. - */ -public final class AttLocalVariableTypeTable extends BaseLocalVariables { - /** {@code non-null;} attribute name for attributes of this type */ - public static final String ATTRIBUTE_NAME = "LocalVariableTypeTable"; - - /** - * Constructs an instance. - * - * @param localVariables {@code non-null;} list of local variable entries - */ - public AttLocalVariableTypeTable(LocalVariableList localVariables) { - super(ATTRIBUTE_NAME, localVariables); - } -} diff --git a/app/src/main/java/com/pojavdx/dx/cf/attrib/AttRuntimeInvisibleAnnotations.java b/app/src/main/java/com/pojavdx/dx/cf/attrib/AttRuntimeInvisibleAnnotations.java deleted file mode 100644 index eb286bc30..000000000 --- a/app/src/main/java/com/pojavdx/dx/cf/attrib/AttRuntimeInvisibleAnnotations.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.pojavdx.dx.cf.attrib; - -import com.pojavdx.dx.rop.annotation.Annotations; - -/** - * Attribute class for standard {@code RuntimeInvisibleAnnotations} - * attributes. - */ -public final class AttRuntimeInvisibleAnnotations extends BaseAnnotations { - /** {@code non-null;} attribute name for attributes of this type */ - public static final String ATTRIBUTE_NAME = "RuntimeInvisibleAnnotations"; - - /** - * Constructs an instance. - * - * @param annotations {@code non-null;} the list of annotations - * @param byteLength {@code >= 0;} attribute data length in the original - * classfile (not including the attribute header) - */ - public AttRuntimeInvisibleAnnotations(Annotations annotations, - int byteLength) { - super(ATTRIBUTE_NAME, annotations, byteLength); - } -} diff --git a/app/src/main/java/com/pojavdx/dx/cf/attrib/AttRuntimeInvisibleParameterAnnotations.java b/app/src/main/java/com/pojavdx/dx/cf/attrib/AttRuntimeInvisibleParameterAnnotations.java deleted file mode 100644 index 8bb921920..000000000 --- a/app/src/main/java/com/pojavdx/dx/cf/attrib/AttRuntimeInvisibleParameterAnnotations.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.pojavdx.dx.cf.attrib; - -import com.pojavdx.dx.rop.annotation.AnnotationsList; - -/** - * Attribute class for standard - * {@code RuntimeInvisibleParameterAnnotations} attributes. - */ -public final class AttRuntimeInvisibleParameterAnnotations - extends BaseParameterAnnotations { - /** {@code non-null;} attribute name for attributes of this type */ - public static final String ATTRIBUTE_NAME = - "RuntimeInvisibleParameterAnnotations"; - - /** - * Constructs an instance. - * - * @param parameterAnnotations {@code non-null;} the parameter annotations - * @param byteLength {@code >= 0;} attribute data length in the original - * classfile (not including the attribute header) - */ - public AttRuntimeInvisibleParameterAnnotations( - AnnotationsList parameterAnnotations, int byteLength) { - super(ATTRIBUTE_NAME, parameterAnnotations, byteLength); - } -} diff --git a/app/src/main/java/com/pojavdx/dx/cf/attrib/AttRuntimeVisibleAnnotations.java b/app/src/main/java/com/pojavdx/dx/cf/attrib/AttRuntimeVisibleAnnotations.java deleted file mode 100644 index bac58f694..000000000 --- a/app/src/main/java/com/pojavdx/dx/cf/attrib/AttRuntimeVisibleAnnotations.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.pojavdx.dx.cf.attrib; - -import com.pojavdx.dx.rop.annotation.Annotations; - -/** - * Attribute class for standard {@code RuntimeVisibleAnnotations} - * attributes. - */ -public final class AttRuntimeVisibleAnnotations extends BaseAnnotations { - /** {@code non-null;} attribute name for attributes of this type */ - public static final String ATTRIBUTE_NAME = "RuntimeVisibleAnnotations"; - - /** - * Constructs an instance. - * - * @param annotations {@code non-null;} the list of annotations - * @param byteLength {@code >= 0;} attribute data length in the original - * classfile (not including the attribute header) - */ - public AttRuntimeVisibleAnnotations(Annotations annotations, - int byteLength) { - super(ATTRIBUTE_NAME, annotations, byteLength); - } -} diff --git a/app/src/main/java/com/pojavdx/dx/cf/attrib/AttRuntimeVisibleParameterAnnotations.java b/app/src/main/java/com/pojavdx/dx/cf/attrib/AttRuntimeVisibleParameterAnnotations.java deleted file mode 100644 index b372d2395..000000000 --- a/app/src/main/java/com/pojavdx/dx/cf/attrib/AttRuntimeVisibleParameterAnnotations.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.pojavdx.dx.cf.attrib; - -import com.pojavdx.dx.rop.annotation.AnnotationsList; - -/** - * Attribute class for standard {@code RuntimeVisibleParameterAnnotations} - * attributes. - */ -public final class AttRuntimeVisibleParameterAnnotations - extends BaseParameterAnnotations { - /** {@code non-null;} attribute name for attributes of this type */ - public static final String ATTRIBUTE_NAME = - "RuntimeVisibleParameterAnnotations"; - - /** - * Constructs an instance. - * - * @param annotations {@code non-null;} the parameter annotations - * @param byteLength {@code >= 0;} attribute data length in the original - * classfile (not including the attribute header) - */ - public AttRuntimeVisibleParameterAnnotations( - AnnotationsList annotations, int byteLength) { - super(ATTRIBUTE_NAME, annotations, byteLength); - } -} diff --git a/app/src/main/java/com/pojavdx/dx/cf/attrib/AttSignature.java b/app/src/main/java/com/pojavdx/dx/cf/attrib/AttSignature.java deleted file mode 100644 index 91f9f025c..000000000 --- a/app/src/main/java/com/pojavdx/dx/cf/attrib/AttSignature.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.pojavdx.dx.cf.attrib; - -import com.pojavdx.dx.rop.cst.CstString; - -/** - * Attribute class for standards-track {@code Signature} attributes. - */ -public final class AttSignature extends BaseAttribute { - /** {@code non-null;} attribute name for attributes of this type */ - public static final String ATTRIBUTE_NAME = "Signature"; - - /** {@code non-null;} the signature string */ - private final CstString signature; - - /** - * Constructs an instance. - * - * @param signature {@code non-null;} the signature string - */ - public AttSignature(CstString signature) { - super(ATTRIBUTE_NAME); - - if (signature == null) { - throw new NullPointerException("signature == null"); - } - - this.signature = signature; - } - - /** {@inheritDoc} */ - @Override - public int byteLength() { - return 8; - } - - /** - * Gets the signature string. - * - * @return {@code non-null;} the signature string - */ - public CstString getSignature() { - return signature; - } -} diff --git a/app/src/main/java/com/pojavdx/dx/cf/attrib/AttSourceDebugExtension.java b/app/src/main/java/com/pojavdx/dx/cf/attrib/AttSourceDebugExtension.java deleted file mode 100644 index 0f9f2e120..000000000 --- a/app/src/main/java/com/pojavdx/dx/cf/attrib/AttSourceDebugExtension.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.pojavdx.dx.cf.attrib; - -import com.pojavdx.dx.rop.cst.CstString; - -/** - * Attribute class for standard {@code SourceDebugExtension} attributes. - */ -public final class AttSourceDebugExtension extends BaseAttribute { - /** {@code non-null;} attribute name for attributes of this type */ - public static final String ATTRIBUTE_NAME = "SourceDebugExtension"; - - /** {@code non-null;} Contents of SMAP */ - private final CstString smapString; - - /** - * Constructs an instance. - * - * @param smapString {@code non-null;} the SMAP data from the class file. - */ - public AttSourceDebugExtension(CstString smapString) { - super(ATTRIBUTE_NAME); - - if (smapString == null) { - throw new NullPointerException("smapString == null"); - } - - this.smapString = smapString; - } - - /** {@inheritDoc} */ - @Override - public int byteLength() { - // Add 6 for the standard attribute header: the attribute name - // index (2 bytes) and the attribute length (4 bytes). - return 6 + smapString.getUtf8Size(); - } - - /** - * Gets the SMAP data of this instance. - * - * @return {@code non-null;} the SMAP data. - */ - public CstString getSmapString() { - return smapString; - } -} diff --git a/app/src/main/java/com/pojavdx/dx/cf/attrib/AttSourceFile.java b/app/src/main/java/com/pojavdx/dx/cf/attrib/AttSourceFile.java deleted file mode 100644 index ebcb85bd5..000000000 --- a/app/src/main/java/com/pojavdx/dx/cf/attrib/AttSourceFile.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.pojavdx.dx.cf.attrib; - -import com.pojavdx.dx.rop.cst.CstString; - -/** - * Attribute class for standard {@code SourceFile} attributes. - */ -public final class AttSourceFile extends BaseAttribute { - /** {@code non-null;} attribute name for attributes of this type */ - public static final String ATTRIBUTE_NAME = "SourceFile"; - - /** {@code non-null;} name of the source file */ - private final CstString sourceFile; - - /** - * Constructs an instance. - * - * @param sourceFile {@code non-null;} the name of the source file - */ - public AttSourceFile(CstString sourceFile) { - super(ATTRIBUTE_NAME); - - if (sourceFile == null) { - throw new NullPointerException("sourceFile == null"); - } - - this.sourceFile = sourceFile; - } - - /** {@inheritDoc} */ - @Override - public int byteLength() { - return 8; - } - - /** - * Gets the source file name of this instance. - * - * @return {@code non-null;} the source file - */ - public CstString getSourceFile() { - return sourceFile; - } -} diff --git a/app/src/main/java/com/pojavdx/dx/cf/attrib/AttSynthetic.java b/app/src/main/java/com/pojavdx/dx/cf/attrib/AttSynthetic.java deleted file mode 100644 index 15ffceb43..000000000 --- a/app/src/main/java/com/pojavdx/dx/cf/attrib/AttSynthetic.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.pojavdx.dx.cf.attrib; - -/** - * Attribute class for standard {@code Synthetic} attributes. - */ -public final class AttSynthetic extends BaseAttribute { - /** {@code non-null;} attribute name for attributes of this type */ - public static final String ATTRIBUTE_NAME = "Synthetic"; - - /** - * Constructs an instance. - */ - public AttSynthetic() { - super(ATTRIBUTE_NAME); - } - - /** {@inheritDoc} */ - @Override - public int byteLength() { - return 6; - } -} diff --git a/app/src/main/java/com/pojavdx/dx/cf/attrib/BaseAnnotations.java b/app/src/main/java/com/pojavdx/dx/cf/attrib/BaseAnnotations.java deleted file mode 100644 index 2c29edf04..000000000 --- a/app/src/main/java/com/pojavdx/dx/cf/attrib/BaseAnnotations.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.pojavdx.dx.cf.attrib; - -import com.pojavdx.dx.rop.annotation.Annotations; -import com.pojavdx.dx.util.MutabilityException; - -/** - * Base class for annotations attributes. - */ -public abstract class BaseAnnotations extends BaseAttribute { - /** {@code non-null;} list of annotations */ - private final Annotations annotations; - - /** {@code >= 0;} attribute data length in the original classfile (not - * including the attribute header) */ - private final int byteLength; - - /** - * Constructs an instance. - * - * @param attributeName {@code non-null;} the name of the attribute - * @param annotations {@code non-null;} the list of annotations - * @param byteLength {@code >= 0;} attribute data length in the original - * classfile (not including the attribute header) - */ - public BaseAnnotations(String attributeName, Annotations annotations, - int byteLength) { - super(attributeName); - - try { - if (annotations.isMutable()) { - throw new MutabilityException("annotations.isMutable()"); - } - } catch (NullPointerException ex) { - // Translate the exception. - throw new NullPointerException("annotations == null"); - } - - this.annotations = annotations; - this.byteLength = byteLength; - } - - /** {@inheritDoc} */ - @Override - public final int byteLength() { - // Add six for the standard attribute header. - return byteLength + 6; - } - - /** - * Gets the list of annotations associated with this instance. - * - * @return {@code non-null;} the list - */ - public final Annotations getAnnotations() { - return annotations; - } -} diff --git a/app/src/main/java/com/pojavdx/dx/cf/attrib/BaseAttribute.java b/app/src/main/java/com/pojavdx/dx/cf/attrib/BaseAttribute.java deleted file mode 100644 index baf8f31bd..000000000 --- a/app/src/main/java/com/pojavdx/dx/cf/attrib/BaseAttribute.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.pojavdx.dx.cf.attrib; - -import com.pojavdx.dx.cf.iface.Attribute; - -/** - * Base implementation of {@link Attribute}, which directly stores - * the attribute name but leaves the rest up to subclasses. - */ -public abstract class BaseAttribute implements Attribute { - /** {@code non-null;} attribute name */ - private final String name; - - /** - * Constructs an instance. - * - * @param name {@code non-null;} attribute name - */ - public BaseAttribute(String name) { - if (name == null) { - throw new NullPointerException("name == null"); - } - - this.name = name; - } - - /** {@inheritDoc} */ - @Override - public String getName() { - return name; - } -} diff --git a/app/src/main/java/com/pojavdx/dx/cf/attrib/BaseLocalVariables.java b/app/src/main/java/com/pojavdx/dx/cf/attrib/BaseLocalVariables.java deleted file mode 100644 index f7a6d160a..000000000 --- a/app/src/main/java/com/pojavdx/dx/cf/attrib/BaseLocalVariables.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.pojavdx.dx.cf.attrib; - -import com.pojavdx.dx.cf.code.LocalVariableList; -import com.pojavdx.dx.util.MutabilityException; - -/** - * Base attribute class for standard {@code LocalVariableTable} - * and {@code LocalVariableTypeTable} attributes. - */ -public abstract class BaseLocalVariables extends BaseAttribute { - /** {@code non-null;} list of local variable entries */ - private final LocalVariableList localVariables; - - /** - * Constructs an instance. - * - * @param name {@code non-null;} attribute name - * @param localVariables {@code non-null;} list of local variable entries - */ - public BaseLocalVariables(String name, - LocalVariableList localVariables) { - super(name); - - try { - if (localVariables.isMutable()) { - throw new MutabilityException("localVariables.isMutable()"); - } - } catch (NullPointerException ex) { - // Translate the exception. - throw new NullPointerException("localVariables == null"); - } - - this.localVariables = localVariables; - } - - /** {@inheritDoc} */ - @Override - public final int byteLength() { - return 8 + localVariables.size() * 10; - } - - /** - * Gets the list of "local variable" entries associated with this instance. - * - * @return {@code non-null;} the list - */ - public final LocalVariableList getLocalVariables() { - return localVariables; - } -} diff --git a/app/src/main/java/com/pojavdx/dx/cf/attrib/BaseParameterAnnotations.java b/app/src/main/java/com/pojavdx/dx/cf/attrib/BaseParameterAnnotations.java deleted file mode 100644 index 4f877b6b0..000000000 --- a/app/src/main/java/com/pojavdx/dx/cf/attrib/BaseParameterAnnotations.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.pojavdx.dx.cf.attrib; - -import com.pojavdx.dx.rop.annotation.AnnotationsList; -import com.pojavdx.dx.util.MutabilityException; - -/** - * Base class for parameter annotation list attributes. - */ -public abstract class BaseParameterAnnotations extends BaseAttribute { - /** {@code non-null;} list of annotations */ - private final AnnotationsList parameterAnnotations; - - /** {@code >= 0;} attribute data length in the original classfile (not - * including the attribute header) */ - private final int byteLength; - - /** - * Constructs an instance. - * - * @param attributeName {@code non-null;} the name of the attribute - * @param parameterAnnotations {@code non-null;} the annotations - * @param byteLength {@code >= 0;} attribute data length in the original - * classfile (not including the attribute header) - */ - public BaseParameterAnnotations(String attributeName, - AnnotationsList parameterAnnotations, int byteLength) { - super(attributeName); - - try { - if (parameterAnnotations.isMutable()) { - throw new MutabilityException( - "parameterAnnotations.isMutable()"); - } - } catch (NullPointerException ex) { - // Translate the exception. - throw new NullPointerException("parameterAnnotations == null"); - } - - this.parameterAnnotations = parameterAnnotations; - this.byteLength = byteLength; - } - - /** {@inheritDoc} */ - @Override - public final int byteLength() { - // Add six for the standard attribute header. - return byteLength + 6; - } - - /** - * Gets the list of annotation lists associated with this instance. - * - * @return {@code non-null;} the list - */ - public final AnnotationsList getParameterAnnotations() { - return parameterAnnotations; - } -} diff --git a/app/src/main/java/com/pojavdx/dx/cf/attrib/InnerClassList.java b/app/src/main/java/com/pojavdx/dx/cf/attrib/InnerClassList.java deleted file mode 100644 index 965c27d54..000000000 --- a/app/src/main/java/com/pojavdx/dx/cf/attrib/InnerClassList.java +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.pojavdx.dx.cf.attrib; - -import com.pojavdx.dx.rop.cst.CstString; -import com.pojavdx.dx.rop.cst.CstType; -import com.pojavdx.dx.util.FixedSizeList; - -/** - * List of "inner class" entries, which are the contents of - * {@code InnerClasses} attributes. - */ -public final class InnerClassList extends FixedSizeList { - /** - * Constructs an instance. - * - * @param count the number of elements to be in the list of inner classes - */ - public InnerClassList(int count) { - super(count); - } - - /** - * Gets the indicated item. - * - * @param n {@code >= 0;} which item - * @return {@code null-ok;} the indicated item - */ - public Item get(int n) { - return (Item) get0(n); - } - - /** - * Sets the item at the given index. - * - * @param n {@code >= 0, < size();} which class - * @param innerClass {@code non-null;} class this item refers to - * @param outerClass {@code null-ok;} outer class that this class is a - * member of, if any - * @param innerName {@code null-ok;} original simple name of this class, - * if not anonymous - * @param accessFlags original declared access flags - */ - public void set(int n, CstType innerClass, CstType outerClass, - CstString innerName, int accessFlags) { - set0(n, new Item(innerClass, outerClass, innerName, accessFlags)); - } - - /** - * Item in an inner classes list. - */ - public static class Item { - /** {@code non-null;} class this item refers to */ - private final CstType innerClass; - - /** {@code null-ok;} outer class that this class is a member of, if any */ - private final CstType outerClass; - - /** {@code null-ok;} original simple name of this class, if not anonymous */ - private final CstString innerName; - - /** original declared access flags */ - private final int accessFlags; - - /** - * Constructs an instance. - * - * @param innerClass {@code non-null;} class this item refers to - * @param outerClass {@code null-ok;} outer class that this class is a - * member of, if any - * @param innerName {@code null-ok;} original simple name of this - * class, if not anonymous - * @param accessFlags original declared access flags - */ - public Item(CstType innerClass, CstType outerClass, - CstString innerName, int accessFlags) { - if (innerClass == null) { - throw new NullPointerException("innerClass == null"); - } - - this.innerClass = innerClass; - this.outerClass = outerClass; - this.innerName = innerName; - this.accessFlags = accessFlags; - } - - /** - * Gets the class this item refers to. - * - * @return {@code non-null;} the class - */ - public CstType getInnerClass() { - return innerClass; - } - - /** - * Gets the outer class that this item's class is a member of, if any. - * - * @return {@code null-ok;} the class - */ - public CstType getOuterClass() { - return outerClass; - } - - /** - * Gets the original name of this item's class, if not anonymous. - * - * @return {@code null-ok;} the name - */ - public CstString getInnerName() { - return innerName; - } - - /** - * Gets the original declared access flags. - * - * @return the access flags - */ - public int getAccessFlags() { - return accessFlags; - } - } -} diff --git a/app/src/main/java/com/pojavdx/dx/cf/attrib/RawAttribute.java b/app/src/main/java/com/pojavdx/dx/cf/attrib/RawAttribute.java deleted file mode 100644 index 90d622da4..000000000 --- a/app/src/main/java/com/pojavdx/dx/cf/attrib/RawAttribute.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.pojavdx.dx.cf.attrib; - -import com.pojavdx.dx.rop.cst.ConstantPool; -import com.pojavdx.dx.util.ByteArray; - -/** - * Raw attribute, for holding onto attributes that are unrecognized. - */ -public final class RawAttribute extends BaseAttribute { - /** {@code non-null;} attribute data */ - private final ByteArray data; - - /** - * {@code null-ok;} constant pool to use for resolution of cpis in {@link - * #data} - */ - private final ConstantPool pool; - - /** - * Constructs an instance. - * - * @param name {@code non-null;} attribute name - * @param data {@code non-null;} attribute data - * @param pool {@code null-ok;} constant pool to use for cpi resolution - */ - public RawAttribute(String name, ByteArray data, ConstantPool pool) { - super(name); - - if (data == null) { - throw new NullPointerException("data == null"); - } - - this.data = data; - this.pool = pool; - } - - /** - * Constructs an instance from a sub-array of a {@link ByteArray}. - * - * @param name {@code non-null;} attribute name - * @param data {@code non-null;} array containing the attribute data - * @param offset offset in {@code data} to the attribute data - * @param length length of the attribute data, in bytes - * @param pool {@code null-ok;} constant pool to use for cpi resolution - */ - public RawAttribute(String name, ByteArray data, int offset, - int length, ConstantPool pool) { - this(name, data.slice(offset, offset + length), pool); - } - - /** - * Get the raw data of the attribute. - * - * @return {@code non-null;} the data - */ - public ByteArray getData() { - return data; - } - - /** {@inheritDoc} */ - @Override - public int byteLength() { - return data.size() + 6; - } - - /** - * Gets the constant pool to use for cpi resolution, if any. It - * presumably came from the class file that this attribute came - * from. - * - * @return {@code null-ok;} the constant pool - */ - public ConstantPool getPool() { - return pool; - } -} diff --git a/app/src/main/java/com/pojavdx/dx/cf/attrib/package.html b/app/src/main/java/com/pojavdx/dx/cf/attrib/package.html deleted file mode 100644 index ac8a3d08b..000000000 --- a/app/src/main/java/com/pojavdx/dx/cf/attrib/package.html +++ /dev/null @@ -1,11 +0,0 @@ - -

Implementation of containers and utilities for all the standard Java -attribute types.

- -

PACKAGES USED: -

    -
  • com.pojavdx.dx.cf.iface
  • -
  • com.pojavdx.dx.rop.pool
  • -
  • com.pojavdx.dx.util
  • -
- diff --git a/app/src/main/java/com/pojavdx/dx/cf/code/BaseMachine.java b/app/src/main/java/com/pojavdx/dx/cf/code/BaseMachine.java deleted file mode 100644 index bac11cf9d..000000000 --- a/app/src/main/java/com/pojavdx/dx/cf/code/BaseMachine.java +++ /dev/null @@ -1,595 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.pojavdx.dx.cf.code; - -import com.pojavdx.dx.rop.code.LocalItem; -import com.pojavdx.dx.rop.code.RegisterSpec; -import com.pojavdx.dx.rop.cst.Constant; -import com.pojavdx.dx.rop.type.Prototype; -import com.pojavdx.dx.rop.type.StdTypeList; -import com.pojavdx.dx.rop.type.Type; -import com.pojavdx.dx.rop.type.TypeBearer; -import java.util.ArrayList; - -/** - * Base implementation of {@link Machine}. - * - *

Note: For the most part, the documentation for this class - * ignores the distinction between {@link Type} and {@link - * TypeBearer}.

- */ -public abstract class BaseMachine implements Machine { - /* {@code non-null;} the prototype for the associated method */ - private final Prototype prototype; - - /** {@code non-null;} primary arguments */ - private TypeBearer[] args; - - /** {@code >= 0;} number of primary arguments */ - private int argCount; - - /** {@code null-ok;} type of the operation, if salient */ - private Type auxType; - - /** auxiliary {@code int} argument */ - private int auxInt; - - /** {@code null-ok;} auxiliary constant argument */ - private Constant auxCst; - - /** auxiliary branch target argument */ - private int auxTarget; - - /** {@code null-ok;} auxiliary switch cases argument */ - private SwitchList auxCases; - - /** {@code null-ok;} auxiliary initial value list for newarray */ - private ArrayList auxInitValues; - - /** {@code >= -1;} last local accessed */ - private int localIndex; - - /** specifies if local has info in the local variable table */ - private boolean localInfo; - - /** {@code null-ok;} local target spec, if salient and calculated */ - private RegisterSpec localTarget; - - /** {@code non-null;} results */ - private TypeBearer[] results; - - /** - * {@code >= -1;} count of the results, or {@code -1} if no results - * have been set - */ - private int resultCount; - - /** - * Constructs an instance. - * - * @param prototype {@code non-null;} the prototype for the - * associated method - */ - public BaseMachine(Prototype prototype) { - if (prototype == null) { - throw new NullPointerException("prototype == null"); - } - - this.prototype = prototype; - args = new TypeBearer[10]; - results = new TypeBearer[6]; - clearArgs(); - } - - /** {@inheritDoc} */ - @Override - public Prototype getPrototype() { - return prototype; - } - - /** {@inheritDoc} */ - @Override - public final void clearArgs() { - argCount = 0; - auxType = null; - auxInt = 0; - auxCst = null; - auxTarget = 0; - auxCases = null; - auxInitValues = null; - localIndex = -1; - localInfo = false; - localTarget = null; - resultCount = -1; - } - - /** {@inheritDoc} */ - @Override - public final void popArgs(Frame frame, int count) { - ExecutionStack stack = frame.getStack(); - - clearArgs(); - - if (count > args.length) { - // Grow args, and add a little extra room to grow even more. - args = new TypeBearer[count + 10]; - } - - for (int i = count - 1; i >= 0; i--) { - args[i] = stack.pop(); - } - - argCount = count; - } - - /** {@inheritDoc} */ - @Override - public void popArgs(Frame frame, Prototype prototype) { - StdTypeList types = prototype.getParameterTypes(); - int size = types.size(); - - // Use the above method to do the actual popping... - popArgs(frame, size); - - // ...and then verify the popped types. - - for (int i = 0; i < size; i++) { - if (! Merger.isPossiblyAssignableFrom(types.getType(i), args[i])) { - throw new SimException("at stack depth " + (size - 1 - i) + - ", expected type " + types.getType(i).toHuman() + - " but found " + args[i].getType().toHuman()); - } - } - } - - @Override - public final void popArgs(Frame frame, Type type) { - // Use the above method to do the actual popping... - popArgs(frame, 1); - - // ...and then verify the popped type. - if (! Merger.isPossiblyAssignableFrom(type, args[0])) { - throw new SimException("expected type " + type.toHuman() + - " but found " + args[0].getType().toHuman()); - } - } - - /** {@inheritDoc} */ - @Override - public final void popArgs(Frame frame, Type type1, Type type2) { - // Use the above method to do the actual popping... - popArgs(frame, 2); - - // ...and then verify the popped types. - - if (! Merger.isPossiblyAssignableFrom(type1, args[0])) { - throw new SimException("expected type " + type1.toHuman() + - " but found " + args[0].getType().toHuman()); - } - - if (! Merger.isPossiblyAssignableFrom(type2, args[1])) { - throw new SimException("expected type " + type2.toHuman() + - " but found " + args[1].getType().toHuman()); - } - } - - /** {@inheritDoc} */ - @Override - public final void popArgs(Frame frame, Type type1, Type type2, - Type type3) { - // Use the above method to do the actual popping... - popArgs(frame, 3); - - // ...and then verify the popped types. - - if (! Merger.isPossiblyAssignableFrom(type1, args[0])) { - throw new SimException("expected type " + type1.toHuman() + - " but found " + args[0].getType().toHuman()); - } - - if (! Merger.isPossiblyAssignableFrom(type2, args[1])) { - throw new SimException("expected type " + type2.toHuman() + - " but found " + args[1].getType().toHuman()); - } - - if (! Merger.isPossiblyAssignableFrom(type3, args[2])) { - throw new SimException("expected type " + type3.toHuman() + - " but found " + args[2].getType().toHuman()); - } - } - - /** {@inheritDoc} */ - @Override - public final void localArg(Frame frame, int idx) { - clearArgs(); - args[0] = frame.getLocals().get(idx); - argCount = 1; - localIndex = idx; - } - - /** {@inheritDoc} */ - @Override - public final void localInfo(boolean local) { - localInfo = local; - } - - /** {@inheritDoc} */ - @Override - public final void auxType(Type type) { - auxType = type; - } - - /** {@inheritDoc} */ - @Override - public final void auxIntArg(int value) { - auxInt = value; - } - - /** {@inheritDoc} */ - @Override - public final void auxCstArg(Constant cst) { - if (cst == null) { - throw new NullPointerException("cst == null"); - } - - auxCst = cst; - } - - /** {@inheritDoc} */ - @Override - public final void auxTargetArg(int target) { - auxTarget = target; - } - - /** {@inheritDoc} */ - @Override - public final void auxSwitchArg(SwitchList cases) { - if (cases == null) { - throw new NullPointerException("cases == null"); - } - - auxCases = cases; - } - - /** {@inheritDoc} */ - @Override - public final void auxInitValues(ArrayList initValues) { - auxInitValues = initValues; - } - - /** {@inheritDoc} */ - @Override - public final void localTarget(int idx, Type type, LocalItem local) { - localTarget = RegisterSpec.makeLocalOptional(idx, type, local); - } - - /** - * Gets the number of primary arguments. - * - * @return {@code >= 0;} the number of primary arguments - */ - protected final int argCount() { - return argCount; - } - - /** - * Gets the width of the arguments (where a category-2 value counts as - * two). - * - * @return {@code >= 0;} the argument width - */ - protected final int argWidth() { - int result = 0; - - for (int i = 0; i < argCount; i++) { - result += args[i].getType().getCategory(); - } - - return result; - } - - /** - * Gets the {@code n}th primary argument. - * - * @param n {@code >= 0, < argCount();} which argument - * @return {@code non-null;} the indicated argument - */ - protected final TypeBearer arg(int n) { - if (n >= argCount) { - throw new IllegalArgumentException("n >= argCount"); - } - - try { - return args[n]; - } catch (ArrayIndexOutOfBoundsException ex) { - // Translate the exception. - throw new IllegalArgumentException("n < 0"); - } - } - - /** - * Gets the type auxiliary argument. - * - * @return {@code null-ok;} the salient type - */ - protected final Type getAuxType() { - return auxType; - } - - /** - * Gets the {@code int} auxiliary argument. - * - * @return the argument value - */ - protected final int getAuxInt() { - return auxInt; - } - - /** - * Gets the constant auxiliary argument. - * - * @return {@code null-ok;} the argument value - */ - protected final Constant getAuxCst() { - return auxCst; - } - - /** - * Gets the branch target auxiliary argument. - * - * @return the argument value - */ - protected final int getAuxTarget() { - return auxTarget; - } - - /** - * Gets the switch cases auxiliary argument. - * - * @return {@code null-ok;} the argument value - */ - protected final SwitchList getAuxCases() { - return auxCases; - } - - /** - * Gets the init values auxiliary argument. - * - * @return {@code null-ok;} the argument value - */ - protected final ArrayList getInitValues() { - return auxInitValues; - } - /** - * Gets the last local index accessed. - * - * @return {@code >= -1;} the salient local index or {@code -1} if none - * was set since the last time {@link #clearArgs} was called - */ - protected final int getLocalIndex() { - return localIndex; - } - - /** - * Gets whether the loaded local has info in the local variable table. - * - * @return {@code true} if local arg has info in the local variable table - */ - protected final boolean getLocalInfo() { - return localInfo; - } - - /** - * Gets the target local register spec of the current operation, if any. - * The local target spec is the combination of the values indicated - * by a previous call to {@link #localTarget} with the type of what - * should be the sole result set by a call to {@link #setResult} (or - * the combination {@link #clearResult} then {@link #addResult}. - * - * @param isMove {@code true} if the operation being performed on the - * local is a move. This will cause constant values to be propagated - * to the returned local - * @return {@code null-ok;} the salient register spec or {@code null} if no - * local target was set since the last time {@link #clearArgs} was - * called - */ - protected final RegisterSpec getLocalTarget(boolean isMove) { - if (localTarget == null) { - return null; - } - - if (resultCount != 1) { - throw new SimException("local target with " + - ((resultCount == 0) ? "no" : "multiple") + " results"); - } - - TypeBearer result = results[0]; - Type resultType = result.getType(); - Type localType = localTarget.getType(); - - if (resultType == localType) { - /* - * If this is to be a move operation and the result is a - * known value, make the returned localTarget embody that - * value. - */ - if (isMove) { - return localTarget.withType(result); - } else { - return localTarget; - } - } - - if (! Merger.isPossiblyAssignableFrom(localType, resultType)) { - // The result and local types are inconsistent. Complain! - throwLocalMismatch(resultType, localType); - return null; - } - - if (localType == Type.OBJECT) { - /* - * The result type is more specific than the local type, - * so use that instead. - */ - localTarget = localTarget.withType(result); - } - - return localTarget; - } - - /** - * Clears the results. - */ - protected final void clearResult() { - resultCount = 0; - } - - /** - * Sets the results list to be the given single value. - * - *

Note: If there is more than one result value, the - * others may be added by using {@link #addResult}.

- * - * @param result {@code non-null;} result value - */ - protected final void setResult(TypeBearer result) { - if (result == null) { - throw new NullPointerException("result == null"); - } - - results[0] = result; - resultCount = 1; - } - - /** - * Adds an additional element to the list of results. - * - * @see #setResult - * - * @param result {@code non-null;} result value - */ - protected final void addResult(TypeBearer result) { - if (result == null) { - throw new NullPointerException("result == null"); - } - - results[resultCount] = result; - resultCount++; - } - - /** - * Gets the count of results. This throws an exception if results were - * never set. (Explicitly clearing the results counts as setting them.) - * - * @return {@code >= 0;} the count - */ - protected final int resultCount() { - if (resultCount < 0) { - throw new SimException("results never set"); - } - - return resultCount; - } - - /** - * Gets the width of the results (where a category-2 value counts as - * two). - * - * @return {@code >= 0;} the result width - */ - protected final int resultWidth() { - int width = 0; - - for (int i = 0; i < resultCount; i++) { - width += results[i].getType().getCategory(); - } - - return width; - } - - /** - * Gets the {@code n}th result value. - * - * @param n {@code >= 0, < resultCount();} which result - * @return {@code non-null;} the indicated result value - */ - protected final TypeBearer result(int n) { - if (n >= resultCount) { - throw new IllegalArgumentException("n >= resultCount"); - } - - try { - return results[n]; - } catch (ArrayIndexOutOfBoundsException ex) { - // Translate the exception. - throw new IllegalArgumentException("n < 0"); - } - } - - /** - * Stores the results of the latest operation into the given frame. If - * there is a local target (see {@link #localTarget}), then the sole - * result is stored to that target; otherwise any results are pushed - * onto the stack. - * - * @param frame {@code non-null;} frame to operate on - */ - protected final void storeResults(Frame frame) { - if (resultCount < 0) { - throw new SimException("results never set"); - } - - if (resultCount == 0) { - // Nothing to do. - return; - } - - if (localTarget != null) { - /* - * Note: getLocalTarget() doesn't necessarily return - * localTarget directly. - */ - frame.getLocals().set(getLocalTarget(false)); - } else { - ExecutionStack stack = frame.getStack(); - for (int i = 0; i < resultCount; i++) { - if (localInfo) { - stack.setLocal(); - } - stack.push(results[i]); - } - } - } - - /** - * Throws an exception that indicates a mismatch in local variable - * types. - * - * @param found {@code non-null;} the encountered type - * @param local {@code non-null;} the local variable's claimed type - */ - public static void throwLocalMismatch(TypeBearer found, - TypeBearer local) { - throw new SimException("local variable type mismatch: " + - "attempt to set or access a value of type " + - found.toHuman() + - " using a local variable of type " + - local.toHuman() + - ". This is symptomatic of .class transformation tools " + - "that ignore local variable information."); - } -} diff --git a/app/src/main/java/com/pojavdx/dx/cf/code/BasicBlocker.java b/app/src/main/java/com/pojavdx/dx/cf/code/BasicBlocker.java deleted file mode 100644 index 9ed090b65..000000000 --- a/app/src/main/java/com/pojavdx/dx/cf/code/BasicBlocker.java +++ /dev/null @@ -1,465 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.pojavdx.dx.cf.code; - -import com.pojavdx.dx.rop.cst.Constant; -import com.pojavdx.dx.rop.cst.CstInvokeDynamic; -import com.pojavdx.dx.rop.cst.CstMemberRef; -import com.pojavdx.dx.rop.cst.CstMethodHandle; -import com.pojavdx.dx.rop.cst.CstProtoRef; -import com.pojavdx.dx.rop.cst.CstString; -import com.pojavdx.dx.rop.cst.CstType; -import com.pojavdx.dx.rop.type.Type; -import com.pojavdx.dx.util.Bits; -import com.pojavdx.dx.util.IntList; -import java.util.ArrayList; - -/** - * Utility that identifies basic blocks in bytecode. - */ -public final class BasicBlocker implements BytecodeArray.Visitor { - /** {@code non-null;} method being converted */ - private final ConcreteMethod method; - - /** - * {@code non-null;} work set; bits indicate offsets in need of - * examination - */ - private final int[] workSet; - - /** - * {@code non-null;} live set; bits indicate potentially-live - * opcodes; contrawise, a bit that isn't on is either in the - * middle of an instruction or is a definitely-dead opcode - */ - private final int[] liveSet; - - /** - * {@code non-null;} block start set; bits indicate the starts of - * basic blocks, including the opcodes that start blocks of - * definitely-dead code - */ - private final int[] blockSet; - - /** - * {@code non-null, sparse;} for each instruction offset to a branch of - * some sort, the list of targets for that instruction - */ - private final IntList[] targetLists; - - /** - * {@code non-null, sparse;} for each instruction offset to a throwing - * instruction, the list of exception handlers for that instruction - */ - private final ByteCatchList[] catchLists; - - /** offset of the previously parsed bytecode */ - private int previousOffset; - - /** - * Identifies and enumerates the basic blocks in the given method, - * returning a list of them. The returned list notably omits any - * definitely-dead code that is identified in the process. - * - * @param method {@code non-null;} method to convert - * @return {@code non-null;} list of basic blocks - */ - public static ByteBlockList identifyBlocks(ConcreteMethod method) { - BasicBlocker bb = new BasicBlocker(method); - - bb.doit(); - return bb.getBlockList(); - } - - /** - * Constructs an instance. This class is not publicly instantiable; use - * {@link #identifyBlocks}. - * - * @param method {@code non-null;} method to convert - */ - private BasicBlocker(ConcreteMethod method) { - if (method == null) { - throw new NullPointerException("method == null"); - } - - this.method = method; - - /* - * The "+1" below is so the idx-past-end is also valid, - * avoiding a special case, but without preventing - * flow-of-control falling past the end of the method from - * getting properly reported. - */ - int sz = method.getCode().size() + 1; - - workSet = Bits.makeBitSet(sz); - liveSet = Bits.makeBitSet(sz); - blockSet = Bits.makeBitSet(sz); - targetLists = new IntList[sz]; - catchLists = new ByteCatchList[sz]; - previousOffset = -1; - } - - /* - * Note: These methods are defined implementation of the interface - * BytecodeArray.Visitor; since the class isn't publicly - * instantiable, no external code ever gets a chance to actually - * call these methods. - */ - - /** {@inheritDoc} */ - @Override - public void visitInvalid(int opcode, int offset, int length) { - visitCommon(offset, length, true); - } - - /** {@inheritDoc} */ - @Override - public void visitNoArgs(int opcode, int offset, int length, Type type) { - switch (opcode) { - case ByteOps.IRETURN: - case ByteOps.RETURN: { - visitCommon(offset, length, false); - targetLists[offset] = IntList.EMPTY; - break; - } - case ByteOps.ATHROW: { - visitCommon(offset, length, false); - visitThrowing(offset, length, false); - break; - } - case ByteOps.IALOAD: - case ByteOps.LALOAD: - case ByteOps.FALOAD: - case ByteOps.DALOAD: - case ByteOps.AALOAD: - case ByteOps.BALOAD: - case ByteOps.CALOAD: - case ByteOps.SALOAD: - case ByteOps.IASTORE: - case ByteOps.LASTORE: - case ByteOps.FASTORE: - case ByteOps.DASTORE: - case ByteOps.AASTORE: - case ByteOps.BASTORE: - case ByteOps.CASTORE: - case ByteOps.SASTORE: - case ByteOps.ARRAYLENGTH: - case ByteOps.MONITORENTER: - case ByteOps.MONITOREXIT: { - /* - * These instructions can all throw, so they have to end - * the block they appear in (since throws are branches). - */ - visitCommon(offset, length, true); - visitThrowing(offset, length, true); - break; - } - case ByteOps.IDIV: - case ByteOps.IREM: { - /* - * The int and long versions of division and remainder may - * throw, but not the other types. - */ - visitCommon(offset, length, true); - if ((type == Type.INT) || (type == Type.LONG)) { - visitThrowing(offset, length, true); - } - break; - } - default: { - visitCommon(offset, length, true); - break; - } - } - } - - /** {@inheritDoc} */ - @Override - public void visitLocal(int opcode, int offset, int length, - int idx, Type type, int value) { - if (opcode == ByteOps.RET) { - visitCommon(offset, length, false); - targetLists[offset] = IntList.EMPTY; - } else { - visitCommon(offset, length, true); - } - } - - /** {@inheritDoc} */ - @Override - public void visitConstant(int opcode, int offset, int length, - Constant cst, int value) { - visitCommon(offset, length, true); - - if (cst instanceof CstMemberRef || cst instanceof CstType || - cst instanceof CstString || cst instanceof CstInvokeDynamic || - cst instanceof CstMethodHandle || cst instanceof CstProtoRef) { - /* - * Instructions with these sorts of constants have the - * possibility of throwing, so this instruction needs to - * end its block (since it can throw, and possible-throws - * are branch points). - */ - visitThrowing(offset, length, true); - } - } - - /** {@inheritDoc} */ - @Override - public void visitBranch(int opcode, int offset, int length, - int target) { - switch (opcode) { - case ByteOps.GOTO: { - visitCommon(offset, length, false); - targetLists[offset] = IntList.makeImmutable(target); - break; - } - case ByteOps.JSR: { - /* - * Each jsr is quarantined into a separate block (containing - * only the jsr instruction) but is otherwise treated - * as a conditional branch. (That is to say, both its - * target and next instruction begin new blocks.) - */ - addWorkIfNecessary(offset, true); - // Fall through to next case... - } - default: { - int next = offset + length; - visitCommon(offset, length, true); - addWorkIfNecessary(next, true); - targetLists[offset] = IntList.makeImmutable(next, target); - break; - } - } - - addWorkIfNecessary(target, true); - } - - /** {@inheritDoc} */ - @Override - public void visitSwitch(int opcode, int offset, int length, - SwitchList cases, int padding) { - visitCommon(offset, length, false); - addWorkIfNecessary(cases.getDefaultTarget(), true); - - int sz = cases.size(); - for (int i = 0; i < sz; i++) { - addWorkIfNecessary(cases.getTarget(i), true); - } - - targetLists[offset] = cases.getTargets(); - } - - /** {@inheritDoc} */ - @Override - public void visitNewarray(int offset, int length, CstType type, - ArrayList intVals) { - visitCommon(offset, length, true); - visitThrowing(offset, length, true); - } - - /** - * Extracts the list of basic blocks from the bit sets. - * - * @return {@code non-null;} the list of basic blocks - */ - private ByteBlockList getBlockList() { - BytecodeArray bytes = method.getCode(); - ByteBlock[] bbs = new ByteBlock[bytes.size()]; - int count = 0; - - for (int at = 0, next; /*at*/; at = next) { - next = Bits.findFirst(blockSet, at + 1); - if (next < 0) { - break; - } - - if (Bits.get(liveSet, at)) { - /* - * Search backward for the branch or throwing - * instruction at the end of this block, if any. If - * there isn't any, then "next" is the sole target. - */ - IntList targets = null; - int targetsAt = -1; - ByteCatchList blockCatches; - - for (int i = next - 1; i >= at; i--) { - targets = targetLists[i]; - if (targets != null) { - targetsAt = i; - break; - } - } - - if (targets == null) { - targets = IntList.makeImmutable(next); - blockCatches = ByteCatchList.EMPTY; - } else { - blockCatches = catchLists[targetsAt]; - if (blockCatches == null) { - blockCatches = ByteCatchList.EMPTY; - } - } - - bbs[count] = - new ByteBlock(at, at, next, targets, blockCatches); - count++; - } - } - - ByteBlockList result = new ByteBlockList(count); - for (int i = 0; i < count; i++) { - result.set(i, bbs[i]); - } - - return result; - } - - /** - * Does basic block identification. - */ - private void doit() { - BytecodeArray bytes = method.getCode(); - ByteCatchList catches = method.getCatches(); - int catchSz = catches.size(); - - /* - * Start by setting offset 0 as the start of a block and in need - * of work... - */ - Bits.set(workSet, 0); - Bits.set(blockSet, 0); - - /* - * And then process the work set, add new work based on - * exception ranges that are active, and iterate until there's - * nothing left to work on. - */ - while (!Bits.isEmpty(workSet)) { - try { - bytes.processWorkSet(workSet, this); - } catch (IllegalArgumentException ex) { - // Translate the exception. - throw new SimException("flow of control falls off " + - "end of method", - ex); - } - - for (int i = 0; i < catchSz; i++) { - ByteCatchList.Item item = catches.get(i); - int start = item.getStartPc(); - int end = item.getEndPc(); - if (Bits.anyInRange(liveSet, start, end)) { - Bits.set(blockSet, start); - Bits.set(blockSet, end); - addWorkIfNecessary(item.getHandlerPc(), true); - } - } - } - } - - /** - * Sets a bit in the work set, but only if the instruction in question - * isn't yet known to be possibly-live. - * - * @param offset offset to the instruction in question - * @param blockStart {@code true} iff this instruction starts a - * basic block - */ - private void addWorkIfNecessary(int offset, boolean blockStart) { - if (!Bits.get(liveSet, offset)) { - Bits.set(workSet, offset); - } - - if (blockStart) { - Bits.set(blockSet, offset); - } - } - - /** - * Helper method used by all the visitor methods. - * - * @param offset offset to the instruction - * @param length length of the instruction, in bytes - * @param nextIsLive {@code true} iff the instruction after - * the indicated one is possibly-live (because this one isn't an - * unconditional branch, a return, or a switch) - */ - private void visitCommon(int offset, int length, boolean nextIsLive) { - Bits.set(liveSet, offset); - - if (nextIsLive) { - /* - * If the next instruction is flowed to by this one, just - * add it to the work set, and then a subsequent visit*() - * will deal with it as appropriate. - */ - addWorkIfNecessary(offset + length, false); - } else { - /* - * If the next instruction isn't flowed to by this one, - * then mark it as a start of a block but *don't* add it - * to the work set, so that in the final phase we can know - * dead code blocks as those marked as blocks but not also marked - * live. - */ - Bits.set(blockSet, offset + length); - } - } - - /** - * Helper method used by all the visitor methods that deal with - * opcodes that possibly throw. This method should be called after calling - * {@link #visitCommon}. - * - * @param offset offset to the instruction - * @param length length of the instruction, in bytes - * @param nextIsLive {@code true} iff the instruction after - * the indicated one is possibly-live (because this one isn't an - * unconditional throw) - */ - private void visitThrowing(int offset, int length, boolean nextIsLive) { - int next = offset + length; - - if (nextIsLive) { - addWorkIfNecessary(next, true); - } - - ByteCatchList catches = method.getCatches().listFor(offset); - catchLists[offset] = catches; - targetLists[offset] = catches.toTargetList(nextIsLive ? next : -1); - } - - /** - * {@inheritDoc} - */ - @Override - public void setPreviousOffset(int offset) { - previousOffset = offset; - } - - /** - * {@inheritDoc} - */ - @Override - public int getPreviousOffset() { - return previousOffset; - } -} diff --git a/app/src/main/java/com/pojavdx/dx/cf/code/BootstrapMethodArgumentsList.java b/app/src/main/java/com/pojavdx/dx/cf/code/BootstrapMethodArgumentsList.java deleted file mode 100644 index d963a979c..000000000 --- a/app/src/main/java/com/pojavdx/dx/cf/code/BootstrapMethodArgumentsList.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.pojavdx.dx.cf.code; - -import com.pojavdx.dx.rop.cst.Constant; -import com.pojavdx.dx.rop.cst.CstDouble; -import com.pojavdx.dx.rop.cst.CstFloat; -import com.pojavdx.dx.rop.cst.CstInteger; -import com.pojavdx.dx.rop.cst.CstLong; -import com.pojavdx.dx.rop.cst.CstMethodHandle; -import com.pojavdx.dx.rop.cst.CstProtoRef; -import com.pojavdx.dx.rop.cst.CstString; -import com.pojavdx.dx.rop.cst.CstType; -import com.pojavdx.dx.util.FixedSizeList; - -/** - * List of bootstrap method arguments, which are part of the contents of - * {@code BootstrapMethods} attributes. - */ -public class BootstrapMethodArgumentsList extends FixedSizeList { - /** - * Constructs an instance. - * - * @param count the number of elements to be in the list - */ - public BootstrapMethodArgumentsList(int count) { - super(count); - } - - /** - * Gets the bootstrap argument from the indicated position. - * - * @param n position of argument to get - * @return {@code Constant} instance - */ - public Constant get(int n) { - return (Constant) get0(n); - } - - /** - * Sets the bootstrap argument at the indicated position. - * - * @param n position of argument to set - * @param cst {@code Constant} instance - */ - public void set(int n, Constant cst) { - // The set of permitted types is defined by the JVMS 8, section 4.7.23. - if (cst instanceof CstString || - cst instanceof CstType || - cst instanceof CstInteger || - cst instanceof CstLong || - cst instanceof CstFloat || - cst instanceof CstDouble || - cst instanceof CstMethodHandle || - cst instanceof CstProtoRef) { - set0(n, cst); - } else { - Class klass = cst.getClass(); - throw new IllegalArgumentException("bad type for bootstrap argument: " + klass); - } - } -} diff --git a/app/src/main/java/com/pojavdx/dx/cf/code/BootstrapMethodsList.java b/app/src/main/java/com/pojavdx/dx/cf/code/BootstrapMethodsList.java deleted file mode 100644 index 55359daf2..000000000 --- a/app/src/main/java/com/pojavdx/dx/cf/code/BootstrapMethodsList.java +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.pojavdx.dx.cf.code; - -import com.pojavdx.dx.rop.cst.CstMethodHandle; -import com.pojavdx.dx.rop.cst.CstType; -import com.pojavdx.dx.util.FixedSizeList; - -/** - * List of bootstrap method entries, which are the contents of - * {@code BootstrapMethods} attributes. - */ -public class BootstrapMethodsList extends FixedSizeList { - /** {@code non-null;} zero-size instance */ - public static final BootstrapMethodsList EMPTY = new BootstrapMethodsList(0); - - /** - * Constructs an instance. - * - * @param count the number of elements to be in the list - */ - public BootstrapMethodsList(int count) { - super(count); - } - - /** - * Gets the indicated item. - * - * @param n {@code >= 0;} which item - * @return {@code null-ok;} the indicated item - */ - public Item get(int n) { - return (Item) get0(n); - } - - /** - * Sets the item at the given index. - * - * @param n {@code >= 0, < size();} which element - * @param item {@code non-null;} the item - */ - public void set(int n, Item item) { - if (item == null) { - throw new NullPointerException("item == null"); - } - - set0(n, item); - } - - /** - * Sets the item at the given index. - * - * @param n {@code >= 0, < size();} which element - * @param declaringClass {@code non-null;} the class declaring bootstrap method. - * @param bootstrapMethodHandle {@code non-null;} the bootstrap method handle - * @param arguments {@code non-null;} the arguments of the bootstrap method - */ - public void set(int n, CstType declaringClass, CstMethodHandle bootstrapMethodHandle, - BootstrapMethodArgumentsList arguments) { - set(n, new Item(declaringClass, bootstrapMethodHandle, arguments)); - } - - /** - * Returns an instance which is the concatenation of the two given - * instances. - * - * @param list1 {@code non-null;} first instance - * @param list2 {@code non-null;} second instance - * @return {@code non-null;} combined instance - */ - public static BootstrapMethodsList concat(BootstrapMethodsList list1, - BootstrapMethodsList list2) { - if (list1 == EMPTY) { - return list2; - } else if (list2 == EMPTY) { - return list1; - } - - int sz1 = list1.size(); - int sz2 = list2.size(); - BootstrapMethodsList result = new BootstrapMethodsList(sz1 + sz2); - - for (int i = 0; i < sz1; i++) { - result.set(i, list1.get(i)); - } - - for (int i = 0; i < sz2; i++) { - result.set(sz1 + i, list2.get(i)); - } - - return result; - } - - public static class Item { - private final BootstrapMethodArgumentsList bootstrapMethodArgumentsList; - private final CstMethodHandle bootstrapMethodHandle; - private final CstType declaringClass; - - public Item(CstType declaringClass, CstMethodHandle bootstrapMethodHandle, - BootstrapMethodArgumentsList bootstrapMethodArguments) { - if (declaringClass == null) { - throw new NullPointerException("declaringClass == null"); - } - if (bootstrapMethodHandle == null) { - throw new NullPointerException("bootstrapMethodHandle == null"); - } - if (bootstrapMethodArguments == null) { - throw new NullPointerException("bootstrapMethodArguments == null"); - } - this.bootstrapMethodHandle = bootstrapMethodHandle; - this.bootstrapMethodArgumentsList = bootstrapMethodArguments; - this.declaringClass = declaringClass; - } - - public CstMethodHandle getBootstrapMethodHandle() { - return bootstrapMethodHandle; - } - - public BootstrapMethodArgumentsList getBootstrapMethodArguments() { - return bootstrapMethodArgumentsList; - } - - public CstType getDeclaringClass() { - return declaringClass; - } - } -} diff --git a/app/src/main/java/com/pojavdx/dx/cf/code/ByteBlock.java b/app/src/main/java/com/pojavdx/dx/cf/code/ByteBlock.java deleted file mode 100644 index c2368802e..000000000 --- a/app/src/main/java/com/pojavdx/dx/cf/code/ByteBlock.java +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.pojavdx.dx.cf.code; - -import com.pojavdx.dx.util.Hex; -import com.pojavdx.dx.util.IntList; -import com.pojavdx.dx.util.LabeledItem; - -/** - * Representation of a basic block in a bytecode array. - */ -public final class ByteBlock implements LabeledItem { - /** {@code >= 0;} label for this block */ - private final int label; - - /** {@code >= 0;} bytecode offset (inclusive) of the start of the block */ - private final int start; - - /** {@code > start;} bytecode offset (exclusive) of the end of the block */ - private final int end; - - /** {@code non-null;} list of successors that this block may branch to */ - private final IntList successors; - - /** {@code non-null;} list of exceptions caught and their handler targets */ - private final ByteCatchList catches; - - /** - * Constructs an instance. - * - * @param label {@code >= 0;} target label for this block - * @param start {@code >= 0;} bytecode offset (inclusive) of the start - * of the block - * @param end {@code > start;} bytecode offset (exclusive) of the end - * of the block - * @param successors {@code non-null;} list of successors that this block may - * branch to - * @param catches {@code non-null;} list of exceptions caught and their - * handler targets - */ - public ByteBlock(int label, int start, int end, IntList successors, - ByteCatchList catches) { - if (label < 0) { - throw new IllegalArgumentException("label < 0"); - } - - if (start < 0) { - throw new IllegalArgumentException("start < 0"); - } - - if (end <= start) { - throw new IllegalArgumentException("end <= start"); - } - - if (successors == null) { - throw new NullPointerException("targets == null"); - } - - int sz = successors.size(); - for (int i = 0; i < sz; i++) { - if (successors.get(i) < 0) { - throw new IllegalArgumentException("successors[" + i + - "] == " + - successors.get(i)); - } - } - - if (catches == null) { - throw new NullPointerException("catches == null"); - } - - this.label = label; - this.start = start; - this.end = end; - this.successors = successors; - this.catches = catches; - } - - /** {@inheritDoc} */ - @Override - public String toString() { - return '{' + Hex.u2(label) + ": " + Hex.u2(start) + ".." + - Hex.u2(end) + '}'; - } - - /** - * Gets the label of this block. - * - * @return {@code >= 0;} the label - */ - @Override - public int getLabel() { - return label; - } - - /** - * Gets the bytecode offset (inclusive) of the start of this block. - * - * @return {@code >= 0;} the start offset - */ - public int getStart() { - return start; - } - - /** - * Gets the bytecode offset (exclusive) of the end of this block. - * - * @return {@code > getStart();} the end offset - */ - public int getEnd() { - return end; - } - - /** - * Gets the list of successors that this block may branch to - * non-exceptionally. - * - * @return {@code non-null;} the successor list - */ - public IntList getSuccessors() { - return successors; - } - - /** - * Gets the list of exceptions caught and their handler targets. - * - * @return {@code non-null;} the catch list - */ - public ByteCatchList getCatches() { - return catches; - } -} diff --git a/app/src/main/java/com/pojavdx/dx/cf/code/ByteBlockList.java b/app/src/main/java/com/pojavdx/dx/cf/code/ByteBlockList.java deleted file mode 100644 index ca11f54fd..000000000 --- a/app/src/main/java/com/pojavdx/dx/cf/code/ByteBlockList.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.pojavdx.dx.cf.code; - -import com.pojavdx.dx.util.Hex; -import com.pojavdx.dx.util.LabeledList; - -/** - * List of {@link ByteBlock} instances. - */ -public final class ByteBlockList extends LabeledList { - - /** - * Constructs an instance. - * - * @param size {@code >= 0;} the number of elements to be in the list - */ - public ByteBlockList(int size) { - super(size); - } - - /** - * Gets the indicated element. It is an error to call this with the - * index for an element which was never set; if you do that, this - * will throw {@code NullPointerException}. - * - * @param n {@code >= 0, < size();} which element - * @return {@code non-null;} the indicated element - */ - public ByteBlock get(int n) { - return (ByteBlock) get0(n); - } - - /** - * Gets the block with the given label. - * - * @param label the label to look for - * @return {@code non-null;} the block with the given label - */ - public ByteBlock labelToBlock(int label) { - int idx = indexOfLabel(label); - - if (idx < 0) { - throw new IllegalArgumentException("no such label: " - + Hex.u2(label)); - } - - return get(idx); - } - - /** - * Sets the element at the given index. - * - * @param n {@code >= 0, < size();} which element - * @param bb {@code null-ok;} the value to store - */ - public void set(int n, ByteBlock bb) { - super.set(n, bb); - } -} diff --git a/app/src/main/java/com/pojavdx/dx/cf/code/ByteCatchList.java b/app/src/main/java/com/pojavdx/dx/cf/code/ByteCatchList.java deleted file mode 100644 index 84e6fda41..000000000 --- a/app/src/main/java/com/pojavdx/dx/cf/code/ByteCatchList.java +++ /dev/null @@ -1,317 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.pojavdx.dx.cf.code; - -import com.pojavdx.dx.rop.cst.CstType; -import com.pojavdx.dx.rop.type.StdTypeList; -import com.pojavdx.dx.rop.type.TypeList; -import com.pojavdx.dx.util.FixedSizeList; -import com.pojavdx.dx.util.IntList; - -/** - * List of catch entries, that is, the elements of an "exception table," - * which is part of a standard {@code Code} attribute. - */ -public final class ByteCatchList extends FixedSizeList { - /** {@code non-null;} convenient zero-entry instance */ - public static final ByteCatchList EMPTY = new ByteCatchList(0); - - /** - * Constructs an instance. - * - * @param count the number of elements to be in the table - */ - public ByteCatchList(int count) { - super(count); - } - - /** - * Gets the total length of this structure in bytes, when included in - * a {@code Code} attribute. The returned value includes the - * two bytes for {@code exception_table_length}. - * - * @return {@code >= 2;} the total length, in bytes - */ - public int byteLength() { - return 2 + size() * 8; - } - - /** - * Gets the indicated item. - * - * @param n {@code >= 0;} which item - * @return {@code null-ok;} the indicated item - */ - public Item get(int n) { - return (Item) get0(n); - } - - /** - * Sets the item at the given index. - * - * @param n {@code >= 0, < size();} which entry to set - * @param item {@code non-null;} the item - */ - public void set(int n, Item item) { - if (item == null) { - throw new NullPointerException("item == null"); - } - - set0(n, item); - } - - /** - * Sets the item at the given index. - * - * @param n {@code >= 0, < size();} which entry to set - * @param startPc {@code >= 0;} the start pc (inclusive) of the handler's range - * @param endPc {@code >= startPc;} the end pc (exclusive) of the - * handler's range - * @param handlerPc {@code >= 0;} the pc of the exception handler - * @param exceptionClass {@code null-ok;} the exception class or - * {@code null} to catch all exceptions with this handler - */ - public void set(int n, int startPc, int endPc, int handlerPc, - CstType exceptionClass) { - set0(n, new Item(startPc, endPc, handlerPc, exceptionClass)); - } - - /** - * Gets the list of items active at the given address. The result is - * automatically made immutable. - * - * @param pc which address - * @return {@code non-null;} list of exception handlers active at - * {@code pc} - */ - public ByteCatchList listFor(int pc) { - int sz = size(); - Item[] resultArr = new Item[sz]; - int resultSz = 0; - - for (int i = 0; i < sz; i++) { - Item one = get(i); - if (one.covers(pc) && typeNotFound(one, resultArr, resultSz)) { - resultArr[resultSz] = one; - resultSz++; - } - } - - if (resultSz == 0) { - return EMPTY; - } - - ByteCatchList result = new ByteCatchList(resultSz); - for (int i = 0; i < resultSz; i++) { - result.set(i, resultArr[i]); - } - - result.setImmutable(); - return result; - } - - /** - * Helper method for {@link #listFor}, which tells whether a match - * is not found for the exception type of the given item in - * the given array. A match is considered to be either an exact type - * match or the class {@code Object} which represents a catch-all. - * - * @param item {@code non-null;} item with the exception type to look for - * @param arr {@code non-null;} array to search in - * @param count {@code non-null;} maximum number of elements in the array to check - * @return {@code true} iff the exception type is not found - */ - private static boolean typeNotFound(Item item, Item[] arr, int count) { - CstType type = item.getExceptionClass(); - - for (int i = 0; i < count; i++) { - CstType one = arr[i].getExceptionClass(); - if ((one == type) || (one == CstType.OBJECT)) { - return false; - } - } - - return true; - } - - /** - * Returns a target list corresponding to this instance. The result - * is a list of all the exception handler addresses, with the given - * {@code noException} address appended if appropriate. The - * result is automatically made immutable. - * - * @param noException {@code >= -1;} the no-exception address to append, or - * {@code -1} not to append anything - * @return {@code non-null;} list of exception targets, with - * {@code noException} appended if necessary - */ - public IntList toTargetList(int noException) { - if (noException < -1) { - throw new IllegalArgumentException("noException < -1"); - } - - boolean hasDefault = (noException >= 0); - int sz = size(); - - if (sz == 0) { - if (hasDefault) { - /* - * The list is empty, but there is a no-exception - * address; so, the result is just that address. - */ - return IntList.makeImmutable(noException); - } - /* - * The list is empty and there isn't even a no-exception - * address. - */ - return IntList.EMPTY; - } - - IntList result = new IntList(sz + (hasDefault ? 1 : 0)); - - for (int i = 0; i < sz; i++) { - result.add(get(i).getHandlerPc()); - } - - if (hasDefault) { - result.add(noException); - } - - result.setImmutable(); - return result; - } - - /** - * Returns a rop-style catches list equivalent to this one. - * - * @return {@code non-null;} the converted instance - */ - public TypeList toRopCatchList() { - int sz = size(); - if (sz == 0) { - return StdTypeList.EMPTY; - } - - StdTypeList result = new StdTypeList(sz); - - for (int i = 0; i < sz; i++) { - result.set(i, get(i).getExceptionClass().getClassType()); - } - - result.setImmutable(); - return result; - } - - /** - * Item in an exception handler list. - */ - public static class Item { - /** {@code >= 0;} the start pc (inclusive) of the handler's range */ - private final int startPc; - - /** {@code >= startPc;} the end pc (exclusive) of the handler's range */ - private final int endPc; - - /** {@code >= 0;} the pc of the exception handler */ - private final int handlerPc; - - /** {@code null-ok;} the exception class or {@code null} to catch all - * exceptions with this handler */ - private final CstType exceptionClass; - - /** - * Constructs an instance. - * - * @param startPc {@code >= 0;} the start pc (inclusive) of the - * handler's range - * @param endPc {@code >= startPc;} the end pc (exclusive) of the - * handler's range - * @param handlerPc {@code >= 0;} the pc of the exception handler - * @param exceptionClass {@code null-ok;} the exception class or - * {@code null} to catch all exceptions with this handler - */ - public Item(int startPc, int endPc, int handlerPc, - CstType exceptionClass) { - if (startPc < 0) { - throw new IllegalArgumentException("startPc < 0"); - } - - if (endPc < startPc) { - throw new IllegalArgumentException("endPc < startPc"); - } - - if (handlerPc < 0) { - throw new IllegalArgumentException("handlerPc < 0"); - } - - this.startPc = startPc; - this.endPc = endPc; - this.handlerPc = handlerPc; - this.exceptionClass = exceptionClass; - } - - /** - * Gets the start pc (inclusive) of the handler's range. - * - * @return {@code >= 0;} the start pc (inclusive) of the handler's range. - */ - public int getStartPc() { - return startPc; - } - - /** - * Gets the end pc (exclusive) of the handler's range. - * - * @return {@code >= startPc;} the end pc (exclusive) of the - * handler's range. - */ - public int getEndPc() { - return endPc; - } - - /** - * Gets the pc of the exception handler. - * - * @return {@code >= 0;} the pc of the exception handler - */ - public int getHandlerPc() { - return handlerPc; - } - - /** - * Gets the class of exception handled. - * - * @return {@code non-null;} the exception class; {@link CstType#OBJECT} - * if this entry handles all possible exceptions - */ - public CstType getExceptionClass() { - return (exceptionClass != null) ? - exceptionClass : CstType.OBJECT; - } - - /** - * Returns whether the given address is in the range of this item. - * - * @param pc the address - * @return {@code true} iff this item covers {@code pc} - */ - public boolean covers(int pc) { - return (pc >= startPc) && (pc < endPc); - } - } -} diff --git a/app/src/main/java/com/pojavdx/dx/cf/code/ByteOps.java b/app/src/main/java/com/pojavdx/dx/cf/code/ByteOps.java deleted file mode 100644 index 9dce1eb74..000000000 --- a/app/src/main/java/com/pojavdx/dx/cf/code/ByteOps.java +++ /dev/null @@ -1,650 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.pojavdx.dx.cf.code; - -import com.pojavdx.dx.util.Hex; - -/** - * Constants and utility methods for dealing with bytecode arrays at an - * opcode level. - */ -public class ByteOps { - // one constant per opcode - public static final int NOP = 0x00; - public static final int ACONST_NULL = 0x01; - public static final int ICONST_M1 = 0x02; - public static final int ICONST_0 = 0x03; - public static final int ICONST_1 = 0x04; - public static final int ICONST_2 = 0x05; - public static final int ICONST_3 = 0x06; - public static final int ICONST_4 = 0x07; - public static final int ICONST_5 = 0x08; - public static final int LCONST_0 = 0x09; - public static final int LCONST_1 = 0x0a; - public static final int FCONST_0 = 0x0b; - public static final int FCONST_1 = 0x0c; - public static final int FCONST_2 = 0x0d; - public static final int DCONST_0 = 0x0e; - public static final int DCONST_1 = 0x0f; - public static final int BIPUSH = 0x10; - public static final int SIPUSH = 0x11; - public static final int LDC = 0x12; - public static final int LDC_W = 0x13; - public static final int LDC2_W = 0x14; - public static final int ILOAD = 0x15; - public static final int LLOAD = 0x16; - public static final int FLOAD = 0x17; - public static final int DLOAD = 0x18; - public static final int ALOAD = 0x19; - public static final int ILOAD_0 = 0x1a; - public static final int ILOAD_1 = 0x1b; - public static final int ILOAD_2 = 0x1c; - public static final int ILOAD_3 = 0x1d; - public static final int LLOAD_0 = 0x1e; - public static final int LLOAD_1 = 0x1f; - public static final int LLOAD_2 = 0x20; - public static final int LLOAD_3 = 0x21; - public static final int FLOAD_0 = 0x22; - public static final int FLOAD_1 = 0x23; - public static final int FLOAD_2 = 0x24; - public static final int FLOAD_3 = 0x25; - public static final int DLOAD_0 = 0x26; - public static final int DLOAD_1 = 0x27; - public static final int DLOAD_2 = 0x28; - public static final int DLOAD_3 = 0x29; - public static final int ALOAD_0 = 0x2a; - public static final int ALOAD_1 = 0x2b; - public static final int ALOAD_2 = 0x2c; - public static final int ALOAD_3 = 0x2d; - public static final int IALOAD = 0x2e; - public static final int LALOAD = 0x2f; - public static final int FALOAD = 0x30; - public static final int DALOAD = 0x31; - public static final int AALOAD = 0x32; - public static final int BALOAD = 0x33; - public static final int CALOAD = 0x34; - public static final int SALOAD = 0x35; - public static final int ISTORE = 0x36; - public static final int LSTORE = 0x37; - public static final int FSTORE = 0x38; - public static final int DSTORE = 0x39; - public static final int ASTORE = 0x3a; - public static final int ISTORE_0 = 0x3b; - public static final int ISTORE_1 = 0x3c; - public static final int ISTORE_2 = 0x3d; - public static final int ISTORE_3 = 0x3e; - public static final int LSTORE_0 = 0x3f; - public static final int LSTORE_1 = 0x40; - public static final int LSTORE_2 = 0x41; - public static final int LSTORE_3 = 0x42; - public static final int FSTORE_0 = 0x43; - public static final int FSTORE_1 = 0x44; - public static final int FSTORE_2 = 0x45; - public static final int FSTORE_3 = 0x46; - public static final int DSTORE_0 = 0x47; - public static final int DSTORE_1 = 0x48; - public static final int DSTORE_2 = 0x49; - public static final int DSTORE_3 = 0x4a; - public static final int ASTORE_0 = 0x4b; - public static final int ASTORE_1 = 0x4c; - public static final int ASTORE_2 = 0x4d; - public static final int ASTORE_3 = 0x4e; - public static final int IASTORE = 0x4f; - public static final int LASTORE = 0x50; - public static final int FASTORE = 0x51; - public static final int DASTORE = 0x52; - public static final int AASTORE = 0x53; - public static final int BASTORE = 0x54; - public static final int CASTORE = 0x55; - public static final int SASTORE = 0x56; - public static final int POP = 0x57; - public static final int POP2 = 0x58; - public static final int DUP = 0x59; - public static final int DUP_X1 = 0x5a; - public static final int DUP_X2 = 0x5b; - public static final int DUP2 = 0x5c; - public static final int DUP2_X1 = 0x5d; - public static final int DUP2_X2 = 0x5e; - public static final int SWAP = 0x5f; - public static final int IADD = 0x60; - public static final int LADD = 0x61; - public static final int FADD = 0x62; - public static final int DADD = 0x63; - public static final int ISUB = 0x64; - public static final int LSUB = 0x65; - public static final int FSUB = 0x66; - public static final int DSUB = 0x67; - public static final int IMUL = 0x68; - public static final int LMUL = 0x69; - public static final int FMUL = 0x6a; - public static final int DMUL = 0x6b; - public static final int IDIV = 0x6c; - public static final int LDIV = 0x6d; - public static final int FDIV = 0x6e; - public static final int DDIV = 0x6f; - public static final int IREM = 0x70; - public static final int LREM = 0x71; - public static final int FREM = 0x72; - public static final int DREM = 0x73; - public static final int INEG = 0x74; - public static final int LNEG = 0x75; - public static final int FNEG = 0x76; - public static final int DNEG = 0x77; - public static final int ISHL = 0x78; - public static final int LSHL = 0x79; - public static final int ISHR = 0x7a; - public static final int LSHR = 0x7b; - public static final int IUSHR = 0x7c; - public static final int LUSHR = 0x7d; - public static final int IAND = 0x7e; - public static final int LAND = 0x7f; - public static final int IOR = 0x80; - public static final int LOR = 0x81; - public static final int IXOR = 0x82; - public static final int LXOR = 0x83; - public static final int IINC = 0x84; - public static final int I2L = 0x85; - public static final int I2F = 0x86; - public static final int I2D = 0x87; - public static final int L2I = 0x88; - public static final int L2F = 0x89; - public static final int L2D = 0x8a; - public static final int F2I = 0x8b; - public static final int F2L = 0x8c; - public static final int F2D = 0x8d; - public static final int D2I = 0x8e; - public static final int D2L = 0x8f; - public static final int D2F = 0x90; - public static final int I2B = 0x91; - public static final int I2C = 0x92; - public static final int I2S = 0x93; - public static final int LCMP = 0x94; - public static final int FCMPL = 0x95; - public static final int FCMPG = 0x96; - public static final int DCMPL = 0x97; - public static final int DCMPG = 0x98; - public static final int IFEQ = 0x99; - public static final int IFNE = 0x9a; - public static final int IFLT = 0x9b; - public static final int IFGE = 0x9c; - public static final int IFGT = 0x9d; - public static final int IFLE = 0x9e; - public static final int IF_ICMPEQ = 0x9f; - public static final int IF_ICMPNE = 0xa0; - public static final int IF_ICMPLT = 0xa1; - public static final int IF_ICMPGE = 0xa2; - public static final int IF_ICMPGT = 0xa3; - public static final int IF_ICMPLE = 0xa4; - public static final int IF_ACMPEQ = 0xa5; - public static final int IF_ACMPNE = 0xa6; - public static final int GOTO = 0xa7; - public static final int JSR = 0xa8; - public static final int RET = 0xa9; - public static final int TABLESWITCH = 0xaa; - public static final int LOOKUPSWITCH = 0xab; - public static final int IRETURN = 0xac; - public static final int LRETURN = 0xad; - public static final int FRETURN = 0xae; - public static final int DRETURN = 0xaf; - public static final int ARETURN = 0xb0; - public static final int RETURN = 0xb1; - public static final int GETSTATIC = 0xb2; - public static final int PUTSTATIC = 0xb3; - public static final int GETFIELD = 0xb4; - public static final int PUTFIELD = 0xb5; - public static final int INVOKEVIRTUAL = 0xb6; - public static final int INVOKESPECIAL = 0xb7; - public static final int INVOKESTATIC = 0xb8; - public static final int INVOKEINTERFACE = 0xb9; - public static final int INVOKEDYNAMIC = 0xba; - public static final int NEW = 0xbb; - public static final int NEWARRAY = 0xbc; - public static final int ANEWARRAY = 0xbd; - public static final int ARRAYLENGTH = 0xbe; - public static final int ATHROW = 0xbf; - public static final int CHECKCAST = 0xc0; - public static final int INSTANCEOF = 0xc1; - public static final int MONITORENTER = 0xc2; - public static final int MONITOREXIT = 0xc3; - public static final int WIDE = 0xc4; - public static final int MULTIANEWARRAY = 0xc5; - public static final int IFNULL = 0xc6; - public static final int IFNONNULL = 0xc7; - public static final int GOTO_W = 0xc8; - public static final int JSR_W = 0xc9; - - // a constant for each valid argument to "newarray" - - public static final int NEWARRAY_BOOLEAN = 4; - public static final int NEWARRAY_CHAR = 5; - public static final int NEWARRAY_FLOAT = 6; - public static final int NEWARRAY_DOUBLE = 7; - public static final int NEWARRAY_BYTE = 8; - public static final int NEWARRAY_SHORT = 9; - public static final int NEWARRAY_INT = 10; - public static final int NEWARRAY_LONG = 11; - - // a constant for each possible instruction format - - /** invalid */ - public static final int FMT_INVALID = 0; - - /** "-": {@code op} */ - public static final int FMT_NO_ARGS = 1; - - /** "0": {@code op}; implies {@code max_locals >= 1} */ - public static final int FMT_NO_ARGS_LOCALS_1 = 2; - - /** "1": {@code op}; implies {@code max_locals >= 2} */ - public static final int FMT_NO_ARGS_LOCALS_2 = 3; - - /** "2": {@code op}; implies {@code max_locals >= 3} */ - public static final int FMT_NO_ARGS_LOCALS_3 = 4; - - /** "3": {@code op}; implies {@code max_locals >= 4} */ - public static final int FMT_NO_ARGS_LOCALS_4 = 5; - - /** "4": {@code op}; implies {@code max_locals >= 5} */ - public static final int FMT_NO_ARGS_LOCALS_5 = 6; - - /** "b": {@code op target target} */ - public static final int FMT_BRANCH = 7; - - /** "c": {@code op target target target target} */ - public static final int FMT_WIDE_BRANCH = 8; - - /** "p": {@code op #cpi #cpi}; constant restricted as specified */ - public static final int FMT_CPI = 9; - - /** - * "l": {@code op local}; category-1 local; implies - * {@code max_locals} is at least two more than the given - * local number - */ - public static final int FMT_LOCAL_1 = 10; - - /** - * "m": {@code op local}; category-2 local; implies - * {@code max_locals} is at least two more than the given - * local number - */ - public static final int FMT_LOCAL_2 = 11; - - /** - * "y": {@code op #byte} ({@code bipush} and - * {@code newarray}) - */ - public static final int FMT_LITERAL_BYTE = 12; - - /** "I": {@code invokeinterface cpi cpi count 0} */ - public static final int FMT_INVOKEINTERFACE = 13; - - /** "L": {@code ldc #cpi}; constant restricted as specified */ - public static final int FMT_LDC = 14; - - /** "S": {@code sipush #byte #byte} */ - public static final int FMT_SIPUSH = 15; - - /** "T": {@code tableswitch ...} */ - public static final int FMT_TABLESWITCH = 16; - - /** "U": {@code lookupswitch ...} */ - public static final int FMT_LOOKUPSWITCH = 17; - - /** "M": {@code multianewarray cpi cpi dims} */ - public static final int FMT_MULTIANEWARRAY = 18; - - /** "W": {@code wide ...} */ - public static final int FMT_WIDE = 19; - - /** mask for the bits representing the opcode format */ - public static final int FMT_MASK = 0x1f; - - /** "I": flag bit for valid cp type for {@code Integer} */ - public static final int CPOK_Integer = 0x20; - - /** "F": flag bit for valid cp type for {@code Float} */ - public static final int CPOK_Float = 0x40; - - /** "J": flag bit for valid cp type for {@code Long} */ - public static final int CPOK_Long = 0x80; - - /** "D": flag bit for valid cp type for {@code Double} */ - public static final int CPOK_Double = 0x100; - - /** "c": flag bit for valid cp type for {@code Class} */ - public static final int CPOK_Class = 0x200; - - /** "s": flag bit for valid cp type for {@code String} */ - public static final int CPOK_String = 0x400; - - /** "f": flag bit for valid cp type for {@code Fieldref} */ - public static final int CPOK_Fieldref = 0x800; - - /** "m": flag bit for valid cp type for {@code Methodref} */ - public static final int CPOK_Methodref = 0x1000; - - /** "i": flag bit for valid cp type for {@code InterfaceMethodref} */ - public static final int CPOK_InterfaceMethodref = 0x2000; - - /** - * {@code non-null;} map from opcodes to format or'ed with allowed constant - * pool types - */ - private static final int[] OPCODE_INFO = new int[256]; - - /** {@code non-null;} map from opcodes to their names */ - private static final String[] OPCODE_NAMES = new String[256]; - - /** {@code non-null;} bigass string describing all the opcodes */ - private static final String OPCODE_DETAILS = - "00 - nop;" + - "01 - aconst_null;" + - "02 - iconst_m1;" + - "03 - iconst_0;" + - "04 - iconst_1;" + - "05 - iconst_2;" + - "06 - iconst_3;" + - "07 - iconst_4;" + - "08 - iconst_5;" + - "09 - lconst_0;" + - "0a - lconst_1;" + - "0b - fconst_0;" + - "0c - fconst_1;" + - "0d - fconst_2;" + - "0e - dconst_0;" + - "0f - dconst_1;" + - "10 y bipush;" + - "11 S sipush;" + - "12 L:IFcs ldc;" + - "13 p:IFcs ldc_w;" + - "14 p:DJ ldc2_w;" + - "15 l iload;" + - "16 m lload;" + - "17 l fload;" + - "18 m dload;" + - "19 l aload;" + - "1a 0 iload_0;" + - "1b 1 iload_1;" + - "1c 2 iload_2;" + - "1d 3 iload_3;" + - "1e 1 lload_0;" + - "1f 2 lload_1;" + - "20 3 lload_2;" + - "21 4 lload_3;" + - "22 0 fload_0;" + - "23 1 fload_1;" + - "24 2 fload_2;" + - "25 3 fload_3;" + - "26 1 dload_0;" + - "27 2 dload_1;" + - "28 3 dload_2;" + - "29 4 dload_3;" + - "2a 0 aload_0;" + - "2b 1 aload_1;" + - "2c 2 aload_2;" + - "2d 3 aload_3;" + - "2e - iaload;" + - "2f - laload;" + - "30 - faload;" + - "31 - daload;" + - "32 - aaload;" + - "33 - baload;" + - "34 - caload;" + - "35 - saload;" + - "36 - istore;" + - "37 - lstore;" + - "38 - fstore;" + - "39 - dstore;" + - "3a - astore;" + - "3b 0 istore_0;" + - "3c 1 istore_1;" + - "3d 2 istore_2;" + - "3e 3 istore_3;" + - "3f 1 lstore_0;" + - "40 2 lstore_1;" + - "41 3 lstore_2;" + - "42 4 lstore_3;" + - "43 0 fstore_0;" + - "44 1 fstore_1;" + - "45 2 fstore_2;" + - "46 3 fstore_3;" + - "47 1 dstore_0;" + - "48 2 dstore_1;" + - "49 3 dstore_2;" + - "4a 4 dstore_3;" + - "4b 0 astore_0;" + - "4c 1 astore_1;" + - "4d 2 astore_2;" + - "4e 3 astore_3;" + - "4f - iastore;" + - "50 - lastore;" + - "51 - fastore;" + - "52 - dastore;" + - "53 - aastore;" + - "54 - bastore;" + - "55 - castore;" + - "56 - sastore;" + - "57 - pop;" + - "58 - pop2;" + - "59 - dup;" + - "5a - dup_x1;" + - "5b - dup_x2;" + - "5c - dup2;" + - "5d - dup2_x1;" + - "5e - dup2_x2;" + - "5f - swap;" + - "60 - iadd;" + - "61 - ladd;" + - "62 - fadd;" + - "63 - dadd;" + - "64 - isub;" + - "65 - lsub;" + - "66 - fsub;" + - "67 - dsub;" + - "68 - imul;" + - "69 - lmul;" + - "6a - fmul;" + - "6b - dmul;" + - "6c - idiv;" + - "6d - ldiv;" + - "6e - fdiv;" + - "6f - ddiv;" + - "70 - irem;" + - "71 - lrem;" + - "72 - frem;" + - "73 - drem;" + - "74 - ineg;" + - "75 - lneg;" + - "76 - fneg;" + - "77 - dneg;" + - "78 - ishl;" + - "79 - lshl;" + - "7a - ishr;" + - "7b - lshr;" + - "7c - iushr;" + - "7d - lushr;" + - "7e - iand;" + - "7f - land;" + - "80 - ior;" + - "81 - lor;" + - "82 - ixor;" + - "83 - lxor;" + - "84 l iinc;" + - "85 - i2l;" + - "86 - i2f;" + - "87 - i2d;" + - "88 - l2i;" + - "89 - l2f;" + - "8a - l2d;" + - "8b - f2i;" + - "8c - f2l;" + - "8d - f2d;" + - "8e - d2i;" + - "8f - d2l;" + - "90 - d2f;" + - "91 - i2b;" + - "92 - i2c;" + - "93 - i2s;" + - "94 - lcmp;" + - "95 - fcmpl;" + - "96 - fcmpg;" + - "97 - dcmpl;" + - "98 - dcmpg;" + - "99 b ifeq;" + - "9a b ifne;" + - "9b b iflt;" + - "9c b ifge;" + - "9d b ifgt;" + - "9e b ifle;" + - "9f b if_icmpeq;" + - "a0 b if_icmpne;" + - "a1 b if_icmplt;" + - "a2 b if_icmpge;" + - "a3 b if_icmpgt;" + - "a4 b if_icmple;" + - "a5 b if_acmpeq;" + - "a6 b if_acmpne;" + - "a7 b goto;" + - "a8 b jsr;" + - "a9 l ret;" + - "aa T tableswitch;" + - "ab U lookupswitch;" + - "ac - ireturn;" + - "ad - lreturn;" + - "ae - freturn;" + - "af - dreturn;" + - "b0 - areturn;" + - "b1 - return;" + - "b2 p:f getstatic;" + - "b3 p:f putstatic;" + - "b4 p:f getfield;" + - "b5 p:f putfield;" + - "b6 p:m invokevirtual;" + - "b7 p:m invokespecial;" + - "b8 p:m invokestatic;" + - "b9 I:i invokeinterface;" + - "bb p:c new;" + - "bc y newarray;" + - "bd p:c anewarray;" + - "be - arraylength;" + - "bf - athrow;" + - "c0 p:c checkcast;" + - "c1 p:c instanceof;" + - "c2 - monitorenter;" + - "c3 - monitorexit;" + - "c4 W wide;" + - "c5 M:c multianewarray;" + - "c6 b ifnull;" + - "c7 b ifnonnull;" + - "c8 c goto_w;" + - "c9 c jsr_w;"; - - static { - // Set up OPCODE_INFO and OPCODE_NAMES. - String s = OPCODE_DETAILS; - int len = s.length(); - - for (int i = 0; i < len; /*i*/) { - int idx = (Character.digit(s.charAt(i), 16) << 4) | - Character.digit(s.charAt(i + 1), 16); - int info; - switch (s.charAt(i + 3)) { - case '-': info = FMT_NO_ARGS; break; - case '0': info = FMT_NO_ARGS_LOCALS_1; break; - case '1': info = FMT_NO_ARGS_LOCALS_2; break; - case '2': info = FMT_NO_ARGS_LOCALS_3; break; - case '3': info = FMT_NO_ARGS_LOCALS_4; break; - case '4': info = FMT_NO_ARGS_LOCALS_5; break; - case 'b': info = FMT_BRANCH; break; - case 'c': info = FMT_WIDE_BRANCH; break; - case 'p': info = FMT_CPI; break; - case 'l': info = FMT_LOCAL_1; break; - case 'm': info = FMT_LOCAL_2; break; - case 'y': info = FMT_LITERAL_BYTE; break; - case 'I': info = FMT_INVOKEINTERFACE; break; - case 'L': info = FMT_LDC; break; - case 'S': info = FMT_SIPUSH; break; - case 'T': info = FMT_TABLESWITCH; break; - case 'U': info = FMT_LOOKUPSWITCH; break; - case 'M': info = FMT_MULTIANEWARRAY; break; - case 'W': info = FMT_WIDE; break; - default: info = FMT_INVALID; break; - } - - i += 5; - if (s.charAt(i - 1) == ':') { - inner: - for (;;) { - switch (s.charAt(i)) { - case 'I': info |= CPOK_Integer; break; - case 'F': info |= CPOK_Float; break; - case 'J': info |= CPOK_Long; break; - case 'D': info |= CPOK_Double; break; - case 'c': info |= CPOK_Class; break; - case 's': info |= CPOK_String; break; - case 'f': info |= CPOK_Fieldref; break; - case 'm': info |= CPOK_Methodref; break; - case 'i': info |= CPOK_InterfaceMethodref; break; - default: break inner; - } - i++; - } - i++; - } - - int endAt = s.indexOf(';', i); - OPCODE_INFO[idx] = info; - OPCODE_NAMES[idx] = s.substring(i, endAt); - i = endAt + 1; - } - } - - /** - * This class is uninstantiable. - */ - private ByteOps() { - // This space intentionally left blank. - } - - /** - * Gets the name of the given opcode. - * - * @param opcode {@code >= 0, <= 255;} the opcode - * @return {@code non-null;} its name - */ - public static String opName(int opcode) { - String result = OPCODE_NAMES[opcode]; - - if (result == null) { - result = "unused_" + Hex.u1(opcode); - OPCODE_NAMES[opcode] = result; - } - - return result; - } - - /** - * Gets the format and allowed cp types of the given opcode. - * - * @param opcode {@code >= 0, <= 255;} the opcode - * @return its format and allowed cp types - */ - public static int opInfo(int opcode) { - return OPCODE_INFO[opcode]; - } -} diff --git a/app/src/main/java/com/pojavdx/dx/cf/code/BytecodeArray.java b/app/src/main/java/com/pojavdx/dx/cf/code/BytecodeArray.java deleted file mode 100644 index 5b27ba602..000000000 --- a/app/src/main/java/com/pojavdx/dx/cf/code/BytecodeArray.java +++ /dev/null @@ -1,1439 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.pojavdx.dx.cf.code; - -import com.pojavdx.dx.rop.cst.Constant; -import com.pojavdx.dx.rop.cst.ConstantPool; -import com.pojavdx.dx.rop.cst.CstDouble; -import com.pojavdx.dx.rop.cst.CstFloat; -import com.pojavdx.dx.rop.cst.CstInteger; -import com.pojavdx.dx.rop.cst.CstInvokeDynamic; -import com.pojavdx.dx.rop.cst.CstKnownNull; -import com.pojavdx.dx.rop.cst.CstLiteralBits; -import com.pojavdx.dx.rop.cst.CstLong; -import com.pojavdx.dx.rop.cst.CstType; -import com.pojavdx.dx.rop.type.Type; -import com.pojavdx.dx.util.Bits; -import com.pojavdx.dx.util.ByteArray; -import com.pojavdx.dx.util.Hex; -import java.util.ArrayList; - -/** - * Bytecode array, which is part of a standard {@code Code} attribute. - */ -public final class BytecodeArray { - /** convenient no-op implementation of {@link Visitor} */ - public static final Visitor EMPTY_VISITOR = new BaseVisitor(); - - /** {@code non-null;} underlying bytes */ - private final ByteArray bytes; - - /** - * {@code non-null;} constant pool to use when resolving constant - * pool indices - */ - private final ConstantPool pool; - - /** - * Constructs an instance. - * - * @param bytes {@code non-null;} underlying bytes - * @param pool {@code non-null;} constant pool to use when - * resolving constant pool indices - */ - public BytecodeArray(ByteArray bytes, ConstantPool pool) { - if (bytes == null) { - throw new NullPointerException("bytes == null"); - } - - if (pool == null) { - throw new NullPointerException("pool == null"); - } - - this.bytes = bytes; - this.pool = pool; - } - - /** - * Gets the underlying byte array. - * - * @return {@code non-null;} the byte array - */ - public ByteArray getBytes() { - return bytes; - } - - /** - * Gets the size of the bytecode array, per se. - * - * @return {@code >= 0;} the length of the bytecode array - */ - public int size() { - return bytes.size(); - } - - /** - * Gets the total length of this structure in bytes, when included in - * a {@code Code} attribute. The returned value includes the - * array size plus four bytes for {@code code_length}. - * - * @return {@code >= 4;} the total length, in bytes - */ - public int byteLength() { - return 4 + bytes.size(); - } - - /** - * Parses each instruction in the array, in order. - * - * @param visitor {@code null-ok;} visitor to call back to for - * each instruction - */ - public void forEach(Visitor visitor) { - int sz = bytes.size(); - int at = 0; - - while (at < sz) { - /* - * Don't record the previous offset here, so that we get to see the - * raw code that initializes the array - */ - at += parseInstruction(at, visitor); - } - } - - /** - * Finds the offset to each instruction in the bytecode array. The - * result is a bit set with the offset of each opcode-per-se flipped on. - * - * @see Bits - * @return {@code non-null;} appropriately constructed bit set - */ - public int[] getInstructionOffsets() { - int sz = bytes.size(); - int[] result = Bits.makeBitSet(sz); - int at = 0; - - while (at < sz) { - Bits.set(result, at, true); - int length = parseInstruction(at, null); - at += length; - } - - return result; - } - - /** - * Processes the given "work set" by repeatedly finding the lowest bit - * in the set, clearing it, and parsing and visiting the instruction at - * the indicated offset (that is, the bit index), repeating until the - * work set is empty. It is expected that the visitor will regularly - * set new bits in the work set during the process. - * - * @param workSet {@code non-null;} the work set to process - * @param visitor {@code non-null;} visitor to call back to for - * each instruction - */ - public void processWorkSet(int[] workSet, Visitor visitor) { - if (visitor == null) { - throw new NullPointerException("visitor == null"); - } - - for (;;) { - int offset = Bits.findFirst(workSet, 0); - if (offset < 0) { - break; - } - Bits.clear(workSet, offset); - parseInstruction(offset, visitor); - visitor.setPreviousOffset(offset); - } - } - - /** - * Parses the instruction at the indicated offset. Indicate the - * result by calling the visitor if supplied and by returning the - * number of bytes consumed by the instruction. - * - *

In order to simplify further processing, the opcodes passed - * to the visitor are canonicalized, altering the opcode to a more - * universal one and making formerly implicit arguments - * explicit. In particular:

- * - *
    - *
  • The opcodes to push literal constants of primitive types all become - * {@code ldc}. - * E.g., {@code fconst_0}, {@code sipush}, and - * {@code lconst_0} qualify for this treatment.
  • - *
  • {@code aconst_null} becomes {@code ldc} of a - * "known null."
  • - *
  • Shorthand local variable accessors become the corresponding - * longhand. E.g. {@code aload_2} becomes {@code aload}.
  • - *
  • {@code goto_w} and {@code jsr_w} become {@code goto} - * and {@code jsr} (respectively).
  • - *
  • {@code ldc_w} becomes {@code ldc}.
  • - *
  • {@code tableswitch} becomes {@code lookupswitch}. - *
  • Arithmetic, array, and value-returning ops are collapsed - * to the {@code int} variant opcode, with the {@code type} - * argument set to indicate the actual type. E.g., - * {@code fadd} becomes {@code iadd}, but - * {@code type} is passed as {@code Type.FLOAT} in that - * case. Similarly, {@code areturn} becomes - * {@code ireturn}. (However, {@code return} remains - * unchanged.
  • - *
  • Local variable access ops are collapsed to the {@code int} - * variant opcode, with the {@code type} argument set to indicate - * the actual type. E.g., {@code aload} becomes {@code iload}, - * but {@code type} is passed as {@code Type.OBJECT} in - * that case.
  • - *
  • Numeric conversion ops ({@code i2l}, etc.) are left alone - * to avoid too much confustion, but their {@code type} is - * the pushed type. E.g., {@code i2b} gets type - * {@code Type.INT}, and {@code f2d} gets type - * {@code Type.DOUBLE}. Other unaltered opcodes also get - * their pushed type. E.g., {@code arraylength} gets type - * {@code Type.INT}.
  • - *
- * - * @param offset {@code >= 0, < bytes.size();} offset to the start of the - * instruction - * @param visitor {@code null-ok;} visitor to call back to - * @return the length of the instruction, in bytes - */ - public int parseInstruction(int offset, Visitor visitor) { - if (visitor == null) { - visitor = EMPTY_VISITOR; - } - - try { - int opcode = bytes.getUnsignedByte(offset); - int info = ByteOps.opInfo(opcode); - int fmt = info & ByteOps.FMT_MASK; - - switch (opcode) { - case ByteOps.NOP: { - visitor.visitNoArgs(opcode, offset, 1, Type.VOID); - return 1; - } - case ByteOps.ACONST_NULL: { - visitor.visitConstant(ByteOps.LDC, offset, 1, - CstKnownNull.THE_ONE, 0); - return 1; - } - case ByteOps.ICONST_M1: { - visitor.visitConstant(ByteOps.LDC, offset, 1, - CstInteger.VALUE_M1, -1); - return 1; - } - case ByteOps.ICONST_0: { - visitor.visitConstant(ByteOps.LDC, offset, 1, - CstInteger.VALUE_0, 0); - return 1; - } - case ByteOps.ICONST_1: { - visitor.visitConstant(ByteOps.LDC, offset, 1, - CstInteger.VALUE_1, 1); - return 1; - } - case ByteOps.ICONST_2: { - visitor.visitConstant(ByteOps.LDC, offset, 1, - CstInteger.VALUE_2, 2); - return 1; - } - case ByteOps.ICONST_3: { - visitor.visitConstant(ByteOps.LDC, offset, 1, - CstInteger.VALUE_3, 3); - return 1; - } - case ByteOps.ICONST_4: { - visitor.visitConstant(ByteOps.LDC, offset, 1, - CstInteger.VALUE_4, 4); - return 1; - } - case ByteOps.ICONST_5: { - visitor.visitConstant(ByteOps.LDC, offset, 1, - CstInteger.VALUE_5, 5); - return 1; - } - case ByteOps.LCONST_0: { - visitor.visitConstant(ByteOps.LDC, offset, 1, - CstLong.VALUE_0, 0); - return 1; - } - case ByteOps.LCONST_1: { - visitor.visitConstant(ByteOps.LDC, offset, 1, - CstLong.VALUE_1, 0); - return 1; - } - case ByteOps.FCONST_0: { - visitor.visitConstant(ByteOps.LDC, offset, 1, - CstFloat.VALUE_0, 0); - return 1; - } - case ByteOps.FCONST_1: { - visitor.visitConstant(ByteOps.LDC, offset, 1, - CstFloat.VALUE_1, 0); - return 1; - } - case ByteOps.FCONST_2: { - visitor.visitConstant(ByteOps.LDC, offset, 1, - CstFloat.VALUE_2, 0); - return 1; - } - case ByteOps.DCONST_0: { - visitor.visitConstant(ByteOps.LDC, offset, 1, - CstDouble.VALUE_0, 0); - return 1; - } - case ByteOps.DCONST_1: { - visitor.visitConstant(ByteOps.LDC, offset, 1, - CstDouble.VALUE_1, 0); - return 1; - } - case ByteOps.BIPUSH: { - int value = bytes.getByte(offset + 1); - visitor.visitConstant(ByteOps.LDC, offset, 2, - CstInteger.make(value), value); - return 2; - } - case ByteOps.SIPUSH: { - int value = bytes.getShort(offset + 1); - visitor.visitConstant(ByteOps.LDC, offset, 3, - CstInteger.make(value), value); - return 3; - } - case ByteOps.LDC: { - int idx = bytes.getUnsignedByte(offset + 1); - Constant cst = pool.get(idx); - int value = (cst instanceof CstInteger) ? - ((CstInteger) cst).getValue() : 0; - visitor.visitConstant(ByteOps.LDC, offset, 2, cst, value); - return 2; - } - case ByteOps.LDC_W: { - int idx = bytes.getUnsignedShort(offset + 1); - Constant cst = pool.get(idx); - int value = (cst instanceof CstInteger) ? - ((CstInteger) cst).getValue() : 0; - visitor.visitConstant(ByteOps.LDC, offset, 3, cst, value); - return 3; - } - case ByteOps.LDC2_W: { - int idx = bytes.getUnsignedShort(offset + 1); - Constant cst = pool.get(idx); - visitor.visitConstant(ByteOps.LDC2_W, offset, 3, cst, 0); - return 3; - } - case ByteOps.ILOAD: { - int idx = bytes.getUnsignedByte(offset + 1); - visitor.visitLocal(ByteOps.ILOAD, offset, 2, idx, - Type.INT, 0); - return 2; - } - case ByteOps.LLOAD: { - int idx = bytes.getUnsignedByte(offset + 1); - visitor.visitLocal(ByteOps.ILOAD, offset, 2, idx, - Type.LONG, 0); - return 2; - } - case ByteOps.FLOAD: { - int idx = bytes.getUnsignedByte(offset + 1); - visitor.visitLocal(ByteOps.ILOAD, offset, 2, idx, - Type.FLOAT, 0); - return 2; - } - case ByteOps.DLOAD: { - int idx = bytes.getUnsignedByte(offset + 1); - visitor.visitLocal(ByteOps.ILOAD, offset, 2, idx, - Type.DOUBLE, 0); - return 2; - } - case ByteOps.ALOAD: { - int idx = bytes.getUnsignedByte(offset + 1); - visitor.visitLocal(ByteOps.ILOAD, offset, 2, idx, - Type.OBJECT, 0); - return 2; - } - case ByteOps.ILOAD_0: - case ByteOps.ILOAD_1: - case ByteOps.ILOAD_2: - case ByteOps.ILOAD_3: { - int idx = opcode - ByteOps.ILOAD_0; - visitor.visitLocal(ByteOps.ILOAD, offset, 1, idx, - Type.INT, 0); - return 1; - } - case ByteOps.LLOAD_0: - case ByteOps.LLOAD_1: - case ByteOps.LLOAD_2: - case ByteOps.LLOAD_3: { - int idx = opcode - ByteOps.LLOAD_0; - visitor.visitLocal(ByteOps.ILOAD, offset, 1, idx, - Type.LONG, 0); - return 1; - } - case ByteOps.FLOAD_0: - case ByteOps.FLOAD_1: - case ByteOps.FLOAD_2: - case ByteOps.FLOAD_3: { - int idx = opcode - ByteOps.FLOAD_0; - visitor.visitLocal(ByteOps.ILOAD, offset, 1, idx, - Type.FLOAT, 0); - return 1; - } - case ByteOps.DLOAD_0: - case ByteOps.DLOAD_1: - case ByteOps.DLOAD_2: - case ByteOps.DLOAD_3: { - int idx = opcode - ByteOps.DLOAD_0; - visitor.visitLocal(ByteOps.ILOAD, offset, 1, idx, - Type.DOUBLE, 0); - return 1; - } - case ByteOps.ALOAD_0: - case ByteOps.ALOAD_1: - case ByteOps.ALOAD_2: - case ByteOps.ALOAD_3: { - int idx = opcode - ByteOps.ALOAD_0; - visitor.visitLocal(ByteOps.ILOAD, offset, 1, idx, - Type.OBJECT, 0); - return 1; - } - case ByteOps.IALOAD: { - visitor.visitNoArgs(ByteOps.IALOAD, offset, 1, Type.INT); - return 1; - } - case ByteOps.LALOAD: { - visitor.visitNoArgs(ByteOps.IALOAD, offset, 1, Type.LONG); - return 1; - } - case ByteOps.FALOAD: { - visitor.visitNoArgs(ByteOps.IALOAD, offset, 1, - Type.FLOAT); - return 1; - } - case ByteOps.DALOAD: { - visitor.visitNoArgs(ByteOps.IALOAD, offset, 1, - Type.DOUBLE); - return 1; - } - case ByteOps.AALOAD: { - visitor.visitNoArgs(ByteOps.IALOAD, offset, 1, - Type.OBJECT); - return 1; - } - case ByteOps.BALOAD: { - /* - * Note: This is a load from either a byte[] or a - * boolean[]. - */ - visitor.visitNoArgs(ByteOps.IALOAD, offset, 1, Type.BYTE); - return 1; - } - case ByteOps.CALOAD: { - visitor.visitNoArgs(ByteOps.IALOAD, offset, 1, Type.CHAR); - return 1; - } - case ByteOps.SALOAD: { - visitor.visitNoArgs(ByteOps.IALOAD, offset, 1, - Type.SHORT); - return 1; - } - case ByteOps.ISTORE: { - int idx = bytes.getUnsignedByte(offset + 1); - visitor.visitLocal(ByteOps.ISTORE, offset, 2, idx, - Type.INT, 0); - return 2; - } - case ByteOps.LSTORE: { - int idx = bytes.getUnsignedByte(offset + 1); - visitor.visitLocal(ByteOps.ISTORE, offset, 2, idx, - Type.LONG, 0); - return 2; - } - case ByteOps.FSTORE: { - int idx = bytes.getUnsignedByte(offset + 1); - visitor.visitLocal(ByteOps.ISTORE, offset, 2, idx, - Type.FLOAT, 0); - return 2; - } - case ByteOps.DSTORE: { - int idx = bytes.getUnsignedByte(offset + 1); - visitor.visitLocal(ByteOps.ISTORE, offset, 2, idx, - Type.DOUBLE, 0); - return 2; - } - case ByteOps.ASTORE: { - int idx = bytes.getUnsignedByte(offset + 1); - visitor.visitLocal(ByteOps.ISTORE, offset, 2, idx, - Type.OBJECT, 0); - return 2; - } - case ByteOps.ISTORE_0: - case ByteOps.ISTORE_1: - case ByteOps.ISTORE_2: - case ByteOps.ISTORE_3: { - int idx = opcode - ByteOps.ISTORE_0; - visitor.visitLocal(ByteOps.ISTORE, offset, 1, idx, - Type.INT, 0); - return 1; - } - case ByteOps.LSTORE_0: - case ByteOps.LSTORE_1: - case ByteOps.LSTORE_2: - case ByteOps.LSTORE_3: { - int idx = opcode - ByteOps.LSTORE_0; - visitor.visitLocal(ByteOps.ISTORE, offset, 1, idx, - Type.LONG, 0); - return 1; - } - case ByteOps.FSTORE_0: - case ByteOps.FSTORE_1: - case ByteOps.FSTORE_2: - case ByteOps.FSTORE_3: { - int idx = opcode - ByteOps.FSTORE_0; - visitor.visitLocal(ByteOps.ISTORE, offset, 1, idx, - Type.FLOAT, 0); - return 1; - } - case ByteOps.DSTORE_0: - case ByteOps.DSTORE_1: - case ByteOps.DSTORE_2: - case ByteOps.DSTORE_3: { - int idx = opcode - ByteOps.DSTORE_0; - visitor.visitLocal(ByteOps.ISTORE, offset, 1, idx, - Type.DOUBLE, 0); - return 1; - } - case ByteOps.ASTORE_0: - case ByteOps.ASTORE_1: - case ByteOps.ASTORE_2: - case ByteOps.ASTORE_3: { - int idx = opcode - ByteOps.ASTORE_0; - visitor.visitLocal(ByteOps.ISTORE, offset, 1, idx, - Type.OBJECT, 0); - return 1; - } - case ByteOps.IASTORE: { - visitor.visitNoArgs(ByteOps.IASTORE, offset, 1, Type.INT); - return 1; - } - case ByteOps.LASTORE: { - visitor.visitNoArgs(ByteOps.IASTORE, offset, 1, - Type.LONG); - return 1; - } - case ByteOps.FASTORE: { - visitor.visitNoArgs(ByteOps.IASTORE, offset, 1, - Type.FLOAT); - return 1; - } - case ByteOps.DASTORE: { - visitor.visitNoArgs(ByteOps.IASTORE, offset, 1, - Type.DOUBLE); - return 1; - } - case ByteOps.AASTORE: { - visitor.visitNoArgs(ByteOps.IASTORE, offset, 1, - Type.OBJECT); - return 1; - } - case ByteOps.BASTORE: { - /* - * Note: This is a load from either a byte[] or a - * boolean[]. - */ - visitor.visitNoArgs(ByteOps.IASTORE, offset, 1, - Type.BYTE); - return 1; - } - case ByteOps.CASTORE: { - visitor.visitNoArgs(ByteOps.IASTORE, offset, 1, - Type.CHAR); - return 1; - } - case ByteOps.SASTORE: { - visitor.visitNoArgs(ByteOps.IASTORE, offset, 1, - Type.SHORT); - return 1; - } - case ByteOps.POP: - case ByteOps.POP2: - case ByteOps.DUP: - case ByteOps.DUP_X1: - case ByteOps.DUP_X2: - case ByteOps.DUP2: - case ByteOps.DUP2_X1: - case ByteOps.DUP2_X2: - case ByteOps.SWAP: { - visitor.visitNoArgs(opcode, offset, 1, Type.VOID); - return 1; - } - case ByteOps.IADD: - case ByteOps.ISUB: - case ByteOps.IMUL: - case ByteOps.IDIV: - case ByteOps.IREM: - case ByteOps.INEG: - case ByteOps.ISHL: - case ByteOps.ISHR: - case ByteOps.IUSHR: - case ByteOps.IAND: - case ByteOps.IOR: - case ByteOps.IXOR: { - visitor.visitNoArgs(opcode, offset, 1, Type.INT); - return 1; - } - case ByteOps.LADD: - case ByteOps.LSUB: - case ByteOps.LMUL: - case ByteOps.LDIV: - case ByteOps.LREM: - case ByteOps.LNEG: - case ByteOps.LSHL: - case ByteOps.LSHR: - case ByteOps.LUSHR: - case ByteOps.LAND: - case ByteOps.LOR: - case ByteOps.LXOR: { - /* - * It's "opcode - 1" because, conveniently enough, all - * these long ops are one past the int variants. - */ - visitor.visitNoArgs(opcode - 1, offset, 1, Type.LONG); - return 1; - } - case ByteOps.FADD: - case ByteOps.FSUB: - case ByteOps.FMUL: - case ByteOps.FDIV: - case ByteOps.FREM: - case ByteOps.FNEG: { - /* - * It's "opcode - 2" because, conveniently enough, all - * these float ops are two past the int variants. - */ - visitor.visitNoArgs(opcode - 2, offset, 1, Type.FLOAT); - return 1; - } - case ByteOps.DADD: - case ByteOps.DSUB: - case ByteOps.DMUL: - case ByteOps.DDIV: - case ByteOps.DREM: - case ByteOps.DNEG: { - /* - * It's "opcode - 3" because, conveniently enough, all - * these double ops are three past the int variants. - */ - visitor.visitNoArgs(opcode - 3, offset, 1, Type.DOUBLE); - return 1; - } - case ByteOps.IINC: { - int idx = bytes.getUnsignedByte(offset + 1); - int value = bytes.getByte(offset + 2); - visitor.visitLocal(opcode, offset, 3, idx, - Type.INT, value); - return 3; - } - case ByteOps.I2L: - case ByteOps.F2L: - case ByteOps.D2L: { - visitor.visitNoArgs(opcode, offset, 1, Type.LONG); - return 1; - } - case ByteOps.I2F: - case ByteOps.L2F: - case ByteOps.D2F: { - visitor.visitNoArgs(opcode, offset, 1, Type.FLOAT); - return 1; - } - case ByteOps.I2D: - case ByteOps.L2D: - case ByteOps.F2D: { - visitor.visitNoArgs(opcode, offset, 1, Type.DOUBLE); - return 1; - } - case ByteOps.L2I: - case ByteOps.F2I: - case ByteOps.D2I: - case ByteOps.I2B: - case ByteOps.I2C: - case ByteOps.I2S: - case ByteOps.LCMP: - case ByteOps.FCMPL: - case ByteOps.FCMPG: - case ByteOps.DCMPL: - case ByteOps.DCMPG: - case ByteOps.ARRAYLENGTH: { - visitor.visitNoArgs(opcode, offset, 1, Type.INT); - return 1; - } - case ByteOps.IFEQ: - case ByteOps.IFNE: - case ByteOps.IFLT: - case ByteOps.IFGE: - case ByteOps.IFGT: - case ByteOps.IFLE: - case ByteOps.IF_ICMPEQ: - case ByteOps.IF_ICMPNE: - case ByteOps.IF_ICMPLT: - case ByteOps.IF_ICMPGE: - case ByteOps.IF_ICMPGT: - case ByteOps.IF_ICMPLE: - case ByteOps.IF_ACMPEQ: - case ByteOps.IF_ACMPNE: - case ByteOps.GOTO: - case ByteOps.JSR: - case ByteOps.IFNULL: - case ByteOps.IFNONNULL: { - int target = offset + bytes.getShort(offset + 1); - visitor.visitBranch(opcode, offset, 3, target); - return 3; - } - case ByteOps.RET: { - int idx = bytes.getUnsignedByte(offset + 1); - visitor.visitLocal(opcode, offset, 2, idx, - Type.RETURN_ADDRESS, 0); - return 2; - } - case ByteOps.TABLESWITCH: { - return parseTableswitch(offset, visitor); - } - case ByteOps.LOOKUPSWITCH: { - return parseLookupswitch(offset, visitor); - } - case ByteOps.IRETURN: { - visitor.visitNoArgs(ByteOps.IRETURN, offset, 1, Type.INT); - return 1; - } - case ByteOps.LRETURN: { - visitor.visitNoArgs(ByteOps.IRETURN, offset, 1, - Type.LONG); - return 1; - } - case ByteOps.FRETURN: { - visitor.visitNoArgs(ByteOps.IRETURN, offset, 1, - Type.FLOAT); - return 1; - } - case ByteOps.DRETURN: { - visitor.visitNoArgs(ByteOps.IRETURN, offset, 1, - Type.DOUBLE); - return 1; - } - case ByteOps.ARETURN: { - visitor.visitNoArgs(ByteOps.IRETURN, offset, 1, - Type.OBJECT); - return 1; - } - case ByteOps.RETURN: - case ByteOps.ATHROW: - case ByteOps.MONITORENTER: - case ByteOps.MONITOREXIT: { - visitor.visitNoArgs(opcode, offset, 1, Type.VOID); - return 1; - } - case ByteOps.GETSTATIC: - case ByteOps.PUTSTATIC: - case ByteOps.GETFIELD: - case ByteOps.PUTFIELD: - case ByteOps.INVOKEVIRTUAL: - case ByteOps.INVOKESPECIAL: - case ByteOps.INVOKESTATIC: - case ByteOps.NEW: - case ByteOps.ANEWARRAY: - case ByteOps.CHECKCAST: - case ByteOps.INSTANCEOF: { - int idx = bytes.getUnsignedShort(offset + 1); - Constant cst = pool.get(idx); - visitor.visitConstant(opcode, offset, 3, cst, 0); - return 3; - } - case ByteOps.INVOKEINTERFACE: { - int idx = bytes.getUnsignedShort(offset + 1); - int count = bytes.getUnsignedByte(offset + 3); - int expectZero = bytes.getUnsignedByte(offset + 4); - Constant cst = pool.get(idx); - visitor.visitConstant(opcode, offset, 5, cst, - count | (expectZero << 8)); - return 5; - } - case ByteOps.INVOKEDYNAMIC: { - int idx = bytes.getUnsignedShort(offset + 1); - // Skip to must-be-zero bytes at offsets 3 and 4 - CstInvokeDynamic cstInvokeDynamic = (CstInvokeDynamic) pool.get(idx); - visitor.visitConstant(opcode, offset, 5, cstInvokeDynamic, 0); - return 5; - } - case ByteOps.NEWARRAY: { - return parseNewarray(offset, visitor); - } - case ByteOps.WIDE: { - return parseWide(offset, visitor); - } - case ByteOps.MULTIANEWARRAY: { - int idx = bytes.getUnsignedShort(offset + 1); - int dimensions = bytes.getUnsignedByte(offset + 3); - Constant cst = pool.get(idx); - visitor.visitConstant(opcode, offset, 4, cst, dimensions); - return 4; - } - case ByteOps.GOTO_W: - case ByteOps.JSR_W: { - int target = offset + bytes.getInt(offset + 1); - int newop = - (opcode == ByteOps.GOTO_W) ? ByteOps.GOTO : - ByteOps.JSR; - visitor.visitBranch(newop, offset, 5, target); - return 5; - } - default: { - visitor.visitInvalid(opcode, offset, 1); - return 1; - } - } - } catch (SimException ex) { - ex.addContext("...at bytecode offset " + Hex.u4(offset)); - throw ex; - } catch (RuntimeException ex) { - SimException se = new SimException(ex); - se.addContext("...at bytecode offset " + Hex.u4(offset)); - throw se; - } - } - - /** - * Helper to deal with {@code tableswitch}. - * - * @param offset the offset to the {@code tableswitch} opcode itself - * @param visitor {@code non-null;} visitor to use - * @return instruction length, in bytes - */ - private int parseTableswitch(int offset, Visitor visitor) { - int at = (offset + 4) & ~3; // "at" skips the padding. - - // Collect the padding. - int padding = 0; - for (int i = offset + 1; i < at; i++) { - padding = (padding << 8) | bytes.getUnsignedByte(i); - } - - int defaultTarget = offset + bytes.getInt(at); - int low = bytes.getInt(at + 4); - int high = bytes.getInt(at + 8); - int count = high - low + 1; - at += 12; - - if (low > high) { - throw new SimException("low / high inversion"); - } - - SwitchList cases = new SwitchList(count); - for (int i = 0; i < count; i++) { - int target = offset + bytes.getInt(at); - at += 4; - cases.add(low + i, target); - } - cases.setDefaultTarget(defaultTarget); - cases.removeSuperfluousDefaults(); - cases.setImmutable(); - - int length = at - offset; - visitor.visitSwitch(ByteOps.LOOKUPSWITCH, offset, length, cases, - padding); - - return length; - } - - /** - * Helper to deal with {@code lookupswitch}. - * - * @param offset the offset to the {@code lookupswitch} opcode itself - * @param visitor {@code non-null;} visitor to use - * @return instruction length, in bytes - */ - private int parseLookupswitch(int offset, Visitor visitor) { - int at = (offset + 4) & ~3; // "at" skips the padding. - - // Collect the padding. - int padding = 0; - for (int i = offset + 1; i < at; i++) { - padding = (padding << 8) | bytes.getUnsignedByte(i); - } - - int defaultTarget = offset + bytes.getInt(at); - int npairs = bytes.getInt(at + 4); - at += 8; - - SwitchList cases = new SwitchList(npairs); - for (int i = 0; i < npairs; i++) { - int match = bytes.getInt(at); - int target = offset + bytes.getInt(at + 4); - at += 8; - cases.add(match, target); - } - cases.setDefaultTarget(defaultTarget); - cases.removeSuperfluousDefaults(); - cases.setImmutable(); - - int length = at - offset; - visitor.visitSwitch(ByteOps.LOOKUPSWITCH, offset, length, cases, - padding); - - return length; - } - - /** - * Helper to deal with {@code newarray}. - * - * @param offset the offset to the {@code newarray} opcode itself - * @param visitor {@code non-null;} visitor to use - * @return instruction length, in bytes - */ - private int parseNewarray(int offset, Visitor visitor) { - int value = bytes.getUnsignedByte(offset + 1); - CstType type; - switch (value) { - case ByteOps.NEWARRAY_BOOLEAN: { - type = CstType.BOOLEAN_ARRAY; - break; - } - case ByteOps.NEWARRAY_CHAR: { - type = CstType.CHAR_ARRAY; - break; - } - case ByteOps.NEWARRAY_DOUBLE: { - type = CstType.DOUBLE_ARRAY; - break; - } - case ByteOps.NEWARRAY_FLOAT: { - type = CstType.FLOAT_ARRAY; - break; - } - case ByteOps.NEWARRAY_BYTE: { - type = CstType.BYTE_ARRAY; - break; - } - case ByteOps.NEWARRAY_SHORT: { - type = CstType.SHORT_ARRAY; - break; - } - case ByteOps.NEWARRAY_INT: { - type = CstType.INT_ARRAY; - break; - } - case ByteOps.NEWARRAY_LONG: { - type = CstType.LONG_ARRAY; - break; - } - default: { - throw new SimException("bad newarray code " + - Hex.u1(value)); - } - } - - // Revisit the previous bytecode to find out the length of the array - int previousOffset = visitor.getPreviousOffset(); - ConstantParserVisitor constantVisitor = new ConstantParserVisitor(); - int arrayLength = 0; - - /* - * For visitors that don't record the previous offset, -1 will be - * seen here - */ - if (previousOffset >= 0) { - parseInstruction(previousOffset, constantVisitor); - if (constantVisitor.cst instanceof CstInteger && - constantVisitor.length + previousOffset == offset) { - arrayLength = constantVisitor.value; - - } - } - - /* - * Try to match the array initialization idiom. For example, if the - * subsequent code is initializing an int array, we are expecting the - * following pattern repeatedly: - * dup - * push index - * push value - * *astore - * - * where the index value will be incrimented sequentially from 0 up. - */ - int nInit = 0; - int curOffset = offset+2; - int lastOffset = curOffset; - ArrayList initVals = new ArrayList(); - - if (arrayLength != 0) { - while (true) { - boolean punt = false; - - // First, check if the next bytecode is dup. - int nextByte = bytes.getUnsignedByte(curOffset++); - if (nextByte != ByteOps.DUP) - break; - - /* - * Next, check if the expected array index is pushed to - * the stack. - */ - parseInstruction(curOffset, constantVisitor); - if (constantVisitor.length == 0 || - !(constantVisitor.cst instanceof CstInteger) || - constantVisitor.value != nInit) - break; - - // Next, fetch the init value and record it. - curOffset += constantVisitor.length; - - /* - * Next, find out what kind of constant is pushed onto - * the stack. - */ - parseInstruction(curOffset, constantVisitor); - if (constantVisitor.length == 0 || - !(constantVisitor.cst instanceof CstLiteralBits)) - break; - - curOffset += constantVisitor.length; - initVals.add(constantVisitor.cst); - - nextByte = bytes.getUnsignedByte(curOffset++); - // Now, check if the value is stored to the array properly. - switch (value) { - case ByteOps.NEWARRAY_BYTE: - case ByteOps.NEWARRAY_BOOLEAN: { - if (nextByte != ByteOps.BASTORE) { - punt = true; - } - break; - } - case ByteOps.NEWARRAY_CHAR: { - if (nextByte != ByteOps.CASTORE) { - punt = true; - } - break; - } - case ByteOps.NEWARRAY_DOUBLE: { - if (nextByte != ByteOps.DASTORE) { - punt = true; - } - break; - } - case ByteOps.NEWARRAY_FLOAT: { - if (nextByte != ByteOps.FASTORE) { - punt = true; - } - break; - } - case ByteOps.NEWARRAY_SHORT: { - if (nextByte != ByteOps.SASTORE) { - punt = true; - } - break; - } - case ByteOps.NEWARRAY_INT: { - if (nextByte != ByteOps.IASTORE) { - punt = true; - } - break; - } - case ByteOps.NEWARRAY_LONG: { - if (nextByte != ByteOps.LASTORE) { - punt = true; - } - break; - } - default: - punt = true; - break; - } - if (punt) { - break; - } - lastOffset = curOffset; - nInit++; - } - } - - /* - * For singleton arrays it is still more economical to - * generate the aput. - */ - if (nInit < 2 || nInit != arrayLength) { - visitor.visitNewarray(offset, 2, type, null); - return 2; - } else { - visitor.visitNewarray(offset, lastOffset - offset, type, initVals); - return lastOffset - offset; - } - } - - - /** - * Helper to deal with {@code wide}. - * - * @param offset the offset to the {@code wide} opcode itself - * @param visitor {@code non-null;} visitor to use - * @return instruction length, in bytes - */ - private int parseWide(int offset, Visitor visitor) { - int opcode = bytes.getUnsignedByte(offset + 1); - int idx = bytes.getUnsignedShort(offset + 2); - switch (opcode) { - case ByteOps.ILOAD: { - visitor.visitLocal(ByteOps.ILOAD, offset, 4, idx, - Type.INT, 0); - return 4; - } - case ByteOps.LLOAD: { - visitor.visitLocal(ByteOps.ILOAD, offset, 4, idx, - Type.LONG, 0); - return 4; - } - case ByteOps.FLOAD: { - visitor.visitLocal(ByteOps.ILOAD, offset, 4, idx, - Type.FLOAT, 0); - return 4; - } - case ByteOps.DLOAD: { - visitor.visitLocal(ByteOps.ILOAD, offset, 4, idx, - Type.DOUBLE, 0); - return 4; - } - case ByteOps.ALOAD: { - visitor.visitLocal(ByteOps.ILOAD, offset, 4, idx, - Type.OBJECT, 0); - return 4; - } - case ByteOps.ISTORE: { - visitor.visitLocal(ByteOps.ISTORE, offset, 4, idx, - Type.INT, 0); - return 4; - } - case ByteOps.LSTORE: { - visitor.visitLocal(ByteOps.ISTORE, offset, 4, idx, - Type.LONG, 0); - return 4; - } - case ByteOps.FSTORE: { - visitor.visitLocal(ByteOps.ISTORE, offset, 4, idx, - Type.FLOAT, 0); - return 4; - } - case ByteOps.DSTORE: { - visitor.visitLocal(ByteOps.ISTORE, offset, 4, idx, - Type.DOUBLE, 0); - return 4; - } - case ByteOps.ASTORE: { - visitor.visitLocal(ByteOps.ISTORE, offset, 4, idx, - Type.OBJECT, 0); - return 4; - } - case ByteOps.RET: { - visitor.visitLocal(opcode, offset, 4, idx, - Type.RETURN_ADDRESS, 0); - return 4; - } - case ByteOps.IINC: { - int value = bytes.getShort(offset + 4); - visitor.visitLocal(opcode, offset, 6, idx, - Type.INT, value); - return 6; - } - default: { - visitor.visitInvalid(ByteOps.WIDE, offset, 1); - return 1; - } - } - } - - /** - * Instruction visitor interface. - */ - public interface Visitor { - /** - * Visits an invalid instruction. - * - * @param opcode the opcode - * @param offset offset to the instruction - * @param length length of the instruction, in bytes - */ - public void visitInvalid(int opcode, int offset, int length); - - /** - * Visits an instruction which has no inline arguments - * (implicit or explicit). - * - * @param opcode the opcode - * @param offset offset to the instruction - * @param length length of the instruction, in bytes - * @param type {@code non-null;} type the instruction operates on - */ - public void visitNoArgs(int opcode, int offset, int length, - Type type); - - /** - * Visits an instruction which has a local variable index argument. - * - * @param opcode the opcode - * @param offset offset to the instruction - * @param length length of the instruction, in bytes - * @param idx the local variable index - * @param type {@code non-null;} the type of the accessed value - * @param value additional literal integer argument, if salient (i.e., - * for {@code iinc}) - */ - public void visitLocal(int opcode, int offset, int length, - int idx, Type type, int value); - - /** - * Visits an instruction which has a (possibly synthetic) - * constant argument, and possibly also an - * additional literal integer argument. In the case of - * {@code multianewarray}, the argument is the count of - * dimensions. In the case of {@code invokeinterface}, - * the argument is the parameter count or'ed with the - * should-be-zero value left-shifted by 8. In the case of entries - * of type {@code int}, the {@code value} field always - * holds the raw value (for convenience of clients). - * - *

Note: In order to avoid giving it a barely-useful - * visitor all its own, {@code newarray} also uses this - * form, passing {@code value} as the array type code and - * {@code cst} as a {@link CstType} instance - * corresponding to the array type.

- * - * @param opcode the opcode - * @param offset offset to the instruction - * @param length length of the instruction, in bytes - * @param cst {@code non-null;} the constant - * @param value additional literal integer argument, if salient - * (ignore if not) - */ - public void visitConstant(int opcode, int offset, int length, - Constant cst, int value); - - /** - * Visits an instruction which has a branch target argument. - * - * @param opcode the opcode - * @param offset offset to the instruction - * @param length length of the instruction, in bytes - * @param target the absolute (not relative) branch target - */ - public void visitBranch(int opcode, int offset, int length, - int target); - - /** - * Visits a switch instruction. - * - * @param opcode the opcode - * @param offset offset to the instruction - * @param length length of the instruction, in bytes - * @param cases {@code non-null;} list of (value, target) - * pairs, plus the default target - * @param padding the bytes found in the padding area (if any), - * packed - */ - public void visitSwitch(int opcode, int offset, int length, - SwitchList cases, int padding); - - /** - * Visits a newarray instruction. - * - * @param offset offset to the instruction - * @param length length of the instruction, in bytes - * @param type {@code non-null;} the type of the array - * @param initVals {@code non-null;} list of bytecode offsets - * for init values - */ - public void visitNewarray(int offset, int length, CstType type, - ArrayList initVals); - - /** - * Set previous bytecode offset - * @param offset offset of the previous fully parsed bytecode - */ - public void setPreviousOffset(int offset); - - /** - * Get previous bytecode offset - * @return return the recored offset of the previous bytecode - */ - public int getPreviousOffset(); - } - - /** - * Base implementation of {@link Visitor}, which has empty method - * bodies for all methods. - */ - public static class BaseVisitor implements Visitor { - - /** offset of the previously parsed bytecode */ - private int previousOffset; - - BaseVisitor() { - previousOffset = -1; - } - - /** {@inheritDoc} */ - @Override - public void visitInvalid(int opcode, int offset, int length) { - // This space intentionally left blank. - } - - /** {@inheritDoc} */ - @Override - public void visitNoArgs(int opcode, int offset, int length, - Type type) { - // This space intentionally left blank. - } - - /** {@inheritDoc} */ - @Override - public void visitLocal(int opcode, int offset, int length, - int idx, Type type, int value) { - // This space intentionally left blank. - } - - /** {@inheritDoc} */ - @Override - public void visitConstant(int opcode, int offset, int length, - Constant cst, int value) { - // This space intentionally left blank. - } - - /** {@inheritDoc} */ - @Override - public void visitBranch(int opcode, int offset, int length, - int target) { - // This space intentionally left blank. - } - - /** {@inheritDoc} */ - @Override - public void visitSwitch(int opcode, int offset, int length, - SwitchList cases, int padding) { - // This space intentionally left blank. - } - - /** {@inheritDoc} */ - @Override - public void visitNewarray(int offset, int length, CstType type, - ArrayList initValues) { - // This space intentionally left blank. - } - - /** {@inheritDoc} */ - @Override - public void setPreviousOffset(int offset) { - previousOffset = offset; - } - - /** {@inheritDoc} */ - @Override - public int getPreviousOffset() { - return previousOffset; - } - } - - /** - * Implementation of {@link Visitor}, which just pays attention - * to constant values. - */ - class ConstantParserVisitor extends BaseVisitor { - Constant cst; - int length; - int value; - - /** Empty constructor */ - ConstantParserVisitor() { - } - - private void clear() { - length = 0; - } - - /** {@inheritDoc} */ - @Override - public void visitInvalid(int opcode, int offset, int length) { - clear(); - } - - /** {@inheritDoc} */ - @Override - public void visitNoArgs(int opcode, int offset, int length, - Type type) { - clear(); - } - - /** {@inheritDoc} */ - @Override - public void visitLocal(int opcode, int offset, int length, - int idx, Type type, int value) { - clear(); - } - - /** {@inheritDoc} */ - @Override - public void visitConstant(int opcode, int offset, int length, - Constant cst, int value) { - this.cst = cst; - this.length = length; - this.value = value; - } - - /** {@inheritDoc} */ - @Override - public void visitBranch(int opcode, int offset, int length, - int target) { - clear(); - } - - /** {@inheritDoc} */ - @Override - public void visitSwitch(int opcode, int offset, int length, - SwitchList cases, int padding) { - clear(); - } - - /** {@inheritDoc} */ - @Override - public void visitNewarray(int offset, int length, CstType type, - ArrayList initVals) { - clear(); - } - - /** {@inheritDoc} */ - @Override - public void setPreviousOffset(int offset) { - // Intentionally left empty - } - - /** {@inheritDoc} */ - @Override - public int getPreviousOffset() { - // Intentionally left empty - return -1; - } - } -} diff --git a/app/src/main/java/com/pojavdx/dx/cf/code/ConcreteMethod.java b/app/src/main/java/com/pojavdx/dx/cf/code/ConcreteMethod.java deleted file mode 100644 index 63f807db9..000000000 --- a/app/src/main/java/com/pojavdx/dx/cf/code/ConcreteMethod.java +++ /dev/null @@ -1,260 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.pojavdx.dx.cf.code; - -import com.pojavdx.dx.cf.attrib.AttCode; -import com.pojavdx.dx.cf.attrib.AttLineNumberTable; -import com.pojavdx.dx.cf.attrib.AttLocalVariableTable; -import com.pojavdx.dx.cf.attrib.AttLocalVariableTypeTable; -import com.pojavdx.dx.cf.iface.AttributeList; -import com.pojavdx.dx.cf.iface.ClassFile; -import com.pojavdx.dx.cf.iface.Method; -import com.pojavdx.dx.rop.code.AccessFlags; -import com.pojavdx.dx.rop.code.SourcePosition; -import com.pojavdx.dx.rop.cst.CstNat; -import com.pojavdx.dx.rop.cst.CstString; -import com.pojavdx.dx.rop.cst.CstType; -import com.pojavdx.dx.rop.type.Prototype; - -/** - * Container for all the giblets that make up a concrete Java bytecode method. - * It implements {@link Method}, so it provides all the original access - * (by delegation), but it also constructs and keeps useful versions of - * stuff extracted from the method's {@code Code} attribute. - */ -public final class ConcreteMethod implements Method { - /** {@code non-null;} method being wrapped */ - private final Method method; - - /** {@code non-null;} the {@code ClassFile} the method belongs to. */ - private final ClassFile classFile; - - /** {@code non-null;} the code attribute */ - private final AttCode attCode; - - /** {@code non-null;} line number list */ - private final LineNumberList lineNumbers; - - /** {@code non-null;} local variable list */ - private final LocalVariableList localVariables; - - /** - * Constructs an instance. - * - * @param method {@code non-null;} the method to be based on - * @param classFile {@code non-null;} the class file that contains this method - * @param keepLines whether to keep the line number information - * (if any) - * @param keepLocals whether to keep the local variable - * information (if any) - */ - public ConcreteMethod(Method method, ClassFile classFile, - boolean keepLines, boolean keepLocals) { - this.method = method; - this.classFile = classFile; - - AttributeList attribs = method.getAttributes(); - this.attCode = (AttCode) attribs.findFirst(AttCode.ATTRIBUTE_NAME); - - AttributeList codeAttribs = attCode.getAttributes(); - - /* - * Combine all LineNumberTable attributes into one, with the - * combined result saved into the instance. The following code - * isn't particularly efficient for doing merges, but as far - * as I know, this situation rarely occurs "in the - * wild," so there's not much point in optimizing for it. - */ - LineNumberList lnl = LineNumberList.EMPTY; - if (keepLines) { - for (AttLineNumberTable lnt = (AttLineNumberTable) - codeAttribs.findFirst(AttLineNumberTable.ATTRIBUTE_NAME); - lnt != null; - lnt = (AttLineNumberTable) codeAttribs.findNext(lnt)) { - lnl = LineNumberList.concat(lnl, lnt.getLineNumbers()); - } - } - this.lineNumbers = lnl; - - LocalVariableList lvl = LocalVariableList.EMPTY; - if (keepLocals) { - /* - * Do likewise (and with the same caveat) for - * LocalVariableTable and LocalVariableTypeTable attributes. - * This combines both of these kinds of attribute into a - * single LocalVariableList. - */ - for (AttLocalVariableTable lvt = (AttLocalVariableTable) - codeAttribs.findFirst( - AttLocalVariableTable.ATTRIBUTE_NAME); - lvt != null; - lvt = (AttLocalVariableTable) codeAttribs.findNext(lvt)) { - - lvl = LocalVariableList.concat(lvl, lvt.getLocalVariables()); - } - - LocalVariableList typeList = LocalVariableList.EMPTY; - for (AttLocalVariableTypeTable lvtt = (AttLocalVariableTypeTable) - codeAttribs.findFirst( - AttLocalVariableTypeTable.ATTRIBUTE_NAME); - lvtt != null; - lvtt = (AttLocalVariableTypeTable) codeAttribs.findNext(lvtt)) { - typeList = LocalVariableList.concat(typeList, lvtt.getLocalVariables()); - } - - if (typeList.size() != 0) { - - lvl = LocalVariableList.mergeDescriptorsAndSignatures(lvl, typeList); - } - } - this.localVariables = lvl; - } - - - /** - * Gets the source file associated with the method if known. - * @return {null-ok;} the source file defining the method if known, null otherwise. - */ - public CstString getSourceFile() { - return classFile.getSourceFile(); - } - - /** - * Tests whether the method is being defined on an interface. - * @return true if the method is being defined on an interface. - */ - public final boolean isDefaultOrStaticInterfaceMethod() { - return (classFile.getAccessFlags() & AccessFlags.ACC_INTERFACE) != 0 - && !getNat().isClassInit(); - } - - /** - * Tests whether the method is being defined is declared as static. - * @return true if the method is being defined is declared as static. - */ - public final boolean isStaticMethod() { - return (getAccessFlags() & AccessFlags.ACC_STATIC) != 0; - } - - /** {@inheritDoc} */ - @Override - public CstNat getNat() { - return method.getNat(); - } - - /** {@inheritDoc} */ - @Override - public CstString getName() { - return method.getName(); - } - - /** {@inheritDoc} */ - @Override - public CstString getDescriptor() { - return method.getDescriptor(); - } - - /** {@inheritDoc} */ - @Override - public int getAccessFlags() { - return method.getAccessFlags(); - } - - /** {@inheritDoc} */ - @Override - public AttributeList getAttributes() { - return method.getAttributes(); - } - - /** {@inheritDoc} */ - @Override - public CstType getDefiningClass() { - return method.getDefiningClass(); - } - - /** {@inheritDoc} */ - @Override - public Prototype getEffectiveDescriptor() { - return method.getEffectiveDescriptor(); - } - - /** - * Gets the maximum stack size. - * - * @return {@code >= 0;} the maximum stack size - */ - public int getMaxStack() { - return attCode.getMaxStack(); - } - - /** - * Gets the number of locals. - * - * @return {@code >= 0;} the number of locals - */ - public int getMaxLocals() { - return attCode.getMaxLocals(); - } - - /** - * Gets the bytecode array. - * - * @return {@code non-null;} the bytecode array - */ - public BytecodeArray getCode() { - return attCode.getCode(); - } - - /** - * Gets the exception table. - * - * @return {@code non-null;} the exception table - */ - public ByteCatchList getCatches() { - return attCode.getCatches(); - } - - /** - * Gets the line number list. - * - * @return {@code non-null;} the line number list - */ - public LineNumberList getLineNumbers() { - return lineNumbers; - } - - /** - * Gets the local variable list. - * - * @return {@code non-null;} the local variable list - */ - public LocalVariableList getLocalVariables() { - return localVariables; - } - - /** - * Returns a {@link SourcePosition} instance corresponding to the - * given bytecode offset. - * - * @param offset {@code >= 0;} the bytecode offset - * @return {@code non-null;} an appropriate instance - */ - public SourcePosition makeSourcePosistion(int offset) { - return new SourcePosition(getSourceFile(), offset, - lineNumbers.pcToLine(offset)); - } -} diff --git a/app/src/main/java/com/pojavdx/dx/cf/code/ExecutionStack.java b/app/src/main/java/com/pojavdx/dx/cf/code/ExecutionStack.java deleted file mode 100644 index 9a45f8859..000000000 --- a/app/src/main/java/com/pojavdx/dx/cf/code/ExecutionStack.java +++ /dev/null @@ -1,343 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.pojavdx.dx.cf.code; - -import com.pojavdx.dex.util.ExceptionWithContext; -import com.pojavdx.dx.rop.type.Type; -import com.pojavdx.dx.rop.type.TypeBearer; -import com.pojavdx.dx.util.Hex; -import com.pojavdx.dx.util.MutabilityControl; - -/** - * Representation of a Java method execution stack. - * - *

Note: For the most part, the documentation for this class - * ignores the distinction between {@link Type} and {@link - * TypeBearer}.

- */ -public final class ExecutionStack extends MutabilityControl { - /** {@code non-null;} array of stack contents */ - private final TypeBearer[] stack; - - /** - * {@code non-null;} array specifying whether stack contents have entries - * in the local variable table - */ - private final boolean[] local; - /** - * {@code >= 0;} stack pointer (points one past the end) / current stack - * size - */ - private int stackPtr; - - /** - * Constructs an instance. - * - * @param maxStack {@code >= 0;} the maximum size of the stack for this - * instance - */ - public ExecutionStack(int maxStack) { - super(maxStack != 0); - stack = new TypeBearer[maxStack]; - local = new boolean[maxStack]; - stackPtr = 0; - } - - /** - * Makes and returns a mutable copy of this instance. - * - * @return {@code non-null;} the copy - */ - public ExecutionStack copy() { - ExecutionStack result = new ExecutionStack(stack.length); - - net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(stack, 0, result.stack, 0, stack.length); - net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(local, 0, result.local, 0, local.length); - result.stackPtr = stackPtr; - - return result; - } - - /** - * Annotates (adds context to) the given exception with information - * about this instance. - * - * @param ex {@code non-null;} the exception to annotate - */ - public void annotate(ExceptionWithContext ex) { - int limit = stackPtr - 1; - - for (int i = 0; i <= limit; i++) { - String idx = (i == limit) ? "top0" : Hex.u2(limit - i); - - ex.addContext("stack[" + idx + "]: " + - stackElementString(stack[i])); - } - } - - /** - * Replaces all the occurrences of the given uninitialized type in - * this stack with its initialized equivalent. - * - * @param type {@code non-null;} type to replace - */ - public void makeInitialized(Type type) { - if (stackPtr == 0) { - // We have to check for this before checking for immutability. - return; - } - - throwIfImmutable(); - - Type initializedType = type.getInitializedType(); - - for (int i = 0; i < stackPtr; i++) { - if (stack[i] == type) { - stack[i] = initializedType; - } - } - } - - /** - * Gets the maximum stack size for this instance. - * - * @return {@code >= 0;} the max stack size - */ - public int getMaxStack() { - return stack.length; - } - - /** - * Gets the current stack size. - * - * @return {@code >= 0, < getMaxStack();} the current stack size - */ - public int size() { - return stackPtr; - } - - /** - * Clears the stack. (That is, this method pops everything off.) - */ - public void clear() { - throwIfImmutable(); - - for (int i = 0; i < stackPtr; i++) { - stack[i] = null; - local[i] = false; - } - - stackPtr = 0; - } - - /** - * Pushes a value of the given type onto the stack. - * - * @param type {@code non-null;} type of the value - * @throws SimException thrown if there is insufficient room on the - * stack for the value - */ - public void push(TypeBearer type) { - throwIfImmutable(); - - int category; - - try { - type = type.getFrameType(); - category = type.getType().getCategory(); - } catch (NullPointerException ex) { - // Elucidate the exception. - throw new NullPointerException("type == null"); - } - - if ((stackPtr + category) > stack.length) { - throwSimException("overflow"); - return; - } - - if (category == 2) { - stack[stackPtr] = null; - stackPtr++; - } - - stack[stackPtr] = type; - stackPtr++; - } - - /** - * Flags the next value pushed onto the stack as having local info. - */ - public void setLocal() { - throwIfImmutable(); - - local[stackPtr] = true; - } - - /** - * Peeks at the {@code n}th element down from the top of the stack. - * {@code n == 0} means to peek at the top of the stack. Note that - * this will return {@code null} if the indicated element is the - * deeper half of a category-2 value. - * - * @param n {@code >= 0;} which element to peek at - * @return {@code null-ok;} the type of value stored at that element - * @throws SimException thrown if {@code n >= size()} - */ - public TypeBearer peek(int n) { - if (n < 0) { - throw new IllegalArgumentException("n < 0"); - } - - if (n >= stackPtr) { - return throwSimException("underflow"); - } - - return stack[stackPtr - n - 1]; - } - - /** - * Peeks at the {@code n}th element down from the top of the - * stack, returning whether or not it has local info. - * - * @param n {@code >= 0;} which element to peek at - * @return {@code true} if the value has local info, {@code false} otherwise - * @throws SimException thrown if {@code n >= size()} - */ - public boolean peekLocal(int n) { - if (n < 0) { - throw new IllegalArgumentException("n < 0"); - } - - if (n >= stackPtr) { - throw new SimException("stack: underflow"); - } - - return local[stackPtr - n - 1]; - } - - /** - * Peeks at the {@code n}th element down from the top of the - * stack, returning the type per se, as opposed to the - * type-bearer. This method is just a convenient shorthand - * for {@code peek(n).getType()}. - * - * @see #peek - */ - public Type peekType(int n) { - return peek(n).getType(); - } - - /** - * Pops the top element off of the stack. - * - * @return {@code non-null;} the type formerly on the top of the stack - * @throws SimException thrown if the stack is empty - */ - public TypeBearer pop() { - throwIfImmutable(); - - TypeBearer result = peek(0); - - stack[stackPtr - 1] = null; - local[stackPtr - 1] = false; - stackPtr -= result.getType().getCategory(); - - return result; - } - - /** - * Changes an element already on a stack. This method is useful in limited - * contexts, particularly when merging two instances. As such, it places - * the following restriction on its behavior: You may only replace - * values with other values of the same category. - * - * @param n {@code >= 0;} which element to change, where {@code 0} is - * the top element of the stack - * @param type {@code non-null;} type of the new value - * @throws SimException thrown if {@code n >= size()} or - * the action is otherwise prohibited - */ - public void change(int n, TypeBearer type) { - throwIfImmutable(); - - try { - type = type.getFrameType(); - } catch (NullPointerException ex) { - // Elucidate the exception. - throw new NullPointerException("type == null"); - } - - int idx = stackPtr - n - 1; - TypeBearer orig = stack[idx]; - - if ((orig == null) || - (orig.getType().getCategory() != type.getType().getCategory())) { - throwSimException("incompatible substitution: " + - stackElementString(orig) + " -> " + - stackElementString(type)); - } - - stack[idx] = type; - } - - /** - * Merges this stack with another stack. A new instance is returned if - * this merge results in a change. If no change results, this instance is - * returned. See {@link Merger#mergeStack(ExecutionStack,ExecutionStack) - * Merger.mergeStack()} - * - * @param other {@code non-null;} a stack to merge with - * @return {@code non-null;} the result of the merge - */ - public ExecutionStack merge(ExecutionStack other) { - try { - return Merger.mergeStack(this, other); - } catch (SimException ex) { - ex.addContext("underlay stack:"); - this.annotate(ex); - ex.addContext("overlay stack:"); - other.annotate(ex); - throw ex; - } - } - - /** - * Gets the string form for a stack element. This is the same as - * {@code toString()} except that {@code null} is converted - * to {@code ""}. - * - * @param type {@code null-ok;} the stack element - * @return {@code non-null;} the string form - */ - private static String stackElementString(TypeBearer type) { - if (type == null) { - return ""; - } - - return type.toString(); - } - - /** - * Throws a properly-formatted exception. - * - * @param msg {@code non-null;} useful message - * @return never (keeps compiler happy) - */ - private static TypeBearer throwSimException(String msg) { - throw new SimException("stack: " + msg); - } -} diff --git a/app/src/main/java/com/pojavdx/dx/cf/code/Frame.java b/app/src/main/java/com/pojavdx/dx/cf/code/Frame.java deleted file mode 100644 index fea4e40a9..000000000 --- a/app/src/main/java/com/pojavdx/dx/cf/code/Frame.java +++ /dev/null @@ -1,415 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.pojavdx.dx.cf.code; - -import com.pojavdx.dex.util.ExceptionWithContext; -import com.pojavdx.dx.rop.cst.CstType; -import com.pojavdx.dx.rop.type.StdTypeList; -import com.pojavdx.dx.rop.type.Type; -import com.pojavdx.dx.util.IntList; - -/** - * Representation of a Java method execution frame. A frame consists - * of a set of locals and a value stack, and it can be told to act on - * them to load and store values between them and an "arguments / - * results" area. - */ -public final class Frame { - /** {@code non-null;} the locals */ - private final LocalsArray locals; - - /** {@code non-null;} the stack */ - private final ExecutionStack stack; - - /** {@code null-ok;} stack of labels of subroutines that this block is nested in */ - private final IntList subroutines; - - /** - * Constructs an instance. - * - * @param locals {@code non-null;} the locals array to use - * @param stack {@code non-null;} the execution stack to use - */ - private Frame(LocalsArray locals, ExecutionStack stack) { - this(locals, stack, IntList.EMPTY); - } - - /** - * Constructs an instance. - * - * @param locals {@code non-null;} the locals array to use - * @param stack {@code non-null;} the execution stack to use - * @param subroutines {@code non-null;} list of subroutine start labels for - * subroutines this frame is nested in - */ - private Frame(LocalsArray locals, - ExecutionStack stack, IntList subroutines) { - if (locals == null) { - throw new NullPointerException("locals == null"); - } - - if (stack == null) { - throw new NullPointerException("stack == null"); - } - - subroutines.throwIfMutable(); - - this.locals = locals; - this.stack = stack; - this.subroutines = subroutines; - } - - /** - * Constructs an instance. The locals array initially consists of - * all-uninitialized values (represented as {@code null}s) and - * the stack starts out empty. - * - * @param maxLocals {@code >= 0;} the maximum number of locals this instance - * can refer to - * @param maxStack {@code >= 0;} the maximum size of the stack for this - * instance - */ - public Frame(int maxLocals, int maxStack) { - this(new OneLocalsArray(maxLocals), new ExecutionStack(maxStack)); - } - - /** - * Makes and returns a mutable copy of this instance. The copy - * contains copies of the locals and stack (that is, it doesn't - * share them with the original). - * - * @return {@code non-null;} the copy - */ - public Frame copy() { - return new Frame(locals.copy(), stack.copy(), subroutines); - } - - /** - * Makes this instance immutable. - */ - public void setImmutable() { - locals.setImmutable(); - stack.setImmutable(); - // "subroutines" is always immutable - } - - /** - * Replaces all the occurrences of the given uninitialized type in - * this frame with its initialized equivalent. - * - * @param type {@code non-null;} type to replace - */ - public void makeInitialized(Type type) { - locals.makeInitialized(type); - stack.makeInitialized(type); - } - - /** - * Gets the locals array for this instance. - * - * @return {@code non-null;} the locals array - */ - public LocalsArray getLocals() { - return locals; - } - - /** - * Gets the execution stack for this instance. - * - * @return {@code non-null;} the execution stack - */ - public ExecutionStack getStack() { - return stack; - } - - /** - * Returns the largest subroutine nesting this block may be in. An - * empty list is returned if this block is not in any subroutine. - * Subroutines are identified by the label of their start block. The - * list is ordered such that the deepest nesting (the actual subroutine - * this block is in) is the last label in the list. - * - * @return {@code non-null;} list as noted above - */ - public IntList getSubroutines() { - return subroutines; - } - - /** - * Initialize this frame with the method's parameters. Used for the first - * frame. - * - * @param params Type list of method parameters. - */ - public void initializeWithParameters(StdTypeList params) { - int at = 0; - int sz = params.size(); - - for (int i = 0; i < sz; i++) { - Type one = params.get(i); - locals.set(at, one); - at += one.getCategory(); - } - } - - /** - * Returns a Frame instance representing the frame state that should - * be used when returning from a subroutine. The stack state of all - * subroutine invocations is identical, but the locals state may differ. - * - * @param startLabel {@code >=0;} The label of the returning subroutine's - * start block - * @param subLabel {@code >=0;} A calling label of a subroutine - * @return {@code null-ok;} an appropriatly-constructed instance, or null - * if label is not in the set - */ - public Frame subFrameForLabel(int startLabel, int subLabel) { - LocalsArray subLocals = null; - - if (locals instanceof LocalsArraySet) { - subLocals = ((LocalsArraySet)locals).subArrayForLabel(subLabel); - } - - IntList newSubroutines; - try { - newSubroutines = subroutines.mutableCopy(); - - if (newSubroutines.pop() != startLabel) { - throw new RuntimeException("returning from invalid subroutine"); - } - newSubroutines.setImmutable(); - } catch (IndexOutOfBoundsException ex) { - throw new RuntimeException("returning from invalid subroutine"); - } catch (NullPointerException ex) { - throw new NullPointerException("can't return from non-subroutine"); - } - - return (subLocals == null) ? null - : new Frame(subLocals, stack, newSubroutines); - } - - /** - * Merges two frames. If the merged result is the same as this frame, - * then this instance is returned. - * - * @param other {@code non-null;} another frame - * @return {@code non-null;} the result of merging the two frames - */ - public Frame mergeWith(Frame other) { - LocalsArray resultLocals; - ExecutionStack resultStack; - IntList resultSubroutines; - - resultLocals = getLocals().merge(other.getLocals()); - resultStack = getStack().merge(other.getStack()); - resultSubroutines = mergeSubroutineLists(other.subroutines); - - resultLocals = adjustLocalsForSubroutines( - resultLocals, resultSubroutines); - - if ((resultLocals == getLocals()) - && (resultStack == getStack()) - && subroutines == resultSubroutines) { - return this; - } - - return new Frame(resultLocals, resultStack, resultSubroutines); - } - - /** - * Merges this frame's subroutine lists with another. The result - * is the deepest common nesting (effectively, the common prefix of the - * two lists). - * - * @param otherSubroutines label list of subroutine start blocks, from - * least-nested to most-nested. - * @return {@code non-null;} merged subroutine nest list as described above - */ - private IntList mergeSubroutineLists(IntList otherSubroutines) { - if (subroutines.equals(otherSubroutines)) { - return subroutines; - } - - IntList resultSubroutines = new IntList(); - - int szSubroutines = subroutines.size(); - int szOthers = otherSubroutines.size(); - for (int i = 0; i < szSubroutines && i < szOthers - && (subroutines.get(i) == otherSubroutines.get(i)); i++) { - resultSubroutines.add(i); - } - - resultSubroutines.setImmutable(); - - return resultSubroutines; - } - - /** - * Adjusts a locals array to account for a merged subroutines list. - * If a frame merge results in, effectively, a subroutine return through - * a throw then the current locals will be a LocalsArraySet that will - * need to be trimmed of all OneLocalsArray elements that relevent to - * the subroutine that is returning. - * - * @param locals {@code non-null;} LocalsArray from before a merge - * @param subroutines {@code non-null;} a label list of subroutine start blocks - * representing the subroutine nesting of the block being merged into. - * @return {@code non-null;} locals set appropriate for merge - */ - private static LocalsArray adjustLocalsForSubroutines( - LocalsArray locals, IntList subroutines) { - if (! (locals instanceof LocalsArraySet)) { - // nothing to see here - return locals; - } - - LocalsArraySet laSet = (LocalsArraySet)locals; - - if (subroutines.size() == 0) { - /* - * We've merged from a subroutine context to a non-subroutine - * context, likely via a throw. Our successor will only need - * to consider the primary locals state, not the state of - * all possible subroutine paths. - */ - - return laSet.getPrimary(); - } - - /* - * It's unclear to me if the locals set needs to be trimmed here. - * If it does, then I believe it is all of the calling blocks - * in the subroutine at the end of "subroutines" passed into - * this method that should be removed. - */ - return laSet; - } - - /** - * Merges this frame with the frame of a subroutine caller at - * {@code predLabel}. Only called on the frame at the first - * block of a subroutine. - * - * @param other {@code non-null;} another frame - * @param subLabel label of subroutine start block - * @param predLabel label of calling block - * @return {@code non-null;} the result of merging the two frames - */ - public Frame mergeWithSubroutineCaller(Frame other, int subLabel, - int predLabel) { - LocalsArray resultLocals; - ExecutionStack resultStack; - - resultLocals = getLocals().mergeWithSubroutineCaller( - other.getLocals(), predLabel); - resultStack = getStack().merge(other.getStack()); - - IntList newOtherSubroutines = other.subroutines.mutableCopy(); - newOtherSubroutines.add(subLabel); - newOtherSubroutines.setImmutable(); - - if ((resultLocals == getLocals()) - && (resultStack == getStack()) - && subroutines.equals(newOtherSubroutines)) { - return this; - } - - IntList resultSubroutines; - - if (subroutines.equals(newOtherSubroutines)) { - resultSubroutines = subroutines; - } else { - /* - * The new subroutines list should be the deepest of the two - * lists being merged, but the postfix of the resultant list - * must be equal to the shorter list. - */ - IntList nonResultSubroutines; - - if (subroutines.size() > newOtherSubroutines.size()) { - resultSubroutines = subroutines; - nonResultSubroutines = newOtherSubroutines; - } else { - resultSubroutines = newOtherSubroutines; - nonResultSubroutines = subroutines; - } - - int szResult = resultSubroutines.size(); - int szNonResult = nonResultSubroutines.size(); - - for (int i = szNonResult - 1; i >=0; i-- ) { - if (nonResultSubroutines.get(i) - != resultSubroutines.get( - i + (szResult - szNonResult))) { - throw new - RuntimeException("Incompatible merged subroutines"); - } - } - - } - - return new Frame(resultLocals, resultStack, resultSubroutines); - } - - /** - * Makes a frame for a subroutine start block, given that this is the - * ending frame of one of the subroutine's calling blocks. Subroutine - * calls may be nested and thus may have nested locals state, so we - * start with an initial state as seen by the subroutine, but keep track - * of the individual locals states that will be expected when the individual - * subroutine calls return. - * - * @param subLabel label of subroutine start block - * @param callerLabel {@code >=0;} label of the caller block where this frame - * came from. - * @return a new instance to begin a called subroutine. - */ - public Frame makeNewSubroutineStartFrame(int subLabel, int callerLabel) { - IntList newSubroutines = subroutines.mutableCopy(); - newSubroutines.add(subLabel); - Frame newFrame = new Frame(locals.getPrimary(), stack, - IntList.makeImmutable(subLabel)); - return newFrame.mergeWithSubroutineCaller(this, subLabel, callerLabel); - } - - /** - * Makes a new frame for an exception handler block invoked from this - * frame. - * - * @param exceptionClass exception that the handler block will handle - * @return new frame - */ - public Frame makeExceptionHandlerStartFrame(CstType exceptionClass) { - ExecutionStack newStack = getStack().copy(); - - newStack.clear(); - newStack.push(exceptionClass); - - return new Frame(getLocals(), newStack, subroutines); - } - - /** - * Annotates (adds context to) the given exception with information - * about this frame. - * - * @param ex {@code non-null;} the exception to annotate - */ - public void annotate(ExceptionWithContext ex) { - locals.annotate(ex); - stack.annotate(ex); - } -} diff --git a/app/src/main/java/com/pojavdx/dx/cf/code/LineNumberList.java b/app/src/main/java/com/pojavdx/dx/cf/code/LineNumberList.java deleted file mode 100644 index f8bc1cc0a..000000000 --- a/app/src/main/java/com/pojavdx/dx/cf/code/LineNumberList.java +++ /dev/null @@ -1,184 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.pojavdx.dx.cf.code; - -import com.pojavdx.dx.util.FixedSizeList; - -/** - * List of "line number" entries, which are the contents of - * {@code LineNumberTable} attributes. - */ -public final class LineNumberList extends FixedSizeList { - /** {@code non-null;} zero-size instance */ - public static final LineNumberList EMPTY = new LineNumberList(0); - - /** - * Returns an instance which is the concatenation of the two given - * instances. - * - * @param list1 {@code non-null;} first instance - * @param list2 {@code non-null;} second instance - * @return {@code non-null;} combined instance - */ - public static LineNumberList concat(LineNumberList list1, - LineNumberList list2) { - if (list1 == EMPTY) { - // easy case - return list2; - } - - int sz1 = list1.size(); - int sz2 = list2.size(); - LineNumberList result = new LineNumberList(sz1 + sz2); - - for (int i = 0; i < sz1; i++) { - result.set(i, list1.get(i)); - } - - for (int i = 0; i < sz2; i++) { - result.set(sz1 + i, list2.get(i)); - } - - return result; - } - - /** - * Constructs an instance. - * - * @param count the number of elements to be in the list - */ - public LineNumberList(int count) { - super(count); - } - - /** - * Gets the indicated item. - * - * @param n {@code >= 0;} which item - * @return {@code null-ok;} the indicated item - */ - public Item get(int n) { - return (Item) get0(n); - } - - /** - * Sets the item at the given index. - * - * @param n {@code >= 0, < size();} which element - * @param item {@code non-null;} the item - */ - public void set(int n, Item item) { - if (item == null) { - throw new NullPointerException("item == null"); - } - - set0(n, item); - } - - /** - * Sets the item at the given index. - * - * @param n {@code >= 0, < size();} which element - * @param startPc {@code >= 0;} start pc of this item - * @param lineNumber {@code >= 0;} corresponding line number - */ - public void set(int n, int startPc, int lineNumber) { - set0(n, new Item(startPc, lineNumber)); - } - - /** - * Gets the line number associated with the given address. - * - * @param pc {@code >= 0;} the address to look up - * @return {@code >= -1;} the associated line number, or {@code -1} if - * none is known - */ - public int pcToLine(int pc) { - /* - * Line number entries don't have to appear in any particular - * order, so we have to do a linear search. TODO: If - * this turns out to be a bottleneck, consider sorting the - * list prior to use. - */ - int sz = size(); - int bestPc = -1; - int bestLine = -1; - - for (int i = 0; i < sz; i++) { - Item one = get(i); - int onePc = one.getStartPc(); - if ((onePc <= pc) && (onePc > bestPc)) { - bestPc = onePc; - bestLine = one.getLineNumber(); - if (bestPc == pc) { - // We can't do better than this - break; - } - } - } - - return bestLine; - } - - /** - * Item in a line number table. - */ - public static class Item { - /** {@code >= 0;} start pc of this item */ - private final int startPc; - - /** {@code >= 0;} corresponding line number */ - private final int lineNumber; - - /** - * Constructs an instance. - * - * @param startPc {@code >= 0;} start pc of this item - * @param lineNumber {@code >= 0;} corresponding line number - */ - public Item(int startPc, int lineNumber) { - if (startPc < 0) { - throw new IllegalArgumentException("startPc < 0"); - } - - if (lineNumber < 0) { - throw new IllegalArgumentException("lineNumber < 0"); - } - - this.startPc = startPc; - this.lineNumber = lineNumber; - } - - /** - * Gets the start pc of this item. - * - * @return the start pc - */ - public int getStartPc() { - return startPc; - } - - /** - * Gets the line number of this item. - * - * @return the line number - */ - public int getLineNumber() { - return lineNumber; - } - } -} diff --git a/app/src/main/java/com/pojavdx/dx/cf/code/LocalVariableList.java b/app/src/main/java/com/pojavdx/dx/cf/code/LocalVariableList.java deleted file mode 100644 index 650a37eca..000000000 --- a/app/src/main/java/com/pojavdx/dx/cf/code/LocalVariableList.java +++ /dev/null @@ -1,373 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.pojavdx.dx.cf.code; - -import com.pojavdx.dx.rop.code.LocalItem; -import com.pojavdx.dx.rop.cst.CstString; -import com.pojavdx.dx.rop.type.Type; -import com.pojavdx.dx.util.FixedSizeList; - -/** - * List of "local variable" entries, which are the contents of - * {@code LocalVariableTable} and {@code LocalVariableTypeTable} - * attributes, as well as combinations of the two. - */ -public final class LocalVariableList extends FixedSizeList { - /** {@code non-null;} zero-size instance */ - public static final LocalVariableList EMPTY = new LocalVariableList(0); - - /** - * Returns an instance which is the concatenation of the two given - * instances. The result is immutable. - * - * @param list1 {@code non-null;} first instance - * @param list2 {@code non-null;} second instance - * @return {@code non-null;} combined instance - */ - public static LocalVariableList concat(LocalVariableList list1, - LocalVariableList list2) { - if (list1 == EMPTY) { - // easy case - return list2; - } - - int sz1 = list1.size(); - int sz2 = list2.size(); - LocalVariableList result = new LocalVariableList(sz1 + sz2); - - for (int i = 0; i < sz1; i++) { - result.set(i, list1.get(i)); - } - - for (int i = 0; i < sz2; i++) { - result.set(sz1 + i, list2.get(i)); - } - - result.setImmutable(); - return result; - } - - /** - * Returns an instance which is the result of merging the two - * given instances, where one instance should have only type - * descriptors and the other only type signatures. The merged - * result is identical to the one with descriptors, except that - * any element whose {name, index, start, length} matches an - * element in the signature list gets augmented with the - * corresponding signature. The result is immutable. - * - * @param descriptorList {@code non-null;} list with descriptors - * @param signatureList {@code non-null;} list with signatures - * @return {@code non-null;} the merged result - */ - public static LocalVariableList mergeDescriptorsAndSignatures( - LocalVariableList descriptorList, - LocalVariableList signatureList) { - int descriptorSize = descriptorList.size(); - LocalVariableList result = new LocalVariableList(descriptorSize); - - for (int i = 0; i < descriptorSize; i++) { - Item item = descriptorList.get(i); - Item signatureItem = signatureList.itemToLocal(item); - if (signatureItem != null) { - CstString signature = signatureItem.getSignature(); - item = item.withSignature(signature); - } - result.set(i, item); - } - - result.setImmutable(); - return result; - } - - /** - * Constructs an instance. - * - * @param count the number of elements to be in the list - */ - public LocalVariableList(int count) { - super(count); - } - - /** - * Gets the indicated item. - * - * @param n {@code >= 0;} which item - * @return {@code null-ok;} the indicated item - */ - public Item get(int n) { - return (Item) get0(n); - } - - /** - * Sets the item at the given index. - * - * @param n {@code >= 0, < size();} which element - * @param item {@code non-null;} the item - */ - public void set(int n, Item item) { - if (item == null) { - throw new NullPointerException("item == null"); - } - - set0(n, item); - } - - /** - * Sets the item at the given index. - * - *

Note: At least one of {@code descriptor} or - * {@code signature} must be passed as non-null.

- * - * @param n {@code >= 0, < size();} which element - * @param startPc {@code >= 0;} the start pc of this variable's scope - * @param length {@code >= 0;} the length (in bytecodes) of this variable's - * scope - * @param name {@code non-null;} the variable's name - * @param descriptor {@code null-ok;} the variable's type descriptor - * @param signature {@code null-ok;} the variable's type signature - * @param index {@code >= 0;} the variable's local index - */ - public void set(int n, int startPc, int length, CstString name, - CstString descriptor, CstString signature, int index) { - set0(n, new Item(startPc, length, name, descriptor, signature, index)); - } - - /** - * Gets the local variable information in this instance which matches - * the given {@link com.pojavdx.dx.cf.code.LocalVariableList.Item} - * in all respects but the type descriptor and signature, if any. - * - * @param item {@code non-null;} local variable information to match - * @return {@code null-ok;} the corresponding local variable information stored - * in this instance, or {@code null} if there is no matching - * information - */ - public Item itemToLocal(Item item) { - int sz = size(); - - for (int i = 0; i < sz; i++) { - Item one = (Item) get0(i); - - if ((one != null) && one.matchesAllButType(item)) { - return one; - } - } - - return null; - } - - /** - * Gets the local variable information associated with a given address - * and local index, if any. Note: In standard classfiles, a - * variable's start point is listed as the address of the instruction - * just past the one that sets the variable. - * - * @param pc {@code >= 0;} the address to look up - * @param index {@code >= 0;} the local variable index - * @return {@code null-ok;} the associated local variable information, or - * {@code null} if none is known - */ - public Item pcAndIndexToLocal(int pc, int index) { - int sz = size(); - - for (int i = 0; i < sz; i++) { - Item one = (Item) get0(i); - - if ((one != null) && one.matchesPcAndIndex(pc, index)) { - return one; - } - } - - return null; - } - - /** - * Item in a local variable table. - */ - public static class Item { - /** {@code >= 0;} the start pc of this variable's scope */ - private final int startPc; - - /** {@code >= 0;} the length (in bytecodes) of this variable's scope */ - private final int length; - - /** {@code non-null;} the variable's name */ - private final CstString name; - - /** {@code null-ok;} the variable's type descriptor */ - private final CstString descriptor; - - /** {@code null-ok;} the variable's type signature */ - private final CstString signature; - - /** {@code >= 0;} the variable's local index */ - private final int index; - - /** - * Constructs an instance. - * - *

Note: At least one of {@code descriptor} or - * {@code signature} must be passed as non-null.

- * - * @param startPc {@code >= 0;} the start pc of this variable's scope - * @param length {@code >= 0;} the length (in bytecodes) of this variable's - * scope - * @param name {@code non-null;} the variable's name - * @param descriptor {@code null-ok;} the variable's type descriptor - * @param signature {@code null-ok;} the variable's type signature - * @param index {@code >= 0;} the variable's local index - */ - public Item(int startPc, int length, CstString name, - CstString descriptor, CstString signature, int index) { - if (startPc < 0) { - throw new IllegalArgumentException("startPc < 0"); - } - - if (length < 0) { - throw new IllegalArgumentException("length < 0"); - } - - if (name == null) { - throw new NullPointerException("name == null"); - } - - if ((descriptor == null) && (signature == null)) { - throw new NullPointerException( - "(descriptor == null) && (signature == null)"); - } - - if (index < 0) { - throw new IllegalArgumentException("index < 0"); - } - - this.startPc = startPc; - this.length = length; - this.name = name; - this.descriptor = descriptor; - this.signature = signature; - this.index = index; - } - - /** - * Gets the start pc of this variable's scope. - * - * @return {@code >= 0;} the start pc of this variable's scope - */ - public int getStartPc() { - return startPc; - } - - /** - * Gets the length (in bytecodes) of this variable's scope. - * - * @return {@code >= 0;} the length (in bytecodes) of this variable's scope - */ - public int getLength() { - return length; - } - - /** - * Gets the variable's type descriptor. - * - * @return {@code null-ok;} the variable's type descriptor - */ - public CstString getDescriptor() { - return descriptor; - } - - /** - * Gets the variable's LocalItem, a (name, signature) tuple - * - * @return {@code null-ok;} the variable's type descriptor - */ - public LocalItem getLocalItem() { - return LocalItem.make(name, signature); - } - - /** - * Gets the variable's type signature. Private because if you need this, - * you want getLocalItem() instead. - * - * @return {@code null-ok;} the variable's type signature - */ - private CstString getSignature() { - return signature; - } - - /** - * Gets the variable's local index. - * - * @return {@code >= 0;} the variable's local index - */ - public int getIndex() { - return index; - } - - /** - * Gets the variable's type descriptor. This is a convenient shorthand - * for {@code Type.intern(getDescriptor().getString())}. - * - * @return {@code non-null;} the variable's type - */ - public Type getType() { - return Type.intern(descriptor.getString()); - } - - /** - * Constructs and returns an instance which is identical to this - * one, except that the signature is changed to the given value. - * - * @param newSignature {@code non-null;} the new signature - * @return {@code non-null;} an appropriately-constructed instance - */ - public Item withSignature(CstString newSignature) { - return new Item(startPc, length, name, descriptor, newSignature, - index); - } - - /** - * Gets whether this instance matches (describes) the given - * address and index. - * - * @param pc {@code >= 0;} the address in question - * @param index {@code >= 0;} the local variable index in question - * @return {@code true} iff this instance matches {@code pc} - * and {@code index} - */ - public boolean matchesPcAndIndex(int pc, int index) { - return (index == this.index) && - (pc >= startPc) && - (pc < (startPc + length)); - } - - /** - * Gets whether this instance matches (describes) the given - * other instance exactly in all fields except type descriptor and - * type signature. - * - * @param other {@code non-null;} the instance to compare to - * @return {@code true} iff this instance matches - */ - public boolean matchesAllButType(Item other) { - return (startPc == other.startPc) - && (length == other.length) - && (index == other.index) - && name.equals(other.name); - } - } -} diff --git a/app/src/main/java/com/pojavdx/dx/cf/code/LocalsArray.java b/app/src/main/java/com/pojavdx/dx/cf/code/LocalsArray.java deleted file mode 100644 index 5036ea215..000000000 --- a/app/src/main/java/com/pojavdx/dx/cf/code/LocalsArray.java +++ /dev/null @@ -1,181 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.pojavdx.dx.cf.code; - -import com.pojavdx.dex.util.ExceptionWithContext; -import com.pojavdx.dx.rop.code.RegisterSpec; -import com.pojavdx.dx.rop.type.Type; -import com.pojavdx.dx.rop.type.TypeBearer; -import com.pojavdx.dx.util.MutabilityControl; -import com.pojavdx.dx.util.ToHuman; - -/** - * Representation of an array of local variables, with Java semantics. - * - *

Note: For the most part, the documentation for this class - * ignores the distinction between {@link Type} and {@link - * TypeBearer}.

- */ -public abstract class LocalsArray extends MutabilityControl implements ToHuman { - - /** - * Constructs an instance, explicitly indicating the mutability. - * - * @param mutable {@code true} if this instance is mutable - */ - protected LocalsArray(boolean mutable) { - super(mutable); - } - - /** - * Makes and returns a mutable copy of this instance. - * - * @return {@code non-null;} the copy - */ - public abstract LocalsArray copy(); - - /** - * Annotates (adds context to) the given exception with information - * about this instance. - * - * @param ex {@code non-null;} the exception to annotate - */ - public abstract void annotate(ExceptionWithContext ex); - - /** - * Replaces all the occurrences of the given uninitialized type in - * this array with its initialized equivalent. - * - * @param type {@code non-null;} type to replace - */ - public abstract void makeInitialized(Type type); - - /** - * Gets the maximum number of locals this instance can refer to. - * - * @return the max locals - */ - public abstract int getMaxLocals(); - - /** - * Sets the type stored at the given local index. If the given type - * is category-2, then (a) the index must be at least two less than - * {@link #getMaxLocals} and (b) the next index gets invalidated - * by the operation. In case of either category, if the previous - * local contains a category-2 value, then it too is invalidated by - * this operation. - * - * @param idx {@code >= 0, < getMaxLocals();} which local - * @param type {@code non-null;} new type for the local at {@code idx} - */ - public abstract void set(int idx, TypeBearer type); - - /** - * Sets the type for the local indicated by the given register spec - * to that register spec (which includes type and optional name - * information). This is identical to calling - * {@code set(spec.getReg(), spec)}. - * - * @param spec {@code non-null;} register spec to use as the basis for the update - */ - public abstract void set(RegisterSpec spec); - - /** - * Invalidates the local at the given index. - * - * @param idx {@code >= 0, < getMaxLocals();} which local - */ - public abstract void invalidate(int idx); - - /** - * Gets the type stored at the given local index, or {@code null} - * if the given local is uninitialized / invalid. - * - * @param idx {@code >= 0, < getMaxLocals();} which local - * @return {@code null-ok;} the type of value stored in that local - */ - public abstract TypeBearer getOrNull(int idx); - - /** - * Gets the type stored at the given local index, only succeeding if - * the given local contains a valid type (though it is allowed to - * be an uninitialized instance). - * - * @param idx {@code >= 0, < getMaxLocals();} which local - * @return {@code non-null;} the type of value stored in that local - * @throws SimException thrown if {@code idx} is valid, but - * the contents are invalid - */ - public abstract TypeBearer get(int idx); - - /** - * Gets the type stored at the given local index, which is expected - * to be an initialized category-1 value. - * - * @param idx {@code >= 0, < getMaxLocals();} which local - * @return {@code non-null;} the type of value stored in that local - * @throws SimException thrown if {@code idx} is valid, but - * one of the following holds: (a) the local is invalid; (b) the local - * contains an uninitialized instance; (c) the local contains a - * category-2 value - */ - public abstract TypeBearer getCategory1(int idx); - - /** - * Gets the type stored at the given local index, which is expected - * to be a category-2 value. - * - * @param idx {@code >= 0, < getMaxLocals();} which local - * @return {@code non-null;} the type of value stored in that local - * @throws SimException thrown if {@code idx} is valid, but - * one of the following holds: (a) the local is invalid; (b) the local - * contains a category-1 value - */ - public abstract TypeBearer getCategory2(int idx); - - /** - * Merges this instance with {@code other}. If the merged result is - * the same as this instance, then this is returned (not a copy). - * - * @param other {@code non-null;} another LocalsArray - * @return {@code non-null;} the merge result, a new instance or this - */ - public abstract LocalsArray merge(LocalsArray other); - - /** - * Merges this instance with a {@code LocalsSet} from a subroutine - * caller. To be used when merging in the first block of a subroutine. - * - * @param other {@code other non-null;} another LocalsArray. The final locals - * state of a subroutine caller. - * @param predLabel the label of the subroutine caller block. - * @return {@code non-null;} the merge result, a new instance or this - */ - public abstract LocalsArraySet mergeWithSubroutineCaller - (LocalsArray other, int predLabel); - - /** - * Gets the locals set appropriate for the current execution context. - * That is, if this is a {@code OneLocalsArray} instance, then return - * {@code this}, otherwise return {@code LocalsArraySet}'s - * primary. - * - * @return locals for this execution context. - */ - protected abstract OneLocalsArray getPrimary(); - -} diff --git a/app/src/main/java/com/pojavdx/dx/cf/code/LocalsArraySet.java b/app/src/main/java/com/pojavdx/dx/cf/code/LocalsArraySet.java deleted file mode 100644 index 72cb3b787..000000000 --- a/app/src/main/java/com/pojavdx/dx/cf/code/LocalsArraySet.java +++ /dev/null @@ -1,461 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.pojavdx.dx.cf.code; - -import com.pojavdx.dex.util.ExceptionWithContext; -import com.pojavdx.dx.rop.code.RegisterSpec; -import com.pojavdx.dx.rop.type.Type; -import com.pojavdx.dx.rop.type.TypeBearer; -import com.pojavdx.dx.util.Hex; -import java.util.ArrayList; - -/** - * Representation of a set of local variable arrays, with Java semantics. - * This peculiar case is to support in-method subroutines, which can - * have different locals sets for each caller. - * - *

Note: For the most part, the documentation for this class - * ignores the distinction between {@link com.pojavdx.dx.rop.type.Type} and {@link - * com.pojavdx.dx.rop.type.TypeBearer}.

- */ -public class LocalsArraySet extends LocalsArray { - - /** - * The primary LocalsArray represents the locals as seen from - * the subroutine itself, which is the merged representation of all the - * individual locals states. - */ - private final OneLocalsArray primary; - - /** - * Indexed by label of caller block: the locals specific to each caller's - * invocation of the subroutine. - */ - private final ArrayList secondaries; - - /** - * Constructs an instance. The locals array initially consists of - * all-uninitialized values (represented as {@code null}s). - * - * @param maxLocals {@code >= 0;} the maximum number of locals this instance - * can refer to - */ - public LocalsArraySet(int maxLocals) { - super(maxLocals != 0); - primary = new OneLocalsArray(maxLocals); - secondaries = new ArrayList(); - } - - /** - * Constructs an instance with the specified primary and secondaries set. - * - * @param primary {@code non-null;} primary locals to use - * @param secondaries {@code non-null;} secondaries set, indexed by subroutine - * caller label. - */ - public LocalsArraySet(OneLocalsArray primary, - ArrayList secondaries) { - super(primary.getMaxLocals() > 0); - - this.primary = primary; - this.secondaries = secondaries; - } - - /** - * Constructs an instance which is a copy of another. - * - * @param toCopy {@code non-null;} instance to copy. - */ - private LocalsArraySet(LocalsArraySet toCopy) { - super(toCopy.getMaxLocals() > 0); - - primary = toCopy.primary.copy(); - secondaries = new ArrayList(toCopy.secondaries.size()); - - int sz = toCopy.secondaries.size(); - for (int i = 0; i < sz; i++) { - LocalsArray la = toCopy.secondaries.get(i); - - if (la == null) { - secondaries.add(null); - } else { - secondaries.add(la.copy()); - } - } - } - - - /** {@inheritDoc} */ - @Override - public void setImmutable() { - primary.setImmutable(); - - for (LocalsArray la : secondaries) { - if (la != null) { - la.setImmutable(); - } - } - super.setImmutable(); - } - - /** {@inheritDoc} */ - @Override - public LocalsArray copy() { - return new LocalsArraySet(this); - } - - /** {@inheritDoc} */ - @Override - public void annotate(ExceptionWithContext ex) { - ex.addContext("(locals array set; primary)"); - primary.annotate(ex); - - int sz = secondaries.size(); - for (int label = 0; label < sz; label++) { - LocalsArray la = secondaries.get(label); - - if (la != null) { - ex.addContext("(locals array set: primary for caller " - + Hex.u2(label) + ')'); - - la.getPrimary().annotate(ex); - } - } - } - - /** {@inheritDoc} */ - @Override - public String toHuman() { - StringBuilder sb = new StringBuilder(); - - sb.append("(locals array set; primary)\n"); - - sb.append(getPrimary().toHuman()); - sb.append('\n'); - - int sz = secondaries.size(); - for (int label = 0; label < sz; label++) { - LocalsArray la = secondaries.get(label); - - if (la != null) { - sb.append("(locals array set: primary for caller " - + Hex.u2(label) + ")\n"); - - sb.append(la.getPrimary().toHuman()); - sb.append('\n'); - } - } - - return sb.toString(); - } - - /** {@inheritDoc} */ - @Override - public void makeInitialized(Type type) { - int len = primary.getMaxLocals(); - - if (len == 0) { - // We have to check for this before checking for immutability. - return; - } - - throwIfImmutable(); - - primary.makeInitialized(type); - - for (LocalsArray la : secondaries) { - if (la != null) { - la.makeInitialized(type); - } - } - } - - /** {@inheritDoc} */ - @Override - public int getMaxLocals() { - return primary.getMaxLocals(); - } - - /** {@inheritDoc} */ - @Override - public void set(int idx, TypeBearer type) { - throwIfImmutable(); - - primary.set(idx, type); - - for (LocalsArray la : secondaries) { - if (la != null) { - la.set(idx, type); - } - } - } - - /** {@inheritDoc} */ - @Override - public void set(RegisterSpec spec) { - set(spec.getReg(), spec); - } - - /** {@inheritDoc} */ - @Override - public void invalidate(int idx) { - throwIfImmutable(); - - primary.invalidate(idx); - - for (LocalsArray la : secondaries) { - if (la != null) { - la.invalidate(idx); - } - } - } - - /** {@inheritDoc} */ - @Override - public TypeBearer getOrNull(int idx) { - return primary.getOrNull(idx); - } - - /** {@inheritDoc} */ - @Override - public TypeBearer get(int idx) { - return primary.get(idx); - } - - /** {@inheritDoc} */ - @Override - public TypeBearer getCategory1(int idx) { - return primary.getCategory1(idx); - } - - /** {@inheritDoc} */ - @Override - public TypeBearer getCategory2(int idx) { - return primary.getCategory2(idx); - } - - /** - * Merges this set with another {@code LocalsArraySet} instance. - * - * @param other {@code non-null;} to merge - * @return {@code non-null;} this instance if merge was a no-op, or - * new merged instance. - */ - private LocalsArraySet mergeWithSet(LocalsArraySet other) { - OneLocalsArray newPrimary; - ArrayList newSecondaries; - boolean secondariesChanged = false; - - newPrimary = primary.merge(other.getPrimary()); - - int sz1 = secondaries.size(); - int sz2 = other.secondaries.size(); - int sz = Math.max(sz1, sz2); - newSecondaries = new ArrayList(sz); - - for (int i = 0; i < sz; i++) { - LocalsArray la1 = (i < sz1 ? secondaries.get(i) : null); - LocalsArray la2 = (i < sz2 ? other.secondaries.get(i) : null); - LocalsArray resultla = null; - - if (la1 == la2) { - resultla = la1; - } else if (la1 == null) { - resultla = la2; - } else if (la2 == null) { - resultla = la1; - } else { - try { - resultla = la1.merge(la2); - } catch (SimException ex) { - ex.addContext( - "Merging locals set for caller block " + Hex.u2(i)); - } - } - - secondariesChanged = secondariesChanged || (la1 != resultla); - - newSecondaries.add(resultla); - } - - if ((primary == newPrimary) && ! secondariesChanged ) { - return this; - } - - return new LocalsArraySet(newPrimary, newSecondaries); - } - - /** - * Merges this set with a {@code OneLocalsArray} instance. - * - * @param other {@code non-null;} to merge - * @return {@code non-null;} this instance if merge was a no-op, or - * new merged instance. - */ - private LocalsArraySet mergeWithOne(OneLocalsArray other) { - OneLocalsArray newPrimary; - ArrayList newSecondaries; - boolean secondariesChanged = false; - - newPrimary = primary.merge(other.getPrimary()); - newSecondaries = new ArrayList(secondaries.size()); - - int sz = secondaries.size(); - for (int i = 0; i < sz; i++) { - LocalsArray la = secondaries.get(i); - LocalsArray resultla = null; - - if (la != null) { - try { - resultla = la.merge(other); - } catch (SimException ex) { - ex.addContext("Merging one locals against caller block " - + Hex.u2(i)); - } - } - - secondariesChanged = secondariesChanged || (la != resultla); - - newSecondaries.add(resultla); - } - - if ((primary == newPrimary) && ! secondariesChanged ) { - return this; - } - - return new LocalsArraySet(newPrimary, newSecondaries); - } - - /** {@inheritDoc} */ - @Override - public LocalsArraySet merge(LocalsArray other) { - LocalsArraySet result; - - try { - if (other instanceof LocalsArraySet) { - result = mergeWithSet((LocalsArraySet) other); - } else { - result = mergeWithOne((OneLocalsArray) other); - } - } catch (SimException ex) { - ex.addContext("underlay locals:"); - annotate(ex); - ex.addContext("overlay locals:"); - other.annotate(ex); - throw ex; - } - - result.setImmutable(); - return result; - } - - /** - * Gets the {@code LocalsArray} instance for a specified subroutine - * caller label, or null if label has no locals associated with it. - * - * @param label {@code >= 0;} subroutine caller label - * @return {@code null-ok;} locals if available. - */ - private LocalsArray getSecondaryForLabel(int label) { - if (label >= secondaries.size()) { - return null; - } - - return secondaries.get(label); - } - - /** {@inheritDoc} */ - @Override - public LocalsArraySet mergeWithSubroutineCaller - (LocalsArray other, int predLabel) { - - LocalsArray mine = getSecondaryForLabel(predLabel); - LocalsArray newSecondary; - OneLocalsArray newPrimary; - - newPrimary = primary.merge(other.getPrimary()); - - if (mine == other) { - newSecondary = mine; - } else if (mine == null) { - newSecondary = other; - } else { - newSecondary = mine.merge(other); - } - - if ((newSecondary == mine) && (newPrimary == primary)) { - return this; - } else { - /* - * We're going to re-build a primary as a merge of all the - * secondaries. - */ - newPrimary = null; - - int szSecondaries = secondaries.size(); - int sz = Math.max(predLabel + 1, szSecondaries); - ArrayList newSecondaries = new ArrayList(sz); - for (int i = 0; i < sz; i++) { - LocalsArray la = null; - - if (i == predLabel) { - /* - * This LocalsArray always replaces any existing one, - * since this is the result of a refined iteration. - */ - la = newSecondary; - } else if (i < szSecondaries) { - la = secondaries.get(i); - } - - if (la != null) { - if (newPrimary == null) { - newPrimary = la.getPrimary(); - } else { - newPrimary = newPrimary.merge(la.getPrimary()); - } - } - - newSecondaries.add(la); - } - - LocalsArraySet result - = new LocalsArraySet(newPrimary, newSecondaries); - result.setImmutable(); - return result; - } - } - - /** - * Returns a LocalsArray instance representing the locals state that should - * be used when returning to a subroutine caller. - * - * @param subLabel {@code >= 0;} A calling label of a subroutine - * @return {@code null-ok;} an instance for this subroutine, or null if subroutine - * is not in this set. - */ - public LocalsArray subArrayForLabel(int subLabel) { - LocalsArray result = getSecondaryForLabel(subLabel); - return result; - } - - /**{@inheritDoc}*/ - @Override - protected OneLocalsArray getPrimary() { - return primary; - } -} diff --git a/app/src/main/java/com/pojavdx/dx/cf/code/Machine.java b/app/src/main/java/com/pojavdx/dx/cf/code/Machine.java deleted file mode 100644 index 59f5e2555..000000000 --- a/app/src/main/java/com/pojavdx/dx/cf/code/Machine.java +++ /dev/null @@ -1,216 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.pojavdx.dx.cf.code; - -import com.pojavdx.dx.rop.code.LocalItem; -import com.pojavdx.dx.rop.cst.Constant; -import com.pojavdx.dx.rop.type.Prototype; -import com.pojavdx.dx.rop.type.Type; -import java.util.ArrayList; - -/** - * Interface for machines capable of executing bytecode by acting - * upon a {@link Frame}. A machine conceptually contains four arbitrary-value - * argument slots, slots for several literal-value arguments, and slots for - * branch target information. - */ -public interface Machine { - /** - * Gets the effective prototype of the method that this instance is - * being used for. The effective prototype includes an initial - * {@code this} argument for instance methods. - * - * @return {@code non-null;} the method prototype - */ - public Prototype getPrototype(); - - /** - * Clears the regular and auxiliary arguments area. - */ - public void clearArgs(); - - /** - * Pops the given number of values from the stack (of either category), - * and store them in the arguments area, indicating that there are now - * that many arguments. Also, clear the auxiliary arguments. - * - * @param frame {@code non-null;} frame to operate on - * @param count {@code >= 0;} number of values to pop - */ - public void popArgs(Frame frame, int count); - - /** - * Pops values from the stack of the types indicated by the given - * {@code Prototype} (popped in reverse of the argument - * order, so the first prototype argument type is for the deepest - * element of the stack), and store them in the arguments area, - * indicating that there are now that many arguments. Also, clear - * the auxiliary arguments. - * - * @param frame {@code non-null;} frame to operate on - * @param prototype {@code non-null;} prototype indicating arguments to pop - */ - public void popArgs(Frame frame, Prototype prototype); - - /** - * Pops a value from the stack of the indicated type, and store it - * in the arguments area, indicating that there are now that many - * arguments. Also, clear the auxiliary arguments. - * - * @param frame {@code non-null;} frame to operate on - * @param type {@code non-null;} type of the argument - */ - public void popArgs(Frame frame, Type type); - - /** - * Pops values from the stack of the indicated types (popped in - * reverse argument order, so the first indicated type is for the - * deepest element of the stack), and store them in the arguments - * area, indicating that there are now that many arguments. Also, - * clear the auxiliary arguments. - * - * @param frame {@code non-null;} frame to operate on - * @param type1 {@code non-null;} type of the first argument - * @param type2 {@code non-null;} type of the second argument - */ - public void popArgs(Frame frame, Type type1, Type type2); - - /** - * Pops values from the stack of the indicated types (popped in - * reverse argument order, so the first indicated type is for the - * deepest element of the stack), and store them in the arguments - * area, indicating that there are now that many arguments. Also, - * clear the auxiliary arguments. - * - * @param frame {@code non-null;} frame to operate on - * @param type1 {@code non-null;} type of the first argument - * @param type2 {@code non-null;} type of the second argument - * @param type3 {@code non-null;} type of the third argument - */ - public void popArgs(Frame frame, Type type1, Type type2, Type type3); - - /** - * Loads the local variable with the given index as the sole argument in - * the arguments area. Also, clear the auxiliary arguments. - * - * @param frame {@code non-null;} frame to operate on - * @param idx {@code >= 0;} the local variable index - */ - public void localArg(Frame frame, int idx); - - /** - * Used to specify if a loaded local variable has info in the local - * variable table. - * - * @param local {@code true} if local arg has info in local variable table - */ - public void localInfo(boolean local); - - /** - * Indicates that the salient type of this operation is as - * given. This differentiates between, for example, the various - * arithmetic opcodes, which, by the time they hit a - * {@code Machine} are collapsed to the {@code int} - * variant. (See {@link BytecodeArray#parseInstruction} for - * details.) - * - * @param type {@code non-null;} the salient type of the upcoming operation - */ - public void auxType(Type type); - - /** - * Indicates that there is an auxiliary (inline, not stack) - * argument of type {@code int}, with the given value. - * - *

Note: Perhaps unintuitively, the stack manipulation - * ops (e.g., {@code dup} and {@code swap}) use this to - * indicate the result stack pattern with a straightforward hex - * encoding of the push order starting with least-significant - * nibbles getting pushed first). For example, an all-category-1 - * {@code dup2_x1} sets this to {@code 0x12312}, and the - * other form of that op sets this to - * {@code 0x121}.

- * - *

Also Note: For {@code switch*} instructions, this is - * used to indicate the padding value (which is only useful for - * verification).

- * - * @param value the argument value - */ - public void auxIntArg(int value); - - /** - * Indicates that there is an auxiliary (inline, not stack) object - * argument, with the value based on the given constant. - * - *

Note: Some opcodes use both {@code int} and - * constant auxiliary arguments.

- * - * @param cst {@code non-null;} the constant containing / referencing - * the value - */ - public void auxCstArg(Constant cst); - - /** - * Indicates that there is an auxiliary (inline, not stack) argument - * indicating a branch target. - * - * @param target the argument value - */ - public void auxTargetArg(int target); - - /** - * Indicates that there is an auxiliary (inline, not stack) argument - * consisting of a {@code switch*} table. - * - *

Note: This is generally used in conjunction with - * {@link #auxIntArg} (which holds the padding).

- * - * @param cases {@code non-null;} the list of key-target pairs, plus the default - * target - */ - public void auxSwitchArg(SwitchList cases); - - /** - * Indicates that there is an auxiliary (inline, not stack) argument - * consisting of a list of initial values for a newly created array. - * - * @param initValues {@code non-null;} the list of constant values to initialize - * the array - */ - public void auxInitValues(ArrayList initValues); - - /** - * Indicates that the target of this operation is the given local. - * - * @param idx {@code >= 0;} the local variable index - * @param type {@code non-null;} the type of the local - * @param local {@code null-ok;} the name and signature of the local, if known - */ - public void localTarget(int idx, Type type, LocalItem local); - - /** - * "Runs" the indicated opcode in an appropriate way, using the arguments - * area as appropriate, and modifying the given frame in response. - * - * @param frame {@code non-null;} frame to operate on - * @param offset {@code >= 0;} byte offset in the method to the opcode being - * run - * @param opcode {@code >= 0;} the opcode to run - */ - public void run(Frame frame, int offset, int opcode); -} diff --git a/app/src/main/java/com/pojavdx/dx/cf/code/Merger.java b/app/src/main/java/com/pojavdx/dx/cf/code/Merger.java deleted file mode 100644 index 1873fc2ae..000000000 --- a/app/src/main/java/com/pojavdx/dx/cf/code/Merger.java +++ /dev/null @@ -1,305 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.pojavdx.dx.cf.code; - -import com.pojavdx.dx.rop.type.Type; -import com.pojavdx.dx.rop.type.TypeBearer; -import com.pojavdx.dx.util.Hex; - -/** - * Utility methods to merge various frame information. - */ -public final class Merger { - /** - * This class is uninstantiable. - */ - private Merger() { - // This space intentionally left blank. - } - - /** - * Merges two locals arrays. If the merged result is the same as the first - * argument, then return the first argument (not a copy). - * - * @param locals1 {@code non-null;} a locals array - * @param locals2 {@code non-null;} another locals array - * @return {@code non-null;} the result of merging the two locals arrays - */ - public static OneLocalsArray mergeLocals(OneLocalsArray locals1, - OneLocalsArray locals2) { - if (locals1 == locals2) { - // Easy out. - return locals1; - } - - int sz = locals1.getMaxLocals(); - OneLocalsArray result = null; - - if (locals2.getMaxLocals() != sz) { - throw new SimException("mismatched maxLocals values"); - } - - for (int i = 0; i < sz; i++) { - TypeBearer tb1 = locals1.getOrNull(i); - TypeBearer tb2 = locals2.getOrNull(i); - TypeBearer resultType = mergeType(tb1, tb2); - if (resultType != tb1) { - /* - * We only need to do anything when the result differs - * from what is in the first array, since that's what the - * result gets initialized to. - */ - if (result == null) { - result = locals1.copy(); - } - - if (resultType == null) { - result.invalidate(i); - } else { - result.set(i, resultType); - } - } - } - - if (result == null) { - return locals1; - } - - result.setImmutable(); - return result; - } - - /** - * Merges two stacks. If the merged result is the same as the first - * argument, then return the first argument (not a copy). - * - * @param stack1 {@code non-null;} a stack - * @param stack2 {@code non-null;} another stack - * @return {@code non-null;} the result of merging the two stacks - */ - public static ExecutionStack mergeStack(ExecutionStack stack1, - ExecutionStack stack2) { - if (stack1 == stack2) { - // Easy out. - return stack1; - } - - int sz = stack1.size(); - ExecutionStack result = null; - - if (stack2.size() != sz) { - throw new SimException("mismatched stack depths"); - } - - for (int i = 0; i < sz; i++) { - TypeBearer tb1 = stack1.peek(i); - TypeBearer tb2 = stack2.peek(i); - TypeBearer resultType = mergeType(tb1, tb2); - if (resultType != tb1) { - /* - * We only need to do anything when the result differs - * from what is in the first stack, since that's what the - * result gets initialized to. - */ - if (result == null) { - result = stack1.copy(); - } - - try { - if (resultType == null) { - throw new SimException("incompatible: " + tb1 + ", " + - tb2); - } else { - result.change(i, resultType); - } - } catch (SimException ex) { - ex.addContext("...while merging stack[" + Hex.u2(i) + "]"); - throw ex; - } - } - } - - if (result == null) { - return stack1; - } - - result.setImmutable(); - return result; - } - - /** - * Merges two frame types. - * - * @param ft1 {@code non-null;} a frame type - * @param ft2 {@code non-null;} another frame type - * @return {@code non-null;} the result of merging the two types - */ - public static TypeBearer mergeType(TypeBearer ft1, TypeBearer ft2) { - if ((ft1 == null) || ft1.equals(ft2)) { - return ft1; - } else if (ft2 == null) { - return null; - } else { - Type type1 = ft1.getType(); - Type type2 = ft2.getType(); - - if (type1 == type2) { - return type1; - } else if (type1.isReference() && type2.isReference()) { - if (type1 == Type.KNOWN_NULL) { - /* - * A known-null merges with any other reference type to - * be that reference type. - */ - return type2; - } else if (type2 == Type.KNOWN_NULL) { - /* - * The same as above, but this time it's type2 that's - * the known-null. - */ - return type1; - } else if (type1.isArray() && type2.isArray()) { - TypeBearer componentUnion = - mergeType(type1.getComponentType(), - type2.getComponentType()); - if (componentUnion == null) { - /* - * At least one of the types is a primitive type, - * so the merged result is just Object. - */ - return Type.OBJECT; - } - return ((Type) componentUnion).getArrayType(); - } else { - /* - * All other unequal reference types get merged to be - * Object in this phase. This is fine here, but it - * won't be the right thing to do in the verifier. - */ - return Type.OBJECT; - } - } else if (type1.isIntlike() && type2.isIntlike()) { - /* - * Merging two non-identical int-like types results in - * the type int. - */ - return Type.INT; - } else { - return null; - } - } - } - - /** - * Returns whether the given supertype is possibly assignable from - * the given subtype. This takes into account primitiveness, - * int-likeness, known-nullness, and array dimensions, but does - * not assume anything about class hierarchy other than that the - * type {@code Object} is the supertype of all reference - * types and all arrays are assignable to - * {@code Serializable} and {@code Cloneable}. - * - * @param supertypeBearer {@code non-null;} the supertype - * @param subtypeBearer {@code non-null;} the subtype - */ - public static boolean isPossiblyAssignableFrom(TypeBearer supertypeBearer, - TypeBearer subtypeBearer) { - Type supertype = supertypeBearer.getType(); - Type subtype = subtypeBearer.getType(); - - if (supertype.equals(subtype)) { - // Easy out. - return true; - } - - int superBt = supertype.getBasicType(); - int subBt = subtype.getBasicType(); - - // Treat return types as Object for the purposes of this method. - - if (superBt == Type.BT_ADDR) { - supertype = Type.OBJECT; - superBt = Type.BT_OBJECT; - } - - if (subBt == Type.BT_ADDR) { - subtype = Type.OBJECT; - subBt = Type.BT_OBJECT; - } - - if ((superBt != Type.BT_OBJECT) || (subBt != Type.BT_OBJECT)) { - /* - * No two distinct primitive types are assignable in this sense, - * unless they are both int-like. - */ - return supertype.isIntlike() && subtype.isIntlike(); - } - - // At this point, we know both types are reference types. - - if (supertype == Type.KNOWN_NULL) { - /* - * A known-null supertype is only assignable from another - * known-null (handled in the easy out at the top of the - * method). - */ - return false; - } else if (subtype == Type.KNOWN_NULL) { - /* - * A known-null subtype is in fact assignable to any - * reference type. - */ - return true; - } else if (supertype == Type.OBJECT) { - /* - * Object is assignable from any reference type. - */ - return true; - } else if (supertype.isArray()) { - // The supertype is an array type. - if (! subtype.isArray()) { - // The subtype isn't an array, and so can't be assignable. - return false; - } - - /* - * Strip off as many matched component types from both - * types as possible, and check the assignability of the - * results. - */ - do { - supertype = supertype.getComponentType(); - subtype = subtype.getComponentType(); - } while (supertype.isArray() && subtype.isArray()); - - return isPossiblyAssignableFrom(supertype, subtype); - } else if (subtype.isArray()) { - /* - * Other than Object (handled above), array types are - * assignable only to Serializable and Cloneable. - */ - return (supertype == Type.SERIALIZABLE) || - (supertype == Type.CLONEABLE); - } else { - /* - * All other unequal reference types are considered at - * least possibly assignable. - */ - return true; - } - } -} diff --git a/app/src/main/java/com/pojavdx/dx/cf/code/OneLocalsArray.java b/app/src/main/java/com/pojavdx/dx/cf/code/OneLocalsArray.java deleted file mode 100644 index a32ded325..000000000 --- a/app/src/main/java/com/pojavdx/dx/cf/code/OneLocalsArray.java +++ /dev/null @@ -1,257 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.pojavdx.dx.cf.code; - -import com.pojavdx.dex.util.ExceptionWithContext; -import com.pojavdx.dx.rop.code.RegisterSpec; -import com.pojavdx.dx.rop.type.Type; -import com.pojavdx.dx.rop.type.TypeBearer; -import com.pojavdx.dx.util.Hex; - -/** - * Representation of an array of local variables, with Java semantics. - * - *

Note: For the most part, the documentation for this class - * ignores the distinction between {@link com.pojavdx.dx.rop.type.Type} and {@link - * com.pojavdx.dx.rop.type.TypeBearer}.

- */ -public class OneLocalsArray extends LocalsArray { - /** {@code non-null;} actual array */ - private final TypeBearer[] locals; - - /** - * Constructs an instance. The locals array initially consists of - * all-uninitialized values (represented as {@code null}s). - * - * @param maxLocals {@code >= 0;} the maximum number of locals this instance - * can refer to - */ - public OneLocalsArray(int maxLocals) { - super(maxLocals != 0); - locals = new TypeBearer[maxLocals]; - } - - /** {@inheritDoc} */ - @Override - public OneLocalsArray copy() { - OneLocalsArray result = new OneLocalsArray(locals.length); - - net.kdt.pojavlaunch.SystemCrackResolver.arraycopy(locals, 0, result.locals, 0, locals.length); - - return result; - } - - /** {@inheritDoc} */ - @Override - public void annotate(ExceptionWithContext ex) { - for (int i = 0; i < locals.length; i++) { - TypeBearer type = locals[i]; - String s = (type == null) ? "" : type.toString(); - ex.addContext("locals[" + Hex.u2(i) + "]: " + s); - } - } - - /** {@inheritDoc} */ - @Override - public String toHuman() { - StringBuilder sb = new StringBuilder(); - - for (int i = 0; i < locals.length; i++) { - TypeBearer type = locals[i]; - String s = (type == null) ? "" : type.toString(); - sb.append("locals[" + Hex.u2(i) + "]: " + s + "\n"); - } - - return sb.toString(); - } - - /** {@inheritDoc} */ - @Override - public void makeInitialized(Type type) { - int len = locals.length; - - if (len == 0) { - // We have to check for this before checking for immutability. - return; - } - - throwIfImmutable(); - - Type initializedType = type.getInitializedType(); - - for (int i = 0; i < len; i++) { - if (locals[i] == type) { - locals[i] = initializedType; - } - } - } - - /** {@inheritDoc} */ - @Override - public int getMaxLocals() { - return locals.length; - } - - /** {@inheritDoc} */ - @Override - public void set(int idx, TypeBearer type) { - throwIfImmutable(); - - try { - type = type.getFrameType(); - } catch (NullPointerException ex) { - // Elucidate the exception - throw new NullPointerException("type == null"); - } - - if (idx < 0) { - throw new IndexOutOfBoundsException("idx < 0"); - } - - // Make highest possible out-of-bounds check happen first. - if (type.getType().isCategory2()) { - locals[idx + 1] = null; - } - - locals[idx] = type; - - if (idx != 0) { - TypeBearer prev = locals[idx - 1]; - if ((prev != null) && prev.getType().isCategory2()) { - locals[idx - 1] = null; - } - } - } - - /** {@inheritDoc} */ - @Override - public void set(RegisterSpec spec) { - set(spec.getReg(), spec); - } - - /** {@inheritDoc} */ - @Override - public void invalidate(int idx) { - throwIfImmutable(); - locals[idx] = null; - } - - /** {@inheritDoc} */ - @Override - public TypeBearer getOrNull(int idx) { - return locals[idx]; - } - - /** {@inheritDoc} */ - @Override - public TypeBearer get(int idx) { - TypeBearer result = locals[idx]; - - if (result == null) { - return throwSimException(idx, "invalid"); - } - - return result; - } - - /** {@inheritDoc} */ - @Override - public TypeBearer getCategory1(int idx) { - TypeBearer result = get(idx); - Type type = result.getType(); - - if (type.isUninitialized()) { - return throwSimException(idx, "uninitialized instance"); - } - - if (type.isCategory2()) { - return throwSimException(idx, "category-2"); - } - - return result; - } - - /** {@inheritDoc} */ - @Override - public TypeBearer getCategory2(int idx) { - TypeBearer result = get(idx); - - if (result.getType().isCategory1()) { - return throwSimException(idx, "category-1"); - } - - return result; - } - - /** {@inheritDoc} */ - @Override - public LocalsArray merge(LocalsArray other) { - if (other instanceof OneLocalsArray) { - return merge((OneLocalsArray)other); - } else { //LocalsArraySet - // LocalsArraySet knows how to merge me. - return other.merge(this); - } - } - - /** - * Merges this OneLocalsArray instance with another OneLocalsArray - * instance. A more-refined version of {@link #merge(LocalsArray) merge} - * which is called by that method when appropriate. - * - * @param other locals array with which to merge - * @return this instance if merge was a no-op, or a new instance if - * the merge resulted in a change. - */ - public OneLocalsArray merge(OneLocalsArray other) { - try { - return Merger.mergeLocals(this, other); - } catch (SimException ex) { - ex.addContext("underlay locals:"); - annotate(ex); - ex.addContext("overlay locals:"); - other.annotate(ex); - throw ex; - } - } - - /** {@inheritDoc} */ - @Override - public LocalsArraySet mergeWithSubroutineCaller - (LocalsArray other, int predLabel) { - - LocalsArraySet result = new LocalsArraySet(getMaxLocals()); - return result.mergeWithSubroutineCaller(other, predLabel); - } - - /**{@inheritDoc}*/ - @Override - protected OneLocalsArray getPrimary() { - return this; - } - - /** - * Throws a properly-formatted exception. - * - * @param idx the salient local index - * @param msg {@code non-null;} useful message - * @return never (keeps compiler happy) - */ - private static TypeBearer throwSimException(int idx, String msg) { - throw new SimException("local " + Hex.u2(idx) + ": " + msg); - } -} diff --git a/app/src/main/java/com/pojavdx/dx/cf/code/ReturnAddress.java b/app/src/main/java/com/pojavdx/dx/cf/code/ReturnAddress.java deleted file mode 100644 index 260d2209f..000000000 --- a/app/src/main/java/com/pojavdx/dx/cf/code/ReturnAddress.java +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.pojavdx.dx.cf.code; - -import com.pojavdx.dx.rop.type.Type; -import com.pojavdx.dx.rop.type.TypeBearer; -import com.pojavdx.dx.util.Hex; - -/** - * Representation of a subroutine return address. In Java verification, - * somewhat counterintuitively, the salient bit of information you need to - * know about a return address is the start address of the subroutine - * being returned from, not the address being returned to, so that's - * what instances of this class hang onto. - */ -public final class ReturnAddress implements TypeBearer { - /** {@code >= 0;} the start address of the subroutine being returned from */ - private final int subroutineAddress; - - /** - * Constructs an instance. - * - * @param subroutineAddress {@code >= 0;} the start address of the - * subroutine being returned from - */ - public ReturnAddress(int subroutineAddress) { - if (subroutineAddress < 0) { - throw new IllegalArgumentException("subroutineAddress < 0"); - } - - this.subroutineAddress = subroutineAddress; - } - - /** {@inheritDoc} */ - @Override - public String toString() { - return (""); - } - - /** {@inheritDoc} */ - @Override - public String toHuman() { - return toString(); - } - - /** {@inheritDoc} */ - @Override - public Type getType() { - return Type.RETURN_ADDRESS; - } - - /** {@inheritDoc} */ - @Override - public TypeBearer getFrameType() { - return this; - } - - /** {@inheritDoc} */ - @Override - public int getBasicType() { - return Type.RETURN_ADDRESS.getBasicType(); - } - - /** {@inheritDoc} */ - @Override - public int getBasicFrameType() { - return Type.RETURN_ADDRESS.getBasicFrameType(); - } - - /** {@inheritDoc} */ - @Override - public boolean isConstant() { - return false; - } - - /** {@inheritDoc} */ - @Override - public boolean equals(Object other) { - if (!(other instanceof ReturnAddress)) { - return false; - } - - return subroutineAddress == ((ReturnAddress) other).subroutineAddress; - } - - /** {@inheritDoc} */ - @Override - public int hashCode() { - return subroutineAddress; - } - - /** - * Gets the subroutine address. - * - * @return {@code >= 0;} the subroutine address - */ - public int getSubroutineAddress() { - return subroutineAddress; - } -} diff --git a/app/src/main/java/com/pojavdx/dx/cf/code/Ropper.java b/app/src/main/java/com/pojavdx/dx/cf/code/Ropper.java deleted file mode 100644 index 23d37fa9f..000000000 --- a/app/src/main/java/com/pojavdx/dx/cf/code/Ropper.java +++ /dev/null @@ -1,1801 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.pojavdx.dx.cf.code; - -import com.pojavdx.dx.cf.iface.MethodList; -import com.pojavdx.dx.dex.DexOptions; -import com.pojavdx.dx.rop.code.AccessFlags; -import com.pojavdx.dx.rop.code.BasicBlock; -import com.pojavdx.dx.rop.code.BasicBlockList; -import com.pojavdx.dx.rop.code.Insn; -import com.pojavdx.dx.rop.code.InsnList; -import com.pojavdx.dx.rop.code.PlainCstInsn; -import com.pojavdx.dx.rop.code.PlainInsn; -import com.pojavdx.dx.rop.code.RegisterSpec; -import com.pojavdx.dx.rop.code.RegisterSpecList; -import com.pojavdx.dx.rop.code.Rop; -import com.pojavdx.dx.rop.code.RopMethod; -import com.pojavdx.dx.rop.code.Rops; -import com.pojavdx.dx.rop.code.SourcePosition; -import com.pojavdx.dx.rop.code.ThrowingCstInsn; -import com.pojavdx.dx.rop.code.ThrowingInsn; -import com.pojavdx.dx.rop.code.TranslationAdvice; -import com.pojavdx.dx.rop.cst.CstInteger; -import com.pojavdx.dx.rop.cst.CstType; -import com.pojavdx.dx.rop.type.Prototype; -import com.pojavdx.dx.rop.type.StdTypeList; -import com.pojavdx.dx.rop.type.Type; -import com.pojavdx.dx.rop.type.TypeList; -import com.pojavdx.dx.util.Bits; -import com.pojavdx.dx.util.Hex; -import com.pojavdx.dx.util.IntList; -import java.util.ArrayList; -import java.util.BitSet; -import java.util.Collection; -import java.util.HashMap; -import java.util.Map; - -/** - * Utility that converts a basic block list into a list of register-oriented - * blocks. - */ -public final class Ropper { - /** label offset for the parameter assignment block */ - private static final int PARAM_ASSIGNMENT = -1; - - /** label offset for the return block */ - private static final int RETURN = -2; - - /** label offset for the synchronized method final return block */ - private static final int SYNCH_RETURN = -3; - - /** label offset for the first synchronized method setup block */ - private static final int SYNCH_SETUP_1 = -4; - - /** label offset for the second synchronized method setup block */ - private static final int SYNCH_SETUP_2 = -5; - - /** - * label offset for the first synchronized method exception - * handler block - */ - private static final int SYNCH_CATCH_1 = -6; - - /** - * label offset for the second synchronized method exception - * handler block - */ - private static final int SYNCH_CATCH_2 = -7; - - /** number of special label offsets */ - private static final int SPECIAL_LABEL_COUNT = 7; - - /** {@code non-null;} method being converted */ - private final ConcreteMethod method; - - /** {@code non-null;} original block list */ - private final ByteBlockList blocks; - - /** max locals of the method */ - private final int maxLocals; - - /** max label (exclusive) of any original bytecode block */ - private final int maxLabel; - - /** {@code non-null;} simulation machine to use */ - private final RopperMachine machine; - - /** {@code non-null;} simulator to use */ - private final Simulator sim; - - /** - * {@code non-null;} sparse array mapping block labels to initial frame - * contents, if known - */ - private final Frame[] startFrames; - - /** {@code non-null;} output block list in-progress */ - private final ArrayList result; - - /** - * {@code non-null;} list of subroutine-nest labels - * (See {@link Frame#getSubroutines} associated with each result block. - * Parallel to {@link Ropper#result}. - */ - private final ArrayList resultSubroutines; - - /** - * {@code non-null;} for each block (by label) that is used as an exception - * handler in the input, the exception handling info in Rop. - */ - private final CatchInfo[] catchInfos; - - /** - * whether an exception-handler block for a synchronized method was - * ever required - */ - private boolean synchNeedsExceptionHandler; - - /** - * {@code non-null;} list of subroutines indexed by label of start - * address */ - private final Subroutine[] subroutines; - - /** true if {@code subroutines} is non-empty */ - private boolean hasSubroutines; - - /** Allocates labels of exception handler setup blocks. */ - private final ExceptionSetupLabelAllocator exceptionSetupLabelAllocator; - - /** - * Keeps mapping of an input exception handler target code and how it is generated/targeted in - * Rop. - */ - private class CatchInfo { - /** - * {@code non-null;} map of ExceptionHandlerSetup by the type they handle */ - private final Map setups = - new HashMap(); - - /** - * Get the {@link ExceptionHandlerSetup} corresponding to the given type. The - * ExceptionHandlerSetup is created if this the first request for the given type. - * - * @param caughtType {@code non-null;} the type catch by the requested setup - * @return {@code non-null;} the handler setup block info for the given type - */ - ExceptionHandlerSetup getSetup(Type caughtType) { - ExceptionHandlerSetup handler = setups.get(caughtType); - if (handler == null) { - int handlerSetupLabel = exceptionSetupLabelAllocator.getNextLabel(); - handler = new ExceptionHandlerSetup(caughtType, handlerSetupLabel); - setups.put(caughtType, handler); - } - return handler; - } - - /** - * Get all {@link ExceptionHandlerSetup} of this handler. - * - * @return {@code non-null;} - */ - Collection getSetups() { - return setups.values(); - } - } - - /** - * Keeps track of an exception handler setup. - */ - private static class ExceptionHandlerSetup { - /** - * {@code non-null;} The caught type. */ - private Type caughtType; - /** - * {@code >= 0;} The label of the exception setup block. */ - private int label; - - /** - * Constructs instance. - * - * @param caughtType {@code non-null;} the caught type - * @param label {@code >= 0;} the label - */ - ExceptionHandlerSetup(Type caughtType, int label) { - this.caughtType = caughtType; - this.label = label; - } - - /** - * @return {@code non-null;} the caught type - */ - Type getCaughtType() { - return caughtType; - } - - /** - * @return {@code >= 0;} the label - */ - public int getLabel() { - return label; - } - } - - /** - * Keeps track of subroutines that exist in java form and are inlined in - * Rop form. - */ - private class Subroutine { - /** list of all blocks that jsr to this subroutine */ - private BitSet callerBlocks; - /** List of all blocks that return from this subroutine */ - private BitSet retBlocks; - /** first block in this subroutine */ - private int startBlock; - - /** - * Constructs instance. - * - * @param startBlock First block of the subroutine. - */ - Subroutine(int startBlock) { - this.startBlock = startBlock; - retBlocks = new BitSet(maxLabel); - callerBlocks = new BitSet(maxLabel); - hasSubroutines = true; - } - - /** - * Constructs instance. - * - * @param startBlock First block of the subroutine. - * @param retBlock one of the ret blocks (final blocks) of this - * subroutine. - */ - Subroutine(int startBlock, int retBlock) { - this(startBlock); - addRetBlock(retBlock); - } - - /** - * @return {@code >= 0;} the label of the subroutine's start block. - */ - int getStartBlock() { - return startBlock; - } - - /** - * Adds a label to the list of ret blocks (final blocks) for this - * subroutine. - * - * @param retBlock ret block label - */ - void addRetBlock(int retBlock) { - retBlocks.set(retBlock); - } - - /** - * Adds a label to the list of caller blocks for this subroutine. - * - * @param label a block that invokes this subroutine. - */ - void addCallerBlock(int label) { - callerBlocks.set(label); - } - - /** - * Generates a list of subroutine successors. Note: successor blocks - * could be listed more than once. This is ok, because this successor - * list (and the block it's associated with) will be copied and inlined - * before we leave the ropper. Redundent successors will result in - * redundent (no-op) merges. - * - * @return all currently known successors - * (return destinations) for that subroutine - */ - IntList getSuccessors() { - IntList successors = new IntList(callerBlocks.size()); - - /* - * For each subroutine caller, get it's target. If the - * target is us, add the ret target (subroutine successor) - * to our list - */ - - for (int label = callerBlocks.nextSetBit(0); label >= 0; - label = callerBlocks.nextSetBit(label+1)) { - BasicBlock subCaller = labelToBlock(label); - successors.add(subCaller.getSuccessors().get(0)); - } - - successors.setImmutable(); - - return successors; - } - - /** - * Merges the specified frame into this subroutine's successors, - * setting {@code workSet} as appropriate. To be called with - * the frame of a subroutine ret block. - * - * @param frame {@code non-null;} frame from ret block to merge - * @param workSet {@code non-null;} workset to update - */ - void mergeToSuccessors(Frame frame, int[] workSet) { - for (int label = callerBlocks.nextSetBit(0); label >= 0; - label = callerBlocks.nextSetBit(label+1)) { - BasicBlock subCaller = labelToBlock(label); - int succLabel = subCaller.getSuccessors().get(0); - - Frame subFrame = frame.subFrameForLabel(startBlock, label); - - if (subFrame != null) { - mergeAndWorkAsNecessary(succLabel, -1, null, - subFrame, workSet); - } else { - Bits.set(workSet, label); - } - } - } - } - - /** - * Converts a {@link ConcreteMethod} to a {@link RopMethod}. - * - * @param method {@code non-null;} method to convert - * @param advice {@code non-null;} translation advice to use - * @param methods {@code non-null;} list of methods defined by the class - * that defines {@code method}. - * @return {@code non-null;} the converted instance - */ - public static RopMethod convert(ConcreteMethod method, - TranslationAdvice advice, MethodList methods, DexOptions dexOptions) { - try { - Ropper r = new Ropper(method, advice, methods, dexOptions); - r.doit(); - return r.getRopMethod(); - } catch (SimException ex) { - ex.addContext("...while working on method " + - method.getNat().toHuman()); - throw ex; - } - } - - /** - * Constructs an instance. This class is not publicly instantiable; use - * {@link #convert}. - * - * @param method {@code non-null;} method to convert - * @param advice {@code non-null;} translation advice to use - * @param methods {@code non-null;} list of methods defined by the class - * that defines {@code method}. - * @param dexOptions {@code non-null;} options for dex output - */ - private Ropper(ConcreteMethod method, TranslationAdvice advice, MethodList methods, - DexOptions dexOptions) { - if (method == null) { - throw new NullPointerException("method == null"); - } - - if (advice == null) { - throw new NullPointerException("advice == null"); - } - - this.method = method; - this.blocks = BasicBlocker.identifyBlocks(method); - this.maxLabel = blocks.getMaxLabel(); - this.maxLocals = method.getMaxLocals(); - this.machine = new RopperMachine(this, method, advice, methods); - this.sim = new Simulator(machine, method, dexOptions); - this.startFrames = new Frame[maxLabel]; - this.subroutines = new Subroutine[maxLabel]; - - /* - * The "* 2 + 10" below is to conservatively believe that every - * block is an exception handler target and should also - * take care of enough other possible extra overhead such that - * the underlying array is unlikely to need resizing. - */ - this.result = new ArrayList(blocks.size() * 2 + 10); - this.resultSubroutines = - new ArrayList(blocks.size() * 2 + 10); - - this.catchInfos = new CatchInfo[maxLabel]; - this.synchNeedsExceptionHandler = false; - - /* - * Set up the first stack frame with the right limits, but leave it - * empty here (to be filled in outside of the constructor). - */ - startFrames[0] = new Frame(maxLocals, method.getMaxStack()); - exceptionSetupLabelAllocator = new ExceptionSetupLabelAllocator(); - } - - /** - * Gets the first (lowest) register number to use as the temporary - * area when unwinding stack manipulation ops. - * - * @return {@code >= 0;} the first register to use - */ - /*package*/ int getFirstTempStackReg() { - /* - * We use the register that is just past the deepest possible - * stack element, plus one if the method is synchronized to - * avoid overlapping with the synch register. We don't need to - * do anything else special at this level, since later passes - * will merely notice the highest register used by explicit - * inspection. - */ - int regCount = getNormalRegCount(); - return isSynchronized() ? regCount + 1 : regCount; - } - - /** - * Gets the label for the given special-purpose block. The given label - * should be one of the static constants defined by this class. - * - * @param label {@code < 0;} the special label constant - * @return {@code >= 0;} the actual label value to use - */ - private int getSpecialLabel(int label) { - /* - * The label is bitwise-complemented so that mistakes where - * LABEL is used instead of getSpecialLabel(LABEL) cause a - * failure at block construction time, since negative labels - * are illegal. 0..maxLabel (exclusive) are the original blocks and - * maxLabel..(maxLabel + method.getCatches().size()) are reserved for exception handler - * setup blocks (see getAvailableLabel(), exceptionSetupLabelAllocator). - */ - return maxLabel + method.getCatches().size() + ~label; - } - - /** - * Gets the minimum label for unreserved use. - * - * @return {@code >= 0;} the minimum label - */ - private int getMinimumUnreservedLabel() { - /* - * The labels below (maxLabel + method.getCatches().size() + SPECIAL_LABEL_COUNT) are - * reserved for particular uses. - */ - - return maxLabel + method.getCatches().size() + SPECIAL_LABEL_COUNT; - } - - /** - * Gets an unreserved and available label. - * Labels are distributed this way: - *
    - *
  • [0, maxLabel[ are the labels of the blocks directly - * corresponding to the input bytecode.
  • - *
  • [maxLabel, maxLabel + method.getCatches().size()[ are reserved for exception setup - * blocks.
  • - *
  • [maxLabel + method.getCatches().size(), - * maxLabel + method.getCatches().size() + SPECIAL_LABEL_COUNT[ are reserved for special blocks, - * ie param assignement, return and synch blocks.
  • - *
  • [maxLabel method.getCatches().size() + SPECIAL_LABEL_COUNT, getAvailableLabel()[ assigned - * labels. Note that some - * of the assigned labels may not be used any more if they were assigned to a block that was - * deleted since.
  • - *
- * - * @return {@code >= 0;} an available label with the guaranty that all greater labels are - * also available. - */ - private int getAvailableLabel() { - int candidate = getMinimumUnreservedLabel(); - - for (BasicBlock bb : result) { - int label = bb.getLabel(); - if (label >= candidate) { - candidate = label + 1; - } - } - - return candidate; - } - - /** - * Gets whether the method being translated is synchronized. - * - * @return whether the method being translated is synchronized - */ - private boolean isSynchronized() { - int accessFlags = method.getAccessFlags(); - return (accessFlags & AccessFlags.ACC_SYNCHRONIZED) != 0; - } - - /** - * Gets whether the method being translated is static. - * - * @return whether the method being translated is static - */ - private boolean isStatic() { - int accessFlags = method.getAccessFlags(); - return (accessFlags & AccessFlags.ACC_STATIC) != 0; - } - - /** - * Gets the total number of registers used for "normal" purposes (i.e., - * for the straightforward translation from the original Java). - * - * @return {@code >= 0;} the total number of registers used - */ - private int getNormalRegCount() { - return maxLocals + method.getMaxStack(); - } - - /** - * Gets the register spec to use to hold the object to synchronize on, - * for a synchronized method. - * - * @return {@code non-null;} the register spec - */ - private RegisterSpec getSynchReg() { - /* - * We use the register that is just past the deepest possible - * stack element, with a minimum of v1 since v0 is what's - * always used to hold the caught exception when unwinding. We - * don't need to do anything else special at this level, since - * later passes will merely notice the highest register used - * by explicit inspection. - */ - int reg = getNormalRegCount(); - return RegisterSpec.make((reg < 1) ? 1 : reg, Type.OBJECT); - } - - /** - * Searches {@link #result} for a block with the given label. Returns its - * index if found, or returns {@code -1} if there is no such block. - * - * @param label the label to look for - * @return {@code >= -1;} the index for the block with the given label or - * {@code -1} if there is no such block - */ - private int labelToResultIndex(int label) { - int sz = result.size(); - for (int i = 0; i < sz; i++) { - BasicBlock one = result.get(i); - if (one.getLabel() == label) { - return i; - } - } - - return -1; - } - - /** - * Searches {@link #result} for a block with the given label. Returns it if - * found, or throws an exception if there is no such block. - * - * @param label the label to look for - * @return {@code non-null;} the block with the given label - */ - private BasicBlock labelToBlock(int label) { - int idx = labelToResultIndex(label); - - if (idx < 0) { - throw new IllegalArgumentException("no such label " + - Hex.u2(label)); - } - - return result.get(idx); - } - - /** - * Adds a block to the output result. - * - * @param block {@code non-null;} the block to add - * @param subroutines {@code non-null;} subroutine label list - * as described in {@link Frame#getSubroutines} - */ - private void addBlock(BasicBlock block, IntList subroutines) { - if (block == null) { - throw new NullPointerException("block == null"); - } - - result.add(block); - subroutines.throwIfMutable(); - resultSubroutines.add(subroutines); - } - - /** - * Adds or replace a block in the output result. If this is a - * replacement, then any extra blocks that got added with the - * original get removed as a result of calling this method. - * - * @param block {@code non-null;} the block to add or replace - * @param subroutines {@code non-null;} subroutine label list - * as described in {@link Frame#getSubroutines} - * @return {@code true} if the block was replaced or - * {@code false} if it was added for the first time - */ - private boolean addOrReplaceBlock(BasicBlock block, IntList subroutines) { - if (block == null) { - throw new NullPointerException("block == null"); - } - - int idx = labelToResultIndex(block.getLabel()); - boolean ret; - - if (idx < 0) { - ret = false; - } else { - /* - * We are replacing a pre-existing block, so find any - * blocks that got added as part of the original and - * remove those too. Such blocks are (possibly indirect) - * successors of this block which are out of the range of - * normally-translated blocks. - */ - removeBlockAndSpecialSuccessors(idx); - ret = true; - } - - result.add(block); - subroutines.throwIfMutable(); - resultSubroutines.add(subroutines); - return ret; - } - - /** - * Adds or replaces a block in the output result. Do not delete - * any successors. - * - * @param block {@code non-null;} the block to add or replace - * @param subroutines {@code non-null;} subroutine label list - * as described in {@link Frame#getSubroutines} - * @return {@code true} if the block was replaced or - * {@code false} if it was added for the first time - */ - private boolean addOrReplaceBlockNoDelete(BasicBlock block, - IntList subroutines) { - if (block == null) { - throw new NullPointerException("block == null"); - } - - int idx = labelToResultIndex(block.getLabel()); - boolean ret; - - if (idx < 0) { - ret = false; - } else { - result.remove(idx); - resultSubroutines.remove(idx); - ret = true; - } - - result.add(block); - subroutines.throwIfMutable(); - resultSubroutines.add(subroutines); - return ret; - } - - /** - * Helper for {@link #addOrReplaceBlock} which recursively removes - * the given block and all blocks that are (direct and indirect) - * successors of it whose labels indicate that they are not in the - * normally-translated range. - * - * @param idx {@code non-null;} block to remove (etc.) - */ - private void removeBlockAndSpecialSuccessors(int idx) { - int minLabel = getMinimumUnreservedLabel(); - BasicBlock block = result.get(idx); - IntList successors = block.getSuccessors(); - int sz = successors.size(); - - result.remove(idx); - resultSubroutines.remove(idx); - - for (int i = 0; i < sz; i++) { - int label = successors.get(i); - if (label >= minLabel) { - idx = labelToResultIndex(label); - if (idx < 0) { - throw new RuntimeException("Invalid label " - + Hex.u2(label)); - } - removeBlockAndSpecialSuccessors(idx); - } - } - } - - /** - * Extracts the resulting {@link RopMethod} from the instance. - * - * @return {@code non-null;} the method object - */ - private RopMethod getRopMethod() { - - // Construct the final list of blocks. - - int sz = result.size(); - BasicBlockList bbl = new BasicBlockList(sz); - for (int i = 0; i < sz; i++) { - bbl.set(i, result.get(i)); - } - bbl.setImmutable(); - - // Construct the method object to wrap it all up. - - /* - * Note: The parameter assignment block is always the first - * that should be executed, hence the second argument to the - * constructor. - */ - return new RopMethod(bbl, getSpecialLabel(PARAM_ASSIGNMENT)); - } - - /** - * Does the conversion. - */ - private void doit() { - int[] workSet = Bits.makeBitSet(maxLabel); - - Bits.set(workSet, 0); - addSetupBlocks(); - setFirstFrame(); - - for (;;) { - int offset = Bits.findFirst(workSet, 0); - if (offset < 0) { - break; - } - Bits.clear(workSet, offset); - ByteBlock block = blocks.labelToBlock(offset); - Frame frame = startFrames[offset]; - try { - processBlock(block, frame, workSet); - } catch (SimException ex) { - ex.addContext("...while working on block " + Hex.u2(offset)); - throw ex; - } - } - - addReturnBlock(); - addSynchExceptionHandlerBlock(); - addExceptionSetupBlocks(); - - if (hasSubroutines) { - // Subroutines are very rare, so skip this step if it's n/a - inlineSubroutines(); - } - } - - /** - * Sets up the first frame to contain all the incoming parameters in - * locals. - */ - private void setFirstFrame() { - Prototype desc = method.getEffectiveDescriptor(); - startFrames[0].initializeWithParameters(desc.getParameterTypes()); - startFrames[0].setImmutable(); - } - - /** - * Processes the given block. - * - * @param block {@code non-null;} block to process - * @param frame {@code non-null;} start frame for the block - * @param workSet {@code non-null;} bits representing work to do, - * which this method may add to - */ - private void processBlock(ByteBlock block, Frame frame, int[] workSet) { - // Prepare the list of caught exceptions for this block. - ByteCatchList catches = block.getCatches(); - machine.startBlock(catches.toRopCatchList()); - - /* - * Using a copy of the given frame, simulate each instruction, - * calling into machine for each. - */ - frame = frame.copy(); - sim.simulate(block, frame); - frame.setImmutable(); - - int extraBlockCount = machine.getExtraBlockCount(); - ArrayList insns = machine.getInsns(); - int insnSz = insns.size(); - - /* - * Merge the frame into each possible non-exceptional - * successor. - */ - - int catchSz = catches.size(); - IntList successors = block.getSuccessors(); - - int startSuccessorIndex; - - Subroutine calledSubroutine = null; - if (machine.hasJsr()) { - /* - * If this frame ends in a JSR, only merge our frame with - * the subroutine start, not the subroutine's return target. - */ - startSuccessorIndex = 1; - - int subroutineLabel = successors.get(1); - - if (subroutines[subroutineLabel] == null) { - subroutines[subroutineLabel] = - new Subroutine (subroutineLabel); - } - - subroutines[subroutineLabel].addCallerBlock(block.getLabel()); - - calledSubroutine = subroutines[subroutineLabel]; - } else if (machine.hasRet()) { - /* - * This block ends in a ret, which means it's the final block - * in some subroutine. Ultimately, this block will be copied - * and inlined for each call and then disposed of. - */ - - ReturnAddress ra = machine.getReturnAddress(); - int subroutineLabel = ra.getSubroutineAddress(); - - if (subroutines[subroutineLabel] == null) { - subroutines[subroutineLabel] - = new Subroutine (subroutineLabel, block.getLabel()); - } else { - subroutines[subroutineLabel].addRetBlock(block.getLabel()); - } - - successors = subroutines[subroutineLabel].getSuccessors(); - subroutines[subroutineLabel] - .mergeToSuccessors(frame, workSet); - // Skip processing below since we just did it. - startSuccessorIndex = successors.size(); - } else if (machine.wereCatchesUsed()) { - /* - * If there are catches, then the first successors - * (which will either be all of them or all but the last one) - * are catch targets. - */ - startSuccessorIndex = catchSz; - } else { - startSuccessorIndex = 0; - } - - int succSz = successors.size(); - for (int i = startSuccessorIndex; i < succSz; - i++) { - int succ = successors.get(i); - try { - mergeAndWorkAsNecessary(succ, block.getLabel(), - calledSubroutine, frame, workSet); - } catch (SimException ex) { - ex.addContext("...while merging to block " + Hex.u2(succ)); - throw ex; - } - } - - if ((succSz == 0) && machine.returns()) { - /* - * The block originally contained a return, but it has - * been made to instead end with a goto, and we need to - * tell it at this point that its sole successor is the - * return block. This has to happen after the merge loop - * above, since, at this point, the return block doesn't - * actually exist; it gets synthesized at the end of - * processing the original blocks. - */ - successors = IntList.makeImmutable(getSpecialLabel(RETURN)); - succSz = 1; - } - - int primarySucc; - - if (succSz == 0) { - primarySucc = -1; - } else { - primarySucc = machine.getPrimarySuccessorIndex(); - if (primarySucc >= 0) { - primarySucc = successors.get(primarySucc); - } - } - - /* - * This variable is true only when the method is synchronized and - * the block being processed can possibly throw an exception. - */ - boolean synch = isSynchronized() && machine.canThrow(); - - if (synch || (catchSz != 0)) { - /* - * Deal with exception handlers: Merge an exception-catch - * frame into each possible exception handler, and - * construct a new set of successors to point at the - * exception handler setup blocks (which get synthesized - * at the very end of processing). - */ - boolean catchesAny = false; - IntList newSucc = new IntList(succSz); - for (int i = 0; i < catchSz; i++) { - ByteCatchList.Item one = catches.get(i); - CstType exceptionClass = one.getExceptionClass(); - int targ = one.getHandlerPc(); - - catchesAny |= (exceptionClass == CstType.OBJECT); - - Frame f = frame.makeExceptionHandlerStartFrame(exceptionClass); - - try { - mergeAndWorkAsNecessary(targ, block.getLabel(), - null, f, workSet); - } catch (SimException ex) { - ex.addContext("...while merging exception to block " + - Hex.u2(targ)); - throw ex; - } - - /* - * Set up the exception handler type. - */ - CatchInfo handlers = catchInfos[targ]; - if (handlers == null) { - handlers = new CatchInfo(); - catchInfos[targ] = handlers; - } - ExceptionHandlerSetup handler = handlers.getSetup(exceptionClass.getClassType()); - - /* - * The synthesized exception setup block will have the label given by handler. - */ - newSucc.add(handler.getLabel()); - } - - if (synch && !catchesAny) { - /* - * The method is synchronized and this block doesn't - * already have a catch-all handler, so add one to the - * end, both in the successors and in the throwing - * instruction(s) at the end of the block (which is where - * the caught classes live). - */ - newSucc.add(getSpecialLabel(SYNCH_CATCH_1)); - synchNeedsExceptionHandler = true; - - for (int i = insnSz - extraBlockCount - 1; i < insnSz; i++) { - Insn insn = insns.get(i); - if (insn.canThrow()) { - insn = insn.withAddedCatch(Type.OBJECT); - insns.set(i, insn); - } - } - } - - if (primarySucc >= 0) { - newSucc.add(primarySucc); - } - - newSucc.setImmutable(); - successors = newSucc; - } - - // Construct the final resulting block(s), and store it (them). - - int primarySuccListIndex = successors.indexOf(primarySucc); - - /* - * If there are any extra blocks, work backwards through the - * list of instructions, adding single-instruction blocks, and - * resetting the successors variables as appropriate. - */ - for (/*extraBlockCount*/; extraBlockCount > 0; extraBlockCount--) { - /* - * Some of the blocks that the RopperMachine wants added - * are for move-result insns, and these need goto insns as well. - */ - Insn extraInsn = insns.get(--insnSz); - boolean needsGoto - = extraInsn.getOpcode().getBranchingness() - == Rop.BRANCH_NONE; - InsnList il = new InsnList(needsGoto ? 2 : 1); - IntList extraBlockSuccessors = successors; - - il.set(0, extraInsn); - - if (needsGoto) { - il.set(1, new PlainInsn(Rops.GOTO, - extraInsn.getPosition(), null, - RegisterSpecList.EMPTY)); - /* - * Obviously, this block won't be throwing an exception - * so it should only have one successor. - */ - extraBlockSuccessors = IntList.makeImmutable(primarySucc); - } - il.setImmutable(); - - int label = getAvailableLabel(); - BasicBlock bb = new BasicBlock(label, il, extraBlockSuccessors, - primarySucc); - // All of these extra blocks will be in the same subroutine - addBlock(bb, frame.getSubroutines()); - - successors = successors.mutableCopy(); - successors.set(primarySuccListIndex, label); - successors.setImmutable(); - primarySucc = label; - } - - Insn lastInsn = (insnSz == 0) ? null : insns.get(insnSz - 1); - - /* - * Add a goto to the end of the block if it doesn't already - * end with a branch, to maintain the invariant that all - * blocks end with a branch of some sort or other. Note that - * it is possible for there to be blocks for which no - * instructions were ever output (e.g., only consist of pop* - * in the original Java bytecode). - */ - if ((lastInsn == null) || - (lastInsn.getOpcode().getBranchingness() == Rop.BRANCH_NONE)) { - SourcePosition pos = (lastInsn == null) ? SourcePosition.NO_INFO : - lastInsn.getPosition(); - insns.add(new PlainInsn(Rops.GOTO, pos, null, - RegisterSpecList.EMPTY)); - insnSz++; - } - - /* - * Construct a block for the remaining instructions (which in - * the usual case is all of them). - */ - - InsnList il = new InsnList(insnSz); - for (int i = 0; i < insnSz; i++) { - il.set(i, insns.get(i)); - } - il.setImmutable(); - - BasicBlock bb = - new BasicBlock(block.getLabel(), il, successors, primarySucc); - addOrReplaceBlock(bb, frame.getSubroutines()); - } - - /** - * Helper for {@link #processBlock}, which merges frames and - * adds to the work set, as necessary. - * - * @param label {@code >= 0;} label to work on - * @param pred predecessor label; must be {@code >= 0} when - * {@code label} is a subroutine start block and calledSubroutine - * is non-null. Otherwise, may be -1. - * @param calledSubroutine {@code null-ok;} a Subroutine instance if - * {@code label} is the first block in a subroutine. - * @param frame {@code non-null;} new frame for the labelled block - * @param workSet {@code non-null;} bits representing work to do, - * which this method may add to - */ - private void mergeAndWorkAsNecessary(int label, int pred, - Subroutine calledSubroutine, Frame frame, int[] workSet) { - Frame existing = startFrames[label]; - Frame merged; - - if (existing != null) { - /* - * Some other block also continues at this label. Merge - * the frames, and re-set the bit in the work set if there - * was a change. - */ - if (calledSubroutine != null) { - merged = existing.mergeWithSubroutineCaller(frame, - calledSubroutine.getStartBlock(), pred); - } else { - merged = existing.mergeWith(frame); - } - if (merged != existing) { - startFrames[label] = merged; - Bits.set(workSet, label); - } - } else { - // This is the first time this label has been encountered. - if (calledSubroutine != null) { - startFrames[label] - = frame.makeNewSubroutineStartFrame(label, pred); - } else { - startFrames[label] = frame; - } - Bits.set(workSet, label); - } - } - - /** - * Constructs and adds the blocks that perform setup for the rest of - * the method. This includes a first block which merely contains - * assignments from parameters to the same-numbered registers and - * a possible second block which deals with synchronization. - */ - private void addSetupBlocks() { - LocalVariableList localVariables = method.getLocalVariables(); - SourcePosition pos = method.makeSourcePosistion(0); - Prototype desc = method.getEffectiveDescriptor(); - StdTypeList params = desc.getParameterTypes(); - int sz = params.size(); - InsnList insns = new InsnList(sz + 1); - int at = 0; - - for (int i = 0; i < sz; i++) { - Type one = params.get(i); - LocalVariableList.Item local = - localVariables.pcAndIndexToLocal(0, at); - RegisterSpec result = (local == null) ? - RegisterSpec.make(at, one) : - RegisterSpec.makeLocalOptional(at, one, local.getLocalItem()); - - Insn insn = new PlainCstInsn(Rops.opMoveParam(one), pos, result, - RegisterSpecList.EMPTY, - CstInteger.make(at)); - insns.set(i, insn); - at += one.getCategory(); - } - - insns.set(sz, new PlainInsn(Rops.GOTO, pos, null, - RegisterSpecList.EMPTY)); - insns.setImmutable(); - - boolean synch = isSynchronized(); - int label = synch ? getSpecialLabel(SYNCH_SETUP_1) : 0; - BasicBlock bb = - new BasicBlock(getSpecialLabel(PARAM_ASSIGNMENT), insns, - IntList.makeImmutable(label), label); - addBlock(bb, IntList.EMPTY); - - if (synch) { - RegisterSpec synchReg = getSynchReg(); - Insn insn; - if (isStatic()) { - insn = new ThrowingCstInsn(Rops.CONST_OBJECT, pos, - RegisterSpecList.EMPTY, - StdTypeList.EMPTY, - method.getDefiningClass()); - insns = new InsnList(1); - insns.set(0, insn); - } else { - insns = new InsnList(2); - insn = new PlainCstInsn(Rops.MOVE_PARAM_OBJECT, pos, - synchReg, RegisterSpecList.EMPTY, - CstInteger.VALUE_0); - insns.set(0, insn); - insns.set(1, new PlainInsn(Rops.GOTO, pos, null, - RegisterSpecList.EMPTY)); - } - - int label2 = getSpecialLabel(SYNCH_SETUP_2); - insns.setImmutable(); - bb = new BasicBlock(label, insns, - IntList.makeImmutable(label2), label2); - addBlock(bb, IntList.EMPTY); - - insns = new InsnList(isStatic() ? 2 : 1); - - if (isStatic()) { - insns.set(0, new PlainInsn(Rops.opMoveResultPseudo(synchReg), - pos, synchReg, RegisterSpecList.EMPTY)); - } - - insn = new ThrowingInsn(Rops.MONITOR_ENTER, pos, - RegisterSpecList.make(synchReg), - StdTypeList.EMPTY); - insns.set(isStatic() ? 1 :0, insn); - insns.setImmutable(); - bb = new BasicBlock(label2, insns, IntList.makeImmutable(0), 0); - addBlock(bb, IntList.EMPTY); - } - } - - /** - * Constructs and adds the return block, if necessary. The return - * block merely contains an appropriate {@code return} - * instruction. - */ - private void addReturnBlock() { - Rop returnOp = machine.getReturnOp(); - - if (returnOp == null) { - /* - * The method being converted never returns normally, so there's - * no need for a return block. - */ - return; - } - - SourcePosition returnPos = machine.getReturnPosition(); - int label = getSpecialLabel(RETURN); - - if (isSynchronized()) { - InsnList insns = new InsnList(1); - Insn insn = new ThrowingInsn(Rops.MONITOR_EXIT, returnPos, - RegisterSpecList.make(getSynchReg()), - StdTypeList.EMPTY); - insns.set(0, insn); - insns.setImmutable(); - - int nextLabel = getSpecialLabel(SYNCH_RETURN); - BasicBlock bb = - new BasicBlock(label, insns, - IntList.makeImmutable(nextLabel), nextLabel); - addBlock(bb, IntList.EMPTY); - - label = nextLabel; - } - - InsnList insns = new InsnList(1); - TypeList sourceTypes = returnOp.getSources(); - RegisterSpecList sources; - - if (sourceTypes.size() == 0) { - sources = RegisterSpecList.EMPTY; - } else { - RegisterSpec source = RegisterSpec.make(0, sourceTypes.getType(0)); - sources = RegisterSpecList.make(source); - } - - Insn insn = new PlainInsn(returnOp, returnPos, null, sources); - insns.set(0, insn); - insns.setImmutable(); - - BasicBlock bb = new BasicBlock(label, insns, IntList.EMPTY, -1); - addBlock(bb, IntList.EMPTY); - } - - /** - * Constructs and adds, if necessary, the catch-all exception handler - * block to deal with unwinding the lock taken on entry to a synchronized - * method. - */ - private void addSynchExceptionHandlerBlock() { - if (!synchNeedsExceptionHandler) { - /* - * The method being converted either isn't synchronized or - * can't possibly throw exceptions in its main body, so - * there's no need for a synchronized method exception - * handler. - */ - return; - } - - SourcePosition pos = method.makeSourcePosistion(0); - RegisterSpec exReg = RegisterSpec.make(0, Type.THROWABLE); - BasicBlock bb; - Insn insn; - - InsnList insns = new InsnList(2); - insn = new PlainInsn(Rops.opMoveException(Type.THROWABLE), pos, - exReg, RegisterSpecList.EMPTY); - insns.set(0, insn); - insn = new ThrowingInsn(Rops.MONITOR_EXIT, pos, - RegisterSpecList.make(getSynchReg()), - StdTypeList.EMPTY); - insns.set(1, insn); - insns.setImmutable(); - - int label2 = getSpecialLabel(SYNCH_CATCH_2); - bb = new BasicBlock(getSpecialLabel(SYNCH_CATCH_1), insns, - IntList.makeImmutable(label2), label2); - addBlock(bb, IntList.EMPTY); - - insns = new InsnList(1); - insn = new ThrowingInsn(Rops.THROW, pos, - RegisterSpecList.make(exReg), - StdTypeList.EMPTY); - insns.set(0, insn); - insns.setImmutable(); - - bb = new BasicBlock(label2, insns, IntList.EMPTY, -1); - addBlock(bb, IntList.EMPTY); - } - - /** - * Creates the exception handler setup blocks. "maxLocals" - * below is because that's the register number corresponding - * to the sole element on a one-deep stack (which is the - * situation at the start of an exception handler block). - */ - private void addExceptionSetupBlocks() { - - int len = catchInfos.length; - for (int i = 0; i < len; i++) { - CatchInfo catches = catchInfos[i]; - if (catches != null) { - for (ExceptionHandlerSetup one : catches.getSetups()) { - Insn proto = labelToBlock(i).getFirstInsn(); - SourcePosition pos = proto.getPosition(); - InsnList il = new InsnList(2); - - Insn insn = new PlainInsn(Rops.opMoveException(one.getCaughtType()), - pos, - RegisterSpec.make(maxLocals, one.getCaughtType()), - RegisterSpecList.EMPTY); - il.set(0, insn); - - insn = new PlainInsn(Rops.GOTO, pos, null, - RegisterSpecList.EMPTY); - il.set(1, insn); - il.setImmutable(); - - BasicBlock bb = new BasicBlock(one.getLabel(), - il, - IntList.makeImmutable(i), - i); - addBlock(bb, startFrames[i].getSubroutines()); - } - } - } - } - - /** - * Checks to see if the basic block is a subroutine caller block. - * - * @param bb {@code non-null;} the basic block in question - * @return true if this block calls a subroutine - */ - private boolean isSubroutineCaller(BasicBlock bb) { - IntList successors = bb.getSuccessors(); - if (successors.size() < 2) return false; - - int subLabel = successors.get(1); - - return (subLabel < subroutines.length) - && (subroutines[subLabel] != null); - } - - /** - * Inlines any subroutine calls. - */ - private void inlineSubroutines() { - final IntList reachableSubroutineCallerLabels = new IntList(4); - - /* - * Compile a list of all subroutine calls reachable - * through the normal (non-subroutine) flow. We do this first, since - * we'll be affecting the call flow as we go. - * - * Start at label 0 -- the param assignment block has nothing for us - */ - forEachNonSubBlockDepthFirst(0, new BasicBlock.Visitor() { - @Override - public void visitBlock(BasicBlock b) { - if (isSubroutineCaller(b)) { - reachableSubroutineCallerLabels.add(b.getLabel()); - } - } - }); - - /* - * Convert the resultSubroutines list, indexed by block index, - * to a label-to-subroutines mapping used by the inliner. - */ - int largestAllocedLabel = getAvailableLabel(); - ArrayList labelToSubroutines - = new ArrayList(largestAllocedLabel); - for (int i = 0; i < largestAllocedLabel; i++) { - labelToSubroutines.add(null); - } - - for (int i = 0; i < result.size(); i++) { - BasicBlock b = result.get(i); - if (b == null) { - continue; - } - IntList subroutineList = resultSubroutines.get(i); - labelToSubroutines.set(b.getLabel(), subroutineList); - } - - /* - * Inline all reachable subroutines. - * Inner subroutines will be inlined as they are encountered. - */ - int sz = reachableSubroutineCallerLabels.size(); - for (int i = 0 ; i < sz ; i++) { - int label = reachableSubroutineCallerLabels.get(i); - new SubroutineInliner( - new LabelAllocator(getAvailableLabel()), - labelToSubroutines) - .inlineSubroutineCalledFrom(labelToBlock(label)); - } - - // Now find the blocks that aren't reachable and remove them - deleteUnreachableBlocks(); - } - - /** - * Deletes all blocks that cannot be reached. This is run to delete - * original subroutine blocks after subroutine inlining. - */ - private void deleteUnreachableBlocks() { - final IntList reachableLabels = new IntList(result.size()); - - // subroutine inlining is done now and we won't update this list here - resultSubroutines.clear(); - - forEachNonSubBlockDepthFirst(getSpecialLabel(PARAM_ASSIGNMENT), - new BasicBlock.Visitor() { - - @Override - public void visitBlock(BasicBlock b) { - reachableLabels.add(b.getLabel()); - } - }); - - reachableLabels.sort(); - - for (int i = result.size() - 1 ; i >= 0 ; i--) { - if (reachableLabels.indexOf(result.get(i).getLabel()) < 0) { - result.remove(i); - // unnecessary here really, since subroutine inlining is done - //resultSubroutines.remove(i); - } - } - } - - /** - * Allocates labels, without requiring previously allocated labels - * to have been added to the blocks list. - */ - private static class LabelAllocator { - int nextAvailableLabel; - - /** - * @param startLabel available label to start allocating from - */ - LabelAllocator(int startLabel) { - nextAvailableLabel = startLabel; - } - - /** - * @return next available label - */ - int getNextLabel() { - return nextAvailableLabel++; - } - } - - /** - * Allocates labels for exception setup blocks. - */ - private class ExceptionSetupLabelAllocator extends LabelAllocator { - int maxSetupLabel; - - ExceptionSetupLabelAllocator() { - super(maxLabel); - maxSetupLabel = maxLabel + method.getCatches().size(); - } - - @Override - int getNextLabel() { - if (nextAvailableLabel >= maxSetupLabel) { - throw new IndexOutOfBoundsException(); - } - return nextAvailableLabel ++; - } - } - - /** - * Inlines a subroutine. Start by calling - * {@link #inlineSubroutineCalledFrom}. - */ - private class SubroutineInliner { - /** - * maps original label to the label that will be used by the - * inlined version - */ - private final HashMap origLabelToCopiedLabel; - - /** set of original labels that need to be copied */ - private final BitSet workList; - - /** the label of the original start block for this subroutine */ - private int subroutineStart; - - /** the label of the ultimate return block */ - private int subroutineSuccessor; - - /** used for generating new labels for copied blocks */ - private final LabelAllocator labelAllocator; - - /** - * A mapping, indexed by label, to subroutine nesting list. - * The subroutine nest list is as returned by - * {@link Frame#getSubroutines}. - */ - private final ArrayList labelToSubroutines; - - SubroutineInliner(final LabelAllocator labelAllocator, - ArrayList labelToSubroutines) { - origLabelToCopiedLabel = new HashMap(); - - workList = new BitSet(maxLabel); - - this.labelAllocator = labelAllocator; - this.labelToSubroutines = labelToSubroutines; - } - - /** - * Inlines a subroutine. - * - * @param b block where {@code jsr} occurred in the original bytecode - */ - void inlineSubroutineCalledFrom(final BasicBlock b) { - /* - * The 0th successor of a subroutine caller block is where - * the subroutine should return to. The 1st successor is - * the start block of the subroutine. - */ - subroutineSuccessor = b.getSuccessors().get(0); - subroutineStart = b.getSuccessors().get(1); - - /* - * This allocates an initial label and adds the first - * block to the worklist. - */ - int newSubStartLabel = mapOrAllocateLabel(subroutineStart); - - for (int label = workList.nextSetBit(0); label >= 0; - label = workList.nextSetBit(0)) { - workList.clear(label); - int newLabel = origLabelToCopiedLabel.get(label); - - copyBlock(label, newLabel); - - if (isSubroutineCaller(labelToBlock(label))) { - new SubroutineInliner(labelAllocator, labelToSubroutines) - .inlineSubroutineCalledFrom(labelToBlock(newLabel)); - } - } - - /* - * Replace the original caller block, since we now have a - * new successor - */ - - addOrReplaceBlockNoDelete( - new BasicBlock(b.getLabel(), b.getInsns(), - IntList.makeImmutable (newSubStartLabel), - newSubStartLabel), - labelToSubroutines.get(b.getLabel())); - } - - /** - * Copies a basic block, mapping its successors along the way. - * - * @param origLabel original block label - * @param newLabel label that the new block should have - */ - private void copyBlock(int origLabel, int newLabel) { - - BasicBlock origBlock = labelToBlock(origLabel); - - final IntList origSuccessors = origBlock.getSuccessors(); - IntList successors; - int primarySuccessor = -1; - Subroutine subroutine; - - if (isSubroutineCaller(origBlock)) { - /* - * A subroutine call inside a subroutine call. - * Set up so we can recurse. The caller block should have - * it's first successor be a copied block that will be - * the subroutine's return point. It's second successor will - * be copied when we recurse, and remains as the original - * label of the start of the inner subroutine. - */ - - successors = IntList.makeImmutable( - mapOrAllocateLabel(origSuccessors.get(0)), - origSuccessors.get(1)); - // primary successor will be set when this block is replaced - } else if (null - != (subroutine = subroutineFromRetBlock(origLabel))) { - /* - * this is a ret block -- its successor - * should be subroutineSuccessor - */ - - // Sanity check - if (subroutine.startBlock != subroutineStart) { - throw new RuntimeException ( - "ret instruction returns to label " - + Hex.u2 (subroutine.startBlock) - + " expected: " + Hex.u2(subroutineStart)); - } - - successors = IntList.makeImmutable(subroutineSuccessor); - primarySuccessor = subroutineSuccessor; - } else { - // Map all the successor labels - - int origPrimary = origBlock.getPrimarySuccessor(); - int sz = origSuccessors.size(); - - successors = new IntList(sz); - - for (int i = 0 ; i < sz ; i++) { - int origSuccLabel = origSuccessors.get(i); - int newSuccLabel = mapOrAllocateLabel(origSuccLabel); - - successors.add(newSuccLabel); - - if (origPrimary == origSuccLabel) { - primarySuccessor = newSuccLabel; - } - } - - successors.setImmutable(); - } - - addBlock ( - new BasicBlock(newLabel, - filterMoveReturnAddressInsns(origBlock.getInsns()), - successors, primarySuccessor), - labelToSubroutines.get(newLabel)); - } - - /** - * Checks to see if a specified label is involved in a specified - * subroutine. - * - * @param label {@code >= 0;} a basic block label - * @param subroutineStart {@code >= 0;} a subroutine as identified - * by the label of its start block - * @return true if the block is dominated by the subroutine call - */ - private boolean involvedInSubroutine(int label, int subroutineStart) { - IntList subroutinesList = labelToSubroutines.get(label); - return (subroutinesList != null && subroutinesList.size() > 0 - && subroutinesList.top() == subroutineStart); - } - - /** - * Maps the label of a pre-copied block to the label of the inlined - * block, allocating a new label and adding it to the worklist - * if necessary. If the origLabel is a "special" label, it - * is returned exactly and not scheduled for duplication: copying - * never proceeds past a special label, which likely is the function - * return block or an immediate predecessor. - * - * @param origLabel label of original, pre-copied block - * @return label for new, inlined block - */ - private int mapOrAllocateLabel(int origLabel) { - int resultLabel; - Integer mappedLabel = origLabelToCopiedLabel.get(origLabel); - - if (mappedLabel != null) { - resultLabel = mappedLabel; - } else if (!involvedInSubroutine(origLabel,subroutineStart)) { - /* - * A subroutine has ended by some means other than a "ret" - * (which really means a throw caught later). - */ - resultLabel = origLabel; - } else { - resultLabel = labelAllocator.getNextLabel(); - workList.set(origLabel); - origLabelToCopiedLabel.put(origLabel, resultLabel); - - // The new label has the same frame as the original label - while (labelToSubroutines.size() <= resultLabel) { - labelToSubroutines.add(null); - } - labelToSubroutines.set(resultLabel, - labelToSubroutines.get(origLabel)); - } - - return resultLabel; - } - } - - /** - * Finds a {@code Subroutine} that is returned from by a {@code ret} in - * a given block. - * - * @param label A block that originally contained a {@code ret} instruction - * @return {@code null-ok;} found subroutine or {@code null} if none - * was found - */ - private Subroutine subroutineFromRetBlock(int label) { - for (int i = subroutines.length - 1 ; i >= 0 ; i--) { - if (subroutines[i] != null) { - Subroutine subroutine = subroutines[i]; - - if (subroutine.retBlocks.get(label)) { - return subroutine; - } - } - } - - return null; - } - - - /** - * Removes all {@code move-return-address} instructions, returning a new - * {@code InsnList} if necessary. The {@code move-return-address} - * insns are dead code after subroutines have been inlined. - * - * @param insns {@code InsnList} that may contain - * {@code move-return-address} insns - * @return {@code InsnList} with {@code move-return-address} removed - */ - private InsnList filterMoveReturnAddressInsns(InsnList insns) { - int sz; - int newSz = 0; - - // First see if we need to filter, and if so what the new size will be - sz = insns.size(); - for (int i = 0; i < sz; i++) { - if (insns.get(i).getOpcode() != Rops.MOVE_RETURN_ADDRESS) { - newSz++; - } - } - - if (newSz == sz) { - return insns; - } - - // Make a new list without the MOVE_RETURN_ADDRESS insns - InsnList newInsns = new InsnList(newSz); - - int newIndex = 0; - for (int i = 0; i < sz; i++) { - Insn insn = insns.get(i); - if (insn.getOpcode() != Rops.MOVE_RETURN_ADDRESS) { - newInsns.set(newIndex++, insn); - } - } - - newInsns.setImmutable(); - return newInsns; - } - - /** - * Visits each non-subroutine block once in depth-first successor order. - * - * @param firstLabel label of start block - * @param v callback interface - */ - private void forEachNonSubBlockDepthFirst(int firstLabel, - BasicBlock.Visitor v) { - forEachNonSubBlockDepthFirst0(labelToBlock(firstLabel), - v, new BitSet(maxLabel)); - } - - /** - * Visits each block once in depth-first successor order, ignoring - * {@code jsr} targets. Worker for {@link #forEachNonSubBlockDepthFirst}. - * - * @param next next block to visit - * @param v callback interface - * @param visited set of blocks already visited - */ - private void forEachNonSubBlockDepthFirst0( - BasicBlock next, BasicBlock.Visitor v, BitSet visited) { - v.visitBlock(next); - visited.set(next.getLabel()); - - IntList successors = next.getSuccessors(); - int sz = successors.size(); - - for (int i = 0; i < sz; i++) { - int succ = successors.get(i); - - if (visited.get(succ)) { - continue; - } - - if (isSubroutineCaller(next) && i > 0) { - // ignore jsr targets - continue; - } - - /* - * Ignore missing labels: they're successors of - * subroutines that never invoke a ret. - */ - int idx = labelToResultIndex(succ); - if (idx >= 0) { - forEachNonSubBlockDepthFirst0(result.get(idx), v, visited); - } - } - } -} diff --git a/app/src/main/java/com/pojavdx/dx/cf/code/RopperMachine.java b/app/src/main/java/com/pojavdx/dx/cf/code/RopperMachine.java deleted file mode 100644 index 3da307f7d..000000000 --- a/app/src/main/java/com/pojavdx/dx/cf/code/RopperMachine.java +++ /dev/null @@ -1,1032 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.pojavdx.dx.cf.code; - -import com.pojavdx.dx.cf.iface.Method; -import com.pojavdx.dx.cf.iface.MethodList; -import com.pojavdx.dx.rop.code.AccessFlags; -import com.pojavdx.dx.rop.code.FillArrayDataInsn; -import com.pojavdx.dx.rop.code.Insn; -import com.pojavdx.dx.rop.code.InvokePolymorphicInsn; -import com.pojavdx.dx.rop.code.PlainCstInsn; -import com.pojavdx.dx.rop.code.PlainInsn; -import com.pojavdx.dx.rop.code.RegOps; -import com.pojavdx.dx.rop.code.RegisterSpec; -import com.pojavdx.dx.rop.code.RegisterSpecList; -import com.pojavdx.dx.rop.code.Rop; -import com.pojavdx.dx.rop.code.Rops; -import com.pojavdx.dx.rop.code.SourcePosition; -import com.pojavdx.dx.rop.code.SwitchInsn; -import com.pojavdx.dx.rop.code.ThrowingCstInsn; -import com.pojavdx.dx.rop.code.ThrowingInsn; -import com.pojavdx.dx.rop.code.TranslationAdvice; -import com.pojavdx.dx.rop.cst.Constant; -import com.pojavdx.dx.rop.cst.CstCallSiteRef; -import com.pojavdx.dx.rop.cst.CstFieldRef; -import com.pojavdx.dx.rop.cst.CstInteger; -import com.pojavdx.dx.rop.cst.CstMethodRef; -import com.pojavdx.dx.rop.cst.CstNat; -import com.pojavdx.dx.rop.cst.CstString; -import com.pojavdx.dx.rop.cst.CstType; -import com.pojavdx.dx.rop.type.Type; -import com.pojavdx.dx.rop.type.TypeBearer; -import com.pojavdx.dx.rop.type.TypeList; -import com.pojavdx.dx.util.IntList; -import java.util.ArrayList; - -/** - * Machine implementation for use by {@link Ropper}. - */ -/*package*/ final class RopperMachine extends ValueAwareMachine { - /** {@code non-null;} array reflection class */ - private static final CstType ARRAY_REFLECT_TYPE = - new CstType(Type.internClassName("java/lang/reflect/Array")); - - /** - * {@code non-null;} method constant for use in converting - * {@code multianewarray} instructions - */ - private static final CstMethodRef MULTIANEWARRAY_METHOD = - new CstMethodRef(ARRAY_REFLECT_TYPE, - new CstNat(new CstString("newInstance"), - new CstString("(Ljava/lang/Class;[I)" + - "Ljava/lang/Object;"))); - - /** {@code non-null;} {@link Ropper} controlling this instance */ - private final Ropper ropper; - - /** {@code non-null;} method being converted */ - private final ConcreteMethod method; - - /** {@code non-null:} list of methods from the class whose method is being converted */ - private final MethodList methods; - - /** {@code non-null;} translation advice */ - private final TranslationAdvice advice; - - /** max locals of the method */ - private final int maxLocals; - - /** {@code non-null;} instructions for the rop basic block in-progress */ - private final ArrayList insns; - - /** {@code non-null;} catches for the block currently being processed */ - private TypeList catches; - - /** whether the catches have been used in an instruction */ - private boolean catchesUsed; - - /** whether the block contains a {@code return} */ - private boolean returns; - - /** primary successor index */ - private int primarySuccessorIndex; - - /** {@code >= 0;} number of extra basic blocks required */ - private int extraBlockCount; - - /** true if last processed block ends with a jsr or jsr_W*/ - private boolean hasJsr; - - /** true if an exception can be thrown by the last block processed */ - private boolean blockCanThrow; - - /** - * If non-null, the ReturnAddress that was used by the terminating ret - * instruction. If null, there was no ret instruction encountered. - */ - - private ReturnAddress returnAddress; - - /** - * {@code null-ok;} the appropriate {@code return} op or {@code null} - * if it is not yet known - */ - private Rop returnOp; - - /** - * {@code null-ok;} the source position for the return block or {@code null} - * if it is not yet known - */ - private SourcePosition returnPosition; - - /** - * Constructs an instance. - * - * @param ropper {@code non-null;} ropper controlling this instance - * @param method {@code non-null;} method being converted - * @param advice {@code non-null;} translation advice to use - * @param methods {@code non-null;} list of methods defined by the class - * that defines {@code method}. - */ - public RopperMachine(Ropper ropper, ConcreteMethod method, - TranslationAdvice advice, MethodList methods) { - super(method.getEffectiveDescriptor()); - - if (methods == null) { - throw new NullPointerException("methods == null"); - } - - if (ropper == null) { - throw new NullPointerException("ropper == null"); - } - - if (advice == null) { - throw new NullPointerException("advice == null"); - } - - this.ropper = ropper; - this.method = method; - this.methods = methods; - this.advice = advice; - this.maxLocals = method.getMaxLocals(); - this.insns = new ArrayList(25); - this.catches = null; - this.catchesUsed = false; - this.returns = false; - this.primarySuccessorIndex = -1; - this.extraBlockCount = 0; - this.blockCanThrow = false; - this.returnOp = null; - this.returnPosition = null; - } - - /** - * Gets the instructions array. It is shared and gets modified by - * subsequent calls to this instance. - * - * @return {@code non-null;} the instructions array - */ - public ArrayList getInsns() { - return insns; - } - - /** - * Gets the return opcode encountered, if any. - * - * @return {@code null-ok;} the return opcode - */ - public Rop getReturnOp() { - return returnOp; - } - - /** - * Gets the return position, if known. - * - * @return {@code null-ok;} the return position - */ - public SourcePosition getReturnPosition() { - return returnPosition; - } - - /** - * Gets ready to start working on a new block. This will clear the - * {@link #insns} list, set {@link #catches}, reset whether it has - * been used, reset whether the block contains a - * {@code return}, and reset {@link #primarySuccessorIndex}. - */ - public void startBlock(TypeList catches) { - this.catches = catches; - - insns.clear(); - catchesUsed = false; - returns = false; - primarySuccessorIndex = 0; - extraBlockCount = 0; - blockCanThrow = false; - hasJsr = false; - returnAddress = null; - } - - /** - * Gets whether {@link #catches} was used. This indicates that the - * last instruction in the block is one of the ones that can throw. - * - * @return whether {@code catches} has been used - */ - public boolean wereCatchesUsed() { - return catchesUsed; - } - - /** - * Gets whether the block just processed ended with a - * {@code return}. - * - * @return whether the block returns - */ - public boolean returns() { - return returns; - } - - /** - * Gets the primary successor index. This is the index into the - * successors list where the primary may be found or - * {@code -1} if there are successors but no primary - * successor. This may return something other than - * {@code -1} in the case of an instruction with no - * successors at all (primary or otherwise). - * - * @return {@code >= -1;} the primary successor index - */ - public int getPrimarySuccessorIndex() { - return primarySuccessorIndex; - } - - /** - * Gets how many extra blocks will be needed to represent the - * block currently being translated. Each extra block should consist - * of one instruction from the end of the original block. - * - * @return {@code >= 0;} the number of extra blocks needed - */ - public int getExtraBlockCount() { - return extraBlockCount; - } - - /** - * @return true if at least one of the insn processed since the last - * call to startBlock() can throw. - */ - public boolean canThrow() { - return blockCanThrow; - } - - /** - * @return true if a JSR has ben encountered since the last call to - * startBlock() - */ - public boolean hasJsr() { - return hasJsr; - } - - /** - * @return {@code true} if a {@code ret} has ben encountered since - * the last call to {@code startBlock()} - */ - public boolean hasRet() { - return returnAddress != null; - } - - /** - * @return {@code null-ok;} return address of a {@code ret} - * instruction if encountered since last call to startBlock(). - * {@code null} if no ret instruction encountered. - */ - public ReturnAddress getReturnAddress() { - return returnAddress; - } - - /** {@inheritDoc} */ - @Override - public void run(Frame frame, int offset, int opcode) { - /* - * This is the stack pointer after the opcode's arguments have been - * popped. - */ - int stackPointer = maxLocals + frame.getStack().size(); - - // The sources have to be retrieved before super.run() gets called. - RegisterSpecList sources = getSources(opcode, stackPointer); - int sourceCount = sources.size(); - - super.run(frame, offset, opcode); - - SourcePosition pos = method.makeSourcePosistion(offset); - RegisterSpec localTarget = getLocalTarget(opcode == ByteOps.ISTORE); - int destCount = resultCount(); - RegisterSpec dest; - - if (destCount == 0) { - dest = null; - switch (opcode) { - case ByteOps.POP: - case ByteOps.POP2: { - // These simply don't appear in the rop form. - return; - } - } - } else if (localTarget != null) { - dest = localTarget; - } else if (destCount == 1) { - dest = RegisterSpec.make(stackPointer, result(0)); - } else { - /* - * This clause only ever applies to the stack manipulation - * ops that have results (that is, dup* and swap but not - * pop*). - * - * What we do is first move all the source registers into - * the "temporary stack" area defined for the method, and - * then move stuff back down onto the main "stack" in the - * arrangement specified by the stack op pattern. - * - * Note: This code ends up emitting a lot of what will - * turn out to be superfluous moves (e.g., moving back and - * forth to the same local when doing a dup); however, - * that makes this code a bit easier (and goodness knows - * it doesn't need any extra complexity), and all the SSA - * stuff is going to want to deal with this sort of - * superfluous assignment anyway, so it should be a wash - * in the end. - */ - int scratchAt = ropper.getFirstTempStackReg(); - RegisterSpec[] scratchRegs = new RegisterSpec[sourceCount]; - - for (int i = 0; i < sourceCount; i++) { - RegisterSpec src = sources.get(i); - TypeBearer type = src.getTypeBearer(); - RegisterSpec scratch = src.withReg(scratchAt); - insns.add(new PlainInsn(Rops.opMove(type), pos, scratch, src)); - scratchRegs[i] = scratch; - scratchAt += src.getCategory(); - } - - for (int pattern = getAuxInt(); pattern != 0; pattern >>= 4) { - int which = (pattern & 0x0f) - 1; - RegisterSpec scratch = scratchRegs[which]; - TypeBearer type = scratch.getTypeBearer(); - insns.add(new PlainInsn(Rops.opMove(type), pos, - scratch.withReg(stackPointer), - scratch)); - stackPointer += type.getType().getCategory(); - } - return; - } - - TypeBearer destType = (dest != null) ? (TypeBearer) dest : Type.VOID; - Constant cst = getAuxCst(); - int ropOpcode; - Rop rop; - Insn insn; - - if (opcode == ByteOps.MULTIANEWARRAY) { - blockCanThrow = true; - - // Add the extra instructions for handling multianewarray. - - extraBlockCount = 6; - - /* - * Add an array constructor for the int[] containing all the - * dimensions. - */ - RegisterSpec dimsReg = - RegisterSpec.make(dest.getNextReg(), Type.INT_ARRAY); - rop = Rops.opFilledNewArray(Type.INT_ARRAY, sourceCount); - insn = new ThrowingCstInsn(rop, pos, sources, catches, - CstType.INT_ARRAY); - insns.add(insn); - - // Add a move-result for the new-filled-array - rop = Rops.opMoveResult(Type.INT_ARRAY); - insn = new PlainInsn(rop, pos, dimsReg, RegisterSpecList.EMPTY); - insns.add(insn); - - /* - * Add a const-class instruction for the specified array - * class. - */ - - /* - * Remove as many dimensions from the originally specified - * class as are given in the explicit list of dimensions, - * so as to pass the right component class to the standard - * Java library array constructor. - */ - Type componentType = ((CstType) cst).getClassType(); - for (int i = 0; i < sourceCount; i++) { - componentType = componentType.getComponentType(); - } - - RegisterSpec classReg = - RegisterSpec.make(dest.getReg(), Type.CLASS); - - if (componentType.isPrimitive()) { - /* - * The component type is primitive (e.g., int as opposed - * to Integer), so we have to fetch the corresponding - * TYPE class. - */ - CstFieldRef typeField = - CstFieldRef.forPrimitiveType(componentType); - insn = new ThrowingCstInsn(Rops.GET_STATIC_OBJECT, pos, - RegisterSpecList.EMPTY, - catches, typeField); - } else { - /* - * The component type is an object type, so just make a - * normal class reference. - */ - insn = new ThrowingCstInsn(Rops.CONST_OBJECT, pos, - RegisterSpecList.EMPTY, catches, - new CstType(componentType)); - } - - insns.add(insn); - - // Add a move-result-pseudo for the get-static or const - rop = Rops.opMoveResultPseudo(classReg.getType()); - insn = new PlainInsn(rop, pos, classReg, RegisterSpecList.EMPTY); - insns.add(insn); - - /* - * Add a call to the "multianewarray method," that is, - * Array.newInstance(class, dims). Note: The result type - * of newInstance() is Object, which is why the last - * instruction in this sequence is a cast to the right - * type for the original instruction. - */ - - RegisterSpec objectReg = - RegisterSpec.make(dest.getReg(), Type.OBJECT); - - insn = new ThrowingCstInsn( - Rops.opInvokeStatic(MULTIANEWARRAY_METHOD.getPrototype()), - pos, RegisterSpecList.make(classReg, dimsReg), - catches, MULTIANEWARRAY_METHOD); - insns.add(insn); - - // Add a move-result. - rop = Rops.opMoveResult(MULTIANEWARRAY_METHOD.getPrototype() - .getReturnType()); - insn = new PlainInsn(rop, pos, objectReg, RegisterSpecList.EMPTY); - insns.add(insn); - - /* - * And finally, set up for the remainder of this method to - * add an appropriate cast. - */ - - opcode = ByteOps.CHECKCAST; - sources = RegisterSpecList.make(objectReg); - } else if (opcode == ByteOps.JSR) { - // JSR has no Rop instruction - hasJsr = true; - return; - } else if (opcode == ByteOps.RET) { - try { - returnAddress = (ReturnAddress)arg(0); - } catch (ClassCastException ex) { - throw new RuntimeException( - "Argument to RET was not a ReturnAddress", ex); - } - // RET has no Rop instruction. - return; - } - - ropOpcode = jopToRopOpcode(opcode, cst); - rop = Rops.ropFor(ropOpcode, destType, sources, cst); - - Insn moveResult = null; - if (dest != null && rop.isCallLike()) { - /* - * We're going to want to have a move-result in the next - * basic block. - */ - extraBlockCount++; - - Type returnType; - if (rop.getOpcode() == RegOps.INVOKE_CUSTOM) { - returnType = ((CstCallSiteRef) cst).getReturnType(); - } else { - returnType = ((CstMethodRef) cst).getPrototype().getReturnType(); - } - moveResult = new PlainInsn(Rops.opMoveResult(returnType), - pos, dest, RegisterSpecList.EMPTY); - - dest = null; - } else if (dest != null && rop.canThrow()) { - /* - * We're going to want to have a move-result-pseudo in the - * next basic block. - */ - extraBlockCount++; - - moveResult = new PlainInsn( - Rops.opMoveResultPseudo(dest.getTypeBearer()), - pos, dest, RegisterSpecList.EMPTY); - - dest = null; - } - if (ropOpcode == RegOps.NEW_ARRAY) { - /* - * In the original bytecode, this was either a primitive - * array constructor "newarray" or an object array - * constructor "anewarray". In the former case, there is - * no explicit constant, and in the latter, the constant - * is for the element type and not the array type. The rop - * instruction form for both of these is supposed to be - * the resulting array type, so we initialize / alter - * "cst" here, accordingly. Conveniently enough, the rop - * opcode already gets constructed with the proper array - * type. - */ - cst = CstType.intern(rop.getResult()); - } else if ((cst == null) && (sourceCount == 2)) { - TypeBearer firstType = sources.get(0).getTypeBearer(); - TypeBearer lastType = sources.get(1).getTypeBearer(); - - if ((lastType.isConstant() || firstType.isConstant()) && - advice.hasConstantOperation(rop, sources.get(0), - sources.get(1))) { - - if (lastType.isConstant()) { - /* - * The target architecture has an instruction that can - * build in the constant found in the second argument, - * so pull it out of the sources and just use it as a - * constant here. - */ - cst = (Constant) lastType; - sources = sources.withoutLast(); - - // For subtraction, change to addition and invert constant - if (rop.getOpcode() == RegOps.SUB) { - ropOpcode = RegOps.ADD; - CstInteger cstInt = (CstInteger) lastType; - cst = CstInteger.make(-cstInt.getValue()); - } - } else { - /* - * The target architecture has an instruction that can - * build in the constant found in the first argument, - * so pull it out of the sources and just use it as a - * constant here. - */ - cst = (Constant) firstType; - sources = sources.withoutFirst(); - } - - rop = Rops.ropFor(ropOpcode, destType, sources, cst); - } - } - - SwitchList cases = getAuxCases(); - ArrayList initValues = getInitValues(); - boolean canThrow = rop.canThrow(); - - blockCanThrow |= canThrow; - - if (cases != null) { - if (cases.size() == 0) { - // It's a default-only switch statement. It can happen! - insn = new PlainInsn(Rops.GOTO, pos, null, - RegisterSpecList.EMPTY); - primarySuccessorIndex = 0; - } else { - IntList values = cases.getValues(); - insn = new SwitchInsn(rop, pos, dest, sources, values); - primarySuccessorIndex = values.size(); - } - } else if (ropOpcode == RegOps.RETURN) { - /* - * Returns get turned into the combination of a move (if - * non-void and if the return doesn't already mention - * register 0) and a goto (to the return block). - */ - if (sources.size() != 0) { - RegisterSpec source = sources.get(0); - TypeBearer type = source.getTypeBearer(); - if (source.getReg() != 0) { - insns.add(new PlainInsn(Rops.opMove(type), pos, - RegisterSpec.make(0, type), - source)); - } - } - insn = new PlainInsn(Rops.GOTO, pos, null, RegisterSpecList.EMPTY); - primarySuccessorIndex = 0; - updateReturnOp(rop, pos); - returns = true; - } else if (cst != null) { - if (canThrow) { - if (rop.getOpcode() == RegOps.INVOKE_POLYMORPHIC) { - insn = makeInvokePolymorphicInsn(rop, pos, sources, catches, cst); - } else { - insn = new ThrowingCstInsn(rop, pos, sources, catches, cst); - } - catchesUsed = true; - primarySuccessorIndex = catches.size(); - } else { - insn = new PlainCstInsn(rop, pos, dest, sources, cst); - } - } else if (canThrow) { - insn = new ThrowingInsn(rop, pos, sources, catches); - catchesUsed = true; - if (opcode == ByteOps.ATHROW) { - /* - * The op athrow is the only one where it's possible - * to have non-empty successors and yet not have a - * primary successor. - */ - primarySuccessorIndex = -1; - } else { - primarySuccessorIndex = catches.size(); - } - } else { - insn = new PlainInsn(rop, pos, dest, sources); - } - - insns.add(insn); - - if (moveResult != null) { - insns.add(moveResult); - } - - /* - * If initValues is non-null, it means that the parser has - * seen a group of compatible constant initialization - * bytecodes that are applied to the current newarray. The - * action we take here is to convert these initialization - * bytecodes into a single fill-array-data ROP which lays out - * all the constant values in a table. - */ - if (initValues != null) { - extraBlockCount++; - insn = new FillArrayDataInsn(Rops.FILL_ARRAY_DATA, pos, - RegisterSpecList.make(moveResult.getResult()), initValues, - cst); - insns.add(insn); - } - } - - /** - * Helper for {@link #run}, which gets the list of sources for the. - * instruction. - * - * @param opcode the opcode being translated - * @param stackPointer {@code >= 0;} the stack pointer after the - * instruction's arguments have been popped - * @return {@code non-null;} the sources - */ - private RegisterSpecList getSources(int opcode, int stackPointer) { - int count = argCount(); - - if (count == 0) { - // We get an easy out if there aren't any sources. - return RegisterSpecList.EMPTY; - } - - int localIndex = getLocalIndex(); - RegisterSpecList sources; - - if (localIndex >= 0) { - // The instruction is operating on a local variable. - sources = new RegisterSpecList(1); - sources.set(0, RegisterSpec.make(localIndex, arg(0))); - } else { - sources = new RegisterSpecList(count); - int regAt = stackPointer; - for (int i = 0; i < count; i++) { - RegisterSpec spec = RegisterSpec.make(regAt, arg(i)); - sources.set(i, spec); - regAt += spec.getCategory(); - } - - switch (opcode) { - case ByteOps.IASTORE: { - /* - * The Java argument order for array stores is - * (array, index, value), but the rop argument - * order is (value, array, index). The following - * code gets the right arguments in the right - * places. - */ - if (count != 3) { - throw new RuntimeException("shouldn't happen"); - } - RegisterSpec array = sources.get(0); - RegisterSpec index = sources.get(1); - RegisterSpec value = sources.get(2); - sources.set(0, value); - sources.set(1, array); - sources.set(2, index); - break; - } - case ByteOps.PUTFIELD: { - /* - * Similar to above: The Java argument order for - * putfield is (object, value), but the rop - * argument order is (value, object). - */ - if (count != 2) { - throw new RuntimeException("shouldn't happen"); - } - RegisterSpec obj = sources.get(0); - RegisterSpec value = sources.get(1); - sources.set(0, value); - sources.set(1, obj); - break; - } - } - } - - sources.setImmutable(); - return sources; - } - - /** - * Sets or updates the information about the return block. - * - * @param op {@code non-null;} the opcode to use - * @param pos {@code non-null;} the position to use - */ - private void updateReturnOp(Rop op, SourcePosition pos) { - if (op == null) { - throw new NullPointerException("op == null"); - } - - if (pos == null) { - throw new NullPointerException("pos == null"); - } - - if (returnOp == null) { - returnOp = op; - returnPosition = pos; - } else { - if (returnOp != op) { - throw new SimException("return op mismatch: " + op + ", " + - returnOp); - } - - if (pos.getLine() > returnPosition.getLine()) { - // Pick the largest line number to be the "canonical" return. - returnPosition = pos; - } - } - } - - /** - * Gets the register opcode for the given Java opcode. - * - * @param jop {@code jop >= 0;} the Java opcode - * @param cst {@code null-ok;} the constant argument, if any - * @return {@code >= 0;} the corresponding register opcode - */ - private int jopToRopOpcode(int jop, Constant cst) { - switch (jop) { - case ByteOps.POP: - case ByteOps.POP2: - case ByteOps.DUP: - case ByteOps.DUP_X1: - case ByteOps.DUP_X2: - case ByteOps.DUP2: - case ByteOps.DUP2_X1: - case ByteOps.DUP2_X2: - case ByteOps.SWAP: - case ByteOps.JSR: - case ByteOps.RET: - case ByteOps.MULTIANEWARRAY: { - // These need to be taken care of specially. - break; - } - case ByteOps.NOP: { - return RegOps.NOP; - } - case ByteOps.LDC: - case ByteOps.LDC2_W: { - return RegOps.CONST; - } - case ByteOps.ILOAD: - case ByteOps.ISTORE: { - return RegOps.MOVE; - } - case ByteOps.IALOAD: { - return RegOps.AGET; - } - case ByteOps.IASTORE: { - return RegOps.APUT; - } - case ByteOps.IADD: - case ByteOps.IINC: { - return RegOps.ADD; - } - case ByteOps.ISUB: { - return RegOps.SUB; - } - case ByteOps.IMUL: { - return RegOps.MUL; - } - case ByteOps.IDIV: { - return RegOps.DIV; - } - case ByteOps.IREM: { - return RegOps.REM; - } - case ByteOps.INEG: { - return RegOps.NEG; - } - case ByteOps.ISHL: { - return RegOps.SHL; - } - case ByteOps.ISHR: { - return RegOps.SHR; - } - case ByteOps.IUSHR: { - return RegOps.USHR; - } - case ByteOps.IAND: { - return RegOps.AND; - } - case ByteOps.IOR: { - return RegOps.OR; - } - case ByteOps.IXOR: { - return RegOps.XOR; - } - case ByteOps.I2L: - case ByteOps.I2F: - case ByteOps.I2D: - case ByteOps.L2I: - case ByteOps.L2F: - case ByteOps.L2D: - case ByteOps.F2I: - case ByteOps.F2L: - case ByteOps.F2D: - case ByteOps.D2I: - case ByteOps.D2L: - case ByteOps.D2F: { - return RegOps.CONV; - } - case ByteOps.I2B: { - return RegOps.TO_BYTE; - } - case ByteOps.I2C: { - return RegOps.TO_CHAR; - } - case ByteOps.I2S: { - return RegOps.TO_SHORT; - } - case ByteOps.LCMP: - case ByteOps.FCMPL: - case ByteOps.DCMPL: { - return RegOps.CMPL; - } - case ByteOps.FCMPG: - case ByteOps.DCMPG: { - return RegOps.CMPG; - } - case ByteOps.IFEQ: - case ByteOps.IF_ICMPEQ: - case ByteOps.IF_ACMPEQ: - case ByteOps.IFNULL: { - return RegOps.IF_EQ; - } - case ByteOps.IFNE: - case ByteOps.IF_ICMPNE: - case ByteOps.IF_ACMPNE: - case ByteOps.IFNONNULL: { - return RegOps.IF_NE; - } - case ByteOps.IFLT: - case ByteOps.IF_ICMPLT: { - return RegOps.IF_LT; - } - case ByteOps.IFGE: - case ByteOps.IF_ICMPGE: { - return RegOps.IF_GE; - } - case ByteOps.IFGT: - case ByteOps.IF_ICMPGT: { - return RegOps.IF_GT; - } - case ByteOps.IFLE: - case ByteOps.IF_ICMPLE: { - return RegOps.IF_LE; - } - case ByteOps.GOTO: { - return RegOps.GOTO; - } - case ByteOps.LOOKUPSWITCH: { - return RegOps.SWITCH; - } - case ByteOps.IRETURN: - case ByteOps.RETURN: { - return RegOps.RETURN; - } - case ByteOps.GETSTATIC: { - return RegOps.GET_STATIC; - } - case ByteOps.PUTSTATIC: { - return RegOps.PUT_STATIC; - } - case ByteOps.GETFIELD: { - return RegOps.GET_FIELD; - } - case ByteOps.PUTFIELD: { - return RegOps.PUT_FIELD; - } - case ByteOps.INVOKEVIRTUAL: { - CstMethodRef ref = (CstMethodRef) cst; - // The java bytecode specification does not explicitly disallow - // invokevirtual calls to any instance method, though it - // specifies that instance methods and private methods "should" be - // called using "invokespecial" instead of "invokevirtual". - // Several bytecode tools generate "invokevirtual" instructions for - // invocation of private methods. - // - // The dalvik opcode specification on the other hand allows - // invoke-virtual to be used only with "normal" virtual methods, - // i.e, ones that are not private, static, final or constructors. - // We therefore need to transform invoke-virtual calls to private - // instance methods to invoke-direct opcodes. - // - // Note that it assumes that all methods for a given class are - // defined in the same dex file. - // - // NOTE: This is a slow O(n) loop, and can be replaced with a - // faster implementation (at the cost of higher memory usage) - // if it proves to be a hot area of code. - if (ref.getDefiningClass().equals(method.getDefiningClass())) { - for (int i = 0; i < methods.size(); ++i) { - final Method m = methods.get(i); - if (AccessFlags.isPrivate(m.getAccessFlags()) && - ref.getNat().equals(m.getNat())) { - return RegOps.INVOKE_DIRECT; - } - } - } - // If the method reference is a signature polymorphic method - // substitute invoke-polymorphic for invoke-virtual. This only - // affects MethodHandle.invoke and MethodHandle.invokeExact. - if (ref.isSignaturePolymorphic()) { - return RegOps.INVOKE_POLYMORPHIC; - } - return RegOps.INVOKE_VIRTUAL; - } - case ByteOps.INVOKESPECIAL: { - /* - * Determine whether the opcode should be - * INVOKE_DIRECT or INVOKE_SUPER. See vmspec-2 section 6 - * on "invokespecial" as well as section 4.8.2 (7th - * bullet point) for the gory details. - */ - /* TODO: Consider checking that invoke-special target - * method is private, or constructor since otherwise ART - * verifier will reject it. - */ - CstMethodRef ref = (CstMethodRef) cst; - if (ref.isInstanceInit() || - (ref.getDefiningClass().equals(method.getDefiningClass()))) { - return RegOps.INVOKE_DIRECT; - } - return RegOps.INVOKE_SUPER; - } - case ByteOps.INVOKESTATIC: { - return RegOps.INVOKE_STATIC; - } - case ByteOps.INVOKEINTERFACE: { - return RegOps.INVOKE_INTERFACE; - } - case ByteOps.INVOKEDYNAMIC: { - return RegOps.INVOKE_CUSTOM; - } - case ByteOps.NEW: { - return RegOps.NEW_INSTANCE; - } - case ByteOps.NEWARRAY: - case ByteOps.ANEWARRAY: { - return RegOps.NEW_ARRAY; - } - case ByteOps.ARRAYLENGTH: { - return RegOps.ARRAY_LENGTH; - } - case ByteOps.ATHROW: { - return RegOps.THROW; - } - case ByteOps.CHECKCAST: { - return RegOps.CHECK_CAST; - } - case ByteOps.INSTANCEOF: { - return RegOps.INSTANCE_OF; - } - case ByteOps.MONITORENTER: { - return RegOps.MONITOR_ENTER; - } - case ByteOps.MONITOREXIT: { - return RegOps.MONITOR_EXIT; - } - } - - throw new RuntimeException("shouldn't happen"); - } - - private Insn makeInvokePolymorphicInsn(Rop rop, SourcePosition pos, RegisterSpecList sources, - TypeList catches, Constant cst) { - CstMethodRef cstMethodRef = (CstMethodRef) cst; - return new InvokePolymorphicInsn(rop, pos, sources, catches, cstMethodRef); - } -} diff --git a/app/src/main/java/com/pojavdx/dx/cf/code/SimException.java b/app/src/main/java/com/pojavdx/dx/cf/code/SimException.java deleted file mode 100644 index bb146375c..000000000 --- a/app/src/main/java/com/pojavdx/dx/cf/code/SimException.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.pojavdx.dx.cf.code; - -import com.pojavdx.dex.util.ExceptionWithContext; - -/** - * Exception from simulation. - */ -public class SimException - extends ExceptionWithContext { - public SimException(String message) { - super(message); - } - - public SimException(Throwable cause) { - super(cause); - } - - public SimException(String message, Throwable cause) { - super(message, cause); - } -} diff --git a/app/src/main/java/com/pojavdx/dx/cf/code/Simulator.java b/app/src/main/java/com/pojavdx/dx/cf/code/Simulator.java deleted file mode 100644 index 494db935e..000000000 --- a/app/src/main/java/com/pojavdx/dx/cf/code/Simulator.java +++ /dev/null @@ -1,955 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.pojavdx.dx.cf.code; - -import com.pojavdx.dex.DexFormat; -import com.pojavdx.dx.dex.DexOptions; -import com.pojavdx.dx.rop.code.LocalItem; -import com.pojavdx.dx.rop.cst.Constant; -import com.pojavdx.dx.rop.cst.CstFieldRef; -import com.pojavdx.dx.rop.cst.CstInteger; -import com.pojavdx.dx.rop.cst.CstInterfaceMethodRef; -import com.pojavdx.dx.rop.cst.CstInvokeDynamic; -import com.pojavdx.dx.rop.cst.CstMethodHandle; -import com.pojavdx.dx.rop.cst.CstMethodRef; -import com.pojavdx.dx.rop.cst.CstProtoRef; -import com.pojavdx.dx.rop.cst.CstType; -import com.pojavdx.dx.rop.type.Prototype; -import com.pojavdx.dx.rop.type.Type; -import com.pojavdx.dx.util.Hex; -import java.util.ArrayList; - -/** - * Class which knows how to simulate the effects of executing bytecode. - * - *

Note: This class is not thread-safe. If multiple threads - * need to use a single instance, they must synchronize access explicitly - * between themselves.

- */ -public class Simulator { - /** - * {@code non-null;} canned error message for local variable - * table mismatches - */ - private static final String LOCAL_MISMATCH_ERROR = - "This is symptomatic of .class transformation tools that ignore " + - "local variable information."; - - /** {@code non-null;} machine to use when simulating */ - private final Machine machine; - - /** {@code non-null;} array of bytecode */ - private final BytecodeArray code; - - /** {@code non-null;} the method being simulated */ - private ConcreteMethod method; - - /** {@code non-null;} local variable information */ - private final LocalVariableList localVariables; - - /** {@code non-null;} visitor instance to use */ - private final SimVisitor visitor; - - /** {@code non-null;} options for dex output */ - private final DexOptions dexOptions; - - /** - * Constructs an instance. - * - * @param machine {@code non-null;} machine to use when simulating - * @param method {@code non-null;} method data to use - * @param dexOptions {@code non-null;} options for dex output - */ - public Simulator(Machine machine, ConcreteMethod method, DexOptions dexOptions) { - if (machine == null) { - throw new NullPointerException("machine == null"); - } - - if (method == null) { - throw new NullPointerException("method == null"); - } - - if (dexOptions == null) { - throw new NullPointerException("dexOptions == null"); - } - - this.machine = machine; - this.code = method.getCode(); - this.method = method; - this.localVariables = method.getLocalVariables(); - this.visitor = new SimVisitor(); - this.dexOptions = dexOptions; - - // This check assumes class is initialized (accesses dexOptions). - if (method.isDefaultOrStaticInterfaceMethod()) { - checkInterfaceMethodDeclaration(method); - } - } - - /** - * Simulates the effect of executing the given basic block. This modifies - * the passed-in frame to represent the end result. - * - * @param bb {@code non-null;} the basic block - * @param frame {@code non-null;} frame to operate on - */ - public void simulate(ByteBlock bb, Frame frame) { - int end = bb.getEnd(); - - visitor.setFrame(frame); - - try { - for (int off = bb.getStart(); off < end; /*off*/) { - int length = code.parseInstruction(off, visitor); - visitor.setPreviousOffset(off); - off += length; - } - } catch (SimException ex) { - frame.annotate(ex); - throw ex; - } - } - - /** - * Simulates the effect of the instruction at the given offset, by - * making appropriate calls on the given frame. - * - * @param offset {@code offset >= 0;} offset of the instruction to simulate - * @param frame {@code non-null;} frame to operate on - * @return the length of the instruction, in bytes - */ - public int simulate(int offset, Frame frame) { - visitor.setFrame(frame); - return code.parseInstruction(offset, visitor); - } - - /** - * Constructs an "illegal top-of-stack" exception, for the stack - * manipulation opcodes. - */ - private static SimException illegalTos() { - return new SimException("stack mismatch: illegal " + - "top-of-stack for opcode"); - } - - /** - * Returns the required array type for an array load or store - * instruction, based on a given implied type and an observed - * actual array type. - * - *

The interesting cases here have to do with object arrays, - * byte[]s, boolean[]s, and - * known-nulls.

- * - *

In the case of arrays of objects, we want to narrow the type - * to the actual array present on the stack, as long as what is - * present is an object type. Similarly, due to a quirk of the - * original bytecode representation, the instructions for dealing - * with byte[] and boolean[] are - * undifferentiated, and we aim here to return whichever one was - * actually present on the stack.

- * - *

In the case where there is a known-null on the stack where - * an array is expected, our behavior depends on the implied type - * of the instruction. When the implied type is a reference, we - * don't attempt to infer anything, as we don't know the dimension - * of the null constant and thus any explicit inferred type could - * be wrong. When the implied type is a primitive, we fall back to - * the implied type of the instruction. Due to the quirk described - * above, this means that source code that uses - * boolean[] might get translated surprisingly -- but - * correctly -- into an instruction that specifies a - * byte[]. It will be correct, because should the - * code actually execute, it will necessarily throw a - * NullPointerException, and it won't matter what - * opcode variant is used to achieve that result.

- * - * @param impliedType {@code non-null;} type implied by the - * instruction; is not an array type - * @param foundArrayType {@code non-null;} type found on the - * stack; is either an array type or a known-null - * @return {@code non-null;} the array type that should be - * required in this context - */ - private static Type requiredArrayTypeFor(Type impliedType, - Type foundArrayType) { - if (foundArrayType == Type.KNOWN_NULL) { - return impliedType.isReference() - ? Type.KNOWN_NULL - : impliedType.getArrayType(); - } - - if ((impliedType == Type.OBJECT) - && foundArrayType.isArray() - && foundArrayType.getComponentType().isReference()) { - return foundArrayType; - } - - if ((impliedType == Type.BYTE) - && (foundArrayType == Type.BOOLEAN_ARRAY)) { - /* - * Per above, an instruction with implied byte[] is also - * allowed to be used on boolean[]. - */ - return Type.BOOLEAN_ARRAY; - } - - return impliedType.getArrayType(); - } - - /** - * Bytecode visitor used during simulation. - */ - private class SimVisitor implements BytecodeArray.Visitor { - /** - * {@code non-null;} machine instance to use (just to avoid excessive - * cross-object field access) - */ - private final Machine machine; - - /** - * {@code null-ok;} frame to use; set with each call to - * {@link Simulator#simulate} - */ - private Frame frame; - - /** offset of the previous bytecode */ - private int previousOffset; - - /** - * Constructs an instance. - */ - public SimVisitor() { - this.machine = Simulator.this.machine; - this.frame = null; - } - - /** - * Sets the frame to act on. - * - * @param frame {@code non-null;} the frame - */ - public void setFrame(Frame frame) { - if (frame == null) { - throw new NullPointerException("frame == null"); - } - - this.frame = frame; - } - - /** {@inheritDoc} */ - @Override - public void visitInvalid(int opcode, int offset, int length) { - throw new SimException("invalid opcode " + Hex.u1(opcode)); - } - - /** {@inheritDoc} */ - @Override - public void visitNoArgs(int opcode, int offset, int length, - Type type) { - switch (opcode) { - case ByteOps.NOP: { - machine.clearArgs(); - break; - } - case ByteOps.INEG: { - machine.popArgs(frame, type); - break; - } - case ByteOps.I2L: - case ByteOps.I2F: - case ByteOps.I2D: - case ByteOps.I2B: - case ByteOps.I2C: - case ByteOps.I2S: { - machine.popArgs(frame, Type.INT); - break; - } - case ByteOps.L2I: - case ByteOps.L2F: - case ByteOps.L2D: { - machine.popArgs(frame, Type.LONG); - break; - } - case ByteOps.F2I: - case ByteOps.F2L: - case ByteOps.F2D: { - machine.popArgs(frame, Type.FLOAT); - break; - } - case ByteOps.D2I: - case ByteOps.D2L: - case ByteOps.D2F: { - machine.popArgs(frame, Type.DOUBLE); - break; - } - case ByteOps.RETURN: { - machine.clearArgs(); - checkReturnType(Type.VOID); - break; - } - case ByteOps.IRETURN: { - Type checkType = type; - if (type == Type.OBJECT) { - /* - * For an object return, use the best-known - * type of the popped value. - */ - checkType = frame.getStack().peekType(0); - } - machine.popArgs(frame, type); - checkReturnType(checkType); - break; - } - case ByteOps.POP: { - Type peekType = frame.getStack().peekType(0); - if (peekType.isCategory2()) { - throw illegalTos(); - } - machine.popArgs(frame, 1); - break; - } - case ByteOps.ARRAYLENGTH: { - Type arrayType = frame.getStack().peekType(0); - if (!arrayType.isArrayOrKnownNull()) { - fail("type mismatch: expected array type but encountered " + - arrayType.toHuman()); - } - machine.popArgs(frame, Type.OBJECT); - break; - } - case ByteOps.ATHROW: - case ByteOps.MONITORENTER: - case ByteOps.MONITOREXIT: { - machine.popArgs(frame, Type.OBJECT); - break; - } - case ByteOps.IALOAD: { - /* - * See comment on requiredArrayTypeFor() for explanation - * about what's going on here. - */ - Type foundArrayType = frame.getStack().peekType(1); - Type requiredArrayType = - requiredArrayTypeFor(type, foundArrayType); - - // Make type agree with the discovered requiredArrayType. - type = (requiredArrayType == Type.KNOWN_NULL) - ? Type.KNOWN_NULL - : requiredArrayType.getComponentType(); - - machine.popArgs(frame, requiredArrayType, Type.INT); - break; - } - case ByteOps.IADD: - case ByteOps.ISUB: - case ByteOps.IMUL: - case ByteOps.IDIV: - case ByteOps.IREM: - case ByteOps.IAND: - case ByteOps.IOR: - case ByteOps.IXOR: { - machine.popArgs(frame, type, type); - break; - } - case ByteOps.ISHL: - case ByteOps.ISHR: - case ByteOps.IUSHR: { - machine.popArgs(frame, type, Type.INT); - break; - } - case ByteOps.LCMP: { - machine.popArgs(frame, Type.LONG, Type.LONG); - break; - } - case ByteOps.FCMPL: - case ByteOps.FCMPG: { - machine.popArgs(frame, Type.FLOAT, Type.FLOAT); - break; - } - case ByteOps.DCMPL: - case ByteOps.DCMPG: { - machine.popArgs(frame, Type.DOUBLE, Type.DOUBLE); - break; - } - case ByteOps.IASTORE: { - /* - * See comment on requiredArrayTypeFor() for - * explanation about what's going on here. In - * addition to that, the category 1 vs. 2 thing - * below is to deal with the fact that, if the - * element type is category 2, we have to skip - * over one extra stack slot to find the array. - */ - ExecutionStack stack = frame.getStack(); - int peekDepth = type.isCategory1() ? 2 : 3; - Type foundArrayType = stack.peekType(peekDepth); - boolean foundArrayLocal = stack.peekLocal(peekDepth); - - Type requiredArrayType = - requiredArrayTypeFor(type, foundArrayType); - - /* - * Make type agree with the discovered requiredArrayType - * if it has local info. - */ - if (foundArrayLocal) { - type = (requiredArrayType == Type.KNOWN_NULL) - ? Type.KNOWN_NULL - : requiredArrayType.getComponentType(); - } - - machine.popArgs(frame, requiredArrayType, Type.INT, type); - break; - } - case ByteOps.POP2: - case ByteOps.DUP2: { - ExecutionStack stack = frame.getStack(); - int pattern; - - if (stack.peekType(0).isCategory2()) { - // "form 2" in vmspec-2 - machine.popArgs(frame, 1); - pattern = 0x11; - } else if (stack.peekType(1).isCategory1()) { - // "form 1" - machine.popArgs(frame, 2); - pattern = 0x2121; - } else { - throw illegalTos(); - } - - if (opcode == ByteOps.DUP2) { - machine.auxIntArg(pattern); - } - break; - } - case ByteOps.DUP: { - Type peekType = frame.getStack().peekType(0); - - if (peekType.isCategory2()) { - throw illegalTos(); - } - - machine.popArgs(frame, 1); - machine.auxIntArg(0x11); - break; - } - case ByteOps.DUP_X1: { - ExecutionStack stack = frame.getStack(); - - if (!(stack.peekType(0).isCategory1() && - stack.peekType(1).isCategory1())) { - throw illegalTos(); - } - - machine.popArgs(frame, 2); - machine.auxIntArg(0x212); - break; - } - case ByteOps.DUP_X2: { - ExecutionStack stack = frame.getStack(); - - if (stack.peekType(0).isCategory2()) { - throw illegalTos(); - } - - if (stack.peekType(1).isCategory2()) { - // "form 2" in vmspec-2 - machine.popArgs(frame, 2); - machine.auxIntArg(0x212); - } else if (stack.peekType(2).isCategory1()) { - // "form 1" - machine.popArgs(frame, 3); - machine.auxIntArg(0x3213); - } else { - throw illegalTos(); - } - break; - } - case ByteOps.DUP2_X1: { - ExecutionStack stack = frame.getStack(); - - if (stack.peekType(0).isCategory2()) { - // "form 2" in vmspec-2 - if (stack.peekType(2).isCategory2()) { - throw illegalTos(); - } - machine.popArgs(frame, 2); - machine.auxIntArg(0x212); - } else { - // "form 1" - if (stack.peekType(1).isCategory2() || - stack.peekType(2).isCategory2()) { - throw illegalTos(); - } - machine.popArgs(frame, 3); - machine.auxIntArg(0x32132); - } - break; - } - case ByteOps.DUP2_X2: { - ExecutionStack stack = frame.getStack(); - - if (stack.peekType(0).isCategory2()) { - if (stack.peekType(2).isCategory2()) { - // "form 4" in vmspec-2 - machine.popArgs(frame, 2); - machine.auxIntArg(0x212); - } else if (stack.peekType(3).isCategory1()) { - // "form 2" - machine.popArgs(frame, 3); - machine.auxIntArg(0x3213); - } else { - throw illegalTos(); - } - } else if (stack.peekType(1).isCategory1()) { - if (stack.peekType(2).isCategory2()) { - // "form 3" - machine.popArgs(frame, 3); - machine.auxIntArg(0x32132); - } else if (stack.peekType(3).isCategory1()) { - // "form 1" - machine.popArgs(frame, 4); - machine.auxIntArg(0x432143); - } else { - throw illegalTos(); - } - } else { - throw illegalTos(); - } - break; - } - case ByteOps.SWAP: { - ExecutionStack stack = frame.getStack(); - - if (!(stack.peekType(0).isCategory1() && - stack.peekType(1).isCategory1())) { - throw illegalTos(); - } - - machine.popArgs(frame, 2); - machine.auxIntArg(0x12); - break; - } - default: { - visitInvalid(opcode, offset, length); - return; - } - } - - machine.auxType(type); - machine.run(frame, offset, opcode); - } - - /** - * Checks whether the prototype is compatible with returning the - * given type, and throws if not. - * - * @param encountered {@code non-null;} the encountered return type - */ - private void checkReturnType(Type encountered) { - Type returnType = machine.getPrototype().getReturnType(); - - /* - * Check to see if the prototype's return type is - * possibly assignable from the type we encountered. This - * takes care of all the salient cases (types are the same, - * they're compatible primitive types, etc.). - */ - if (!Merger.isPossiblyAssignableFrom(returnType, encountered)) { - fail("return type mismatch: prototype " + - "indicates " + returnType.toHuman() + - ", but encountered type " + encountered.toHuman()); - } - } - - /** {@inheritDoc} */ - @Override - public void visitLocal(int opcode, int offset, int length, - int idx, Type type, int value) { - /* - * Note that the "type" parameter is always the simplest - * type based on the original opcode, e.g., "int" for - * "iload" (per se) and "Object" for "aload". So, when - * possible, we replace the type with the one indicated in - * the local variable table, though we still need to check - * to make sure it's valid for the opcode. - * - * The reason we use (offset + length) for the localOffset - * for a store is because it is only after the store that - * the local type becomes valid. On the other hand, the - * type associated with a load is valid at the start of - * the instruction. - */ - int localOffset = - (opcode == ByteOps.ISTORE) ? (offset + length) : offset; - LocalVariableList.Item local = - localVariables.pcAndIndexToLocal(localOffset, idx); - Type localType; - - if (local != null) { - localType = local.getType(); - if (localType.getBasicFrameType() != - type.getBasicFrameType()) { - // wrong type, ignore local variable info - local = null; - localType = type; - } - } else { - localType = type; - } - - switch (opcode) { - case ByteOps.ILOAD: - case ByteOps.RET: { - machine.localArg(frame, idx); - machine.localInfo(local != null); - machine.auxType(type); - break; - } - case ByteOps.ISTORE: { - LocalItem item - = (local == null) ? null : local.getLocalItem(); - machine.popArgs(frame, type); - machine.auxType(type); - machine.localTarget(idx, localType, item); - break; - } - case ByteOps.IINC: { - LocalItem item - = (local == null) ? null : local.getLocalItem(); - machine.localArg(frame, idx); - machine.localTarget(idx, localType, item); - machine.auxType(type); - machine.auxIntArg(value); - machine.auxCstArg(CstInteger.make(value)); - break; - } - default: { - visitInvalid(opcode, offset, length); - return; - } - } - - machine.run(frame, offset, opcode); - } - - /** {@inheritDoc} */ - @Override - public void visitConstant(int opcode, int offset, int length, - Constant cst, int value) { - switch (opcode) { - case ByteOps.ANEWARRAY: { - machine.popArgs(frame, Type.INT); - break; - } - case ByteOps.PUTSTATIC: { - Type fieldType = ((CstFieldRef) cst).getType(); - machine.popArgs(frame, fieldType); - break; - } - case ByteOps.GETFIELD: - case ByteOps.CHECKCAST: - case ByteOps.INSTANCEOF: { - machine.popArgs(frame, Type.OBJECT); - break; - } - case ByteOps.PUTFIELD: { - Type fieldType = ((CstFieldRef) cst).getType(); - machine.popArgs(frame, Type.OBJECT, fieldType); - break; - } - case ByteOps.INVOKEINTERFACE: - case ByteOps.INVOKEVIRTUAL: - case ByteOps.INVOKESPECIAL: - case ByteOps.INVOKESTATIC: { - /* - * Convert the interface method ref into a normal - * method ref if necessary. - */ - if (cst instanceof CstInterfaceMethodRef) { - cst = ((CstInterfaceMethodRef) cst).toMethodRef(); - checkInvokeInterfaceSupported(opcode, (CstMethodRef) cst); - } - - /* - * Check whether invoke-polymorphic is required and supported. - */ - if (cst instanceof CstMethodRef) { - CstMethodRef methodRef = (CstMethodRef) cst; - if (methodRef.isSignaturePolymorphic()) { - checkInvokeSignaturePolymorphic(opcode); - } - } - - /* - * Get the instance or static prototype, and use it to - * direct the machine. - */ - boolean staticMethod = (opcode == ByteOps.INVOKESTATIC); - Prototype prototype - = ((CstMethodRef) cst).getPrototype(staticMethod); - machine.popArgs(frame, prototype); - break; - } - case ByteOps.INVOKEDYNAMIC: { - checkInvokeDynamicSupported(opcode); - CstInvokeDynamic invokeDynamicRef = (CstInvokeDynamic) cst; - Prototype prototype = invokeDynamicRef.getPrototype(); - machine.popArgs(frame, prototype); - // Change the constant to be associated with instruction to - // a call site reference. - cst = invokeDynamicRef.addReference(); - break; - } - case ByteOps.MULTIANEWARRAY: { - /* - * The "value" here is the count of dimensions to - * create. Make a prototype of that many "int" - * types, and tell the machine to pop them. This - * isn't the most efficient way in the world to do - * this, but then again, multianewarray is pretty - * darn rare and so not worth much effort - * optimizing for. - */ - Prototype prototype = - Prototype.internInts(Type.VOID, value); - machine.popArgs(frame, prototype); - break; - } - case ByteOps.LDC: - case ByteOps.LDC_W: { - if ((cst instanceof CstMethodHandle || cst instanceof CstProtoRef)) { - checkConstMethodHandleSupported(cst); - } - machine.clearArgs(); - break; - } - default: { - machine.clearArgs(); - break; - } - } - - machine.auxIntArg(value); - machine.auxCstArg(cst); - machine.run(frame, offset, opcode); - } - - /** {@inheritDoc} */ - @Override - public void visitBranch(int opcode, int offset, int length, - int target) { - switch (opcode) { - case ByteOps.IFEQ: - case ByteOps.IFNE: - case ByteOps.IFLT: - case ByteOps.IFGE: - case ByteOps.IFGT: - case ByteOps.IFLE: { - machine.popArgs(frame, Type.INT); - break; - } - case ByteOps.IFNULL: - case ByteOps.IFNONNULL: { - machine.popArgs(frame, Type.OBJECT); - break; - } - case ByteOps.IF_ICMPEQ: - case ByteOps.IF_ICMPNE: - case ByteOps.IF_ICMPLT: - case ByteOps.IF_ICMPGE: - case ByteOps.IF_ICMPGT: - case ByteOps.IF_ICMPLE: { - machine.popArgs(frame, Type.INT, Type.INT); - break; - } - case ByteOps.IF_ACMPEQ: - case ByteOps.IF_ACMPNE: { - machine.popArgs(frame, Type.OBJECT, Type.OBJECT); - break; - } - case ByteOps.GOTO: - case ByteOps.JSR: - case ByteOps.GOTO_W: - case ByteOps.JSR_W: { - machine.clearArgs(); - break; - } - default: { - visitInvalid(opcode, offset, length); - return; - } - } - - machine.auxTargetArg(target); - machine.run(frame, offset, opcode); - } - - /** {@inheritDoc} */ - @Override - public void visitSwitch(int opcode, int offset, int length, - SwitchList cases, int padding) { - machine.popArgs(frame, Type.INT); - machine.auxIntArg(padding); - machine.auxSwitchArg(cases); - machine.run(frame, offset, opcode); - } - - /** {@inheritDoc} */ - @Override - public void visitNewarray(int offset, int length, CstType type, - ArrayList initValues) { - machine.popArgs(frame, Type.INT); - machine.auxInitValues(initValues); - machine.auxCstArg(type); - machine.run(frame, offset, ByteOps.NEWARRAY); - } - - /** {@inheritDoc} */ - @Override - public void setPreviousOffset(int offset) { - previousOffset = offset; - } - - /** {@inheritDoc} */ - @Override - public int getPreviousOffset() { - return previousOffset; - } - } - - private void checkConstMethodHandleSupported(Constant cst) throws SimException { - if (!dexOptions.apiIsSupported(DexFormat.API_CONST_METHOD_HANDLE)) { - fail(String.format("invalid constant type %s requires --min-sdk-version >= %d " + - "(currently %d)", - cst.typeName(), DexFormat.API_CONST_METHOD_HANDLE, - dexOptions.minSdkVersion)); - } - } - - private void checkInvokeDynamicSupported(int opcode) throws SimException { - if (!dexOptions.apiIsSupported(DexFormat.API_METHOD_HANDLES)) { - fail(String.format("invalid opcode %02x - invokedynamic requires " + - "--min-sdk-version >= %d (currently %d)", - opcode, DexFormat.API_METHOD_HANDLES, dexOptions.minSdkVersion)); - } - } - - private void checkInvokeInterfaceSupported(final int opcode, CstMethodRef callee) { - if (opcode == ByteOps.INVOKEINTERFACE) { - // Invoked in the tranditional way, this is fine. - return; - } - - if (dexOptions.apiIsSupported(DexFormat.API_INVOKE_INTERFACE_METHODS)) { - // Running at the officially support API level for default - // and static interface methods. - return; - } - - // - // One might expect a hard API level for invoking interface - // methods. It's either okay to have code invoking static (and - // default) interface methods or not. Reality asks to be - // prepared for a little compromise here because the - // traditional guidance to Android developers when producing a - // multi-API level DEX file is to guard the use of the newer - // feature with an API level check, e.g. - // - // int x = (android.os.Build.VERSION.SDK_INT >= 038) ? - // DoJava8Thing() : Do JavaOtherThing(); - // - // This is fine advice if the bytecodes and VM semantics never - // change. Unfortunately, changes like Java 8 support - // introduce new bytecodes and also additional semantics to - // existing bytecodes. Invoking static and default interface - // methods is one of these awkward VM transitions. - // - // Experimentally invoke-static of static interface methods - // breaks on VMs running below API level 21. Invocations of - // default interface methods may soft-fail verification but so - // long as they are not called that's okay. - // - boolean softFail = dexOptions.allowAllInterfaceMethodInvokes; - if (opcode == ByteOps.INVOKESTATIC) { - softFail &= dexOptions.apiIsSupported(DexFormat.API_INVOKE_STATIC_INTERFACE_METHODS); - } else { - assert (opcode == ByteOps.INVOKESPECIAL) || (opcode == ByteOps.INVOKEVIRTUAL); - } - - // Running below the officially supported API level. Fail hard - // unless the user has explicitly allowed this with - // "--allow-all-interface-method-invokes". - String invokeKind = (opcode == ByteOps.INVOKESTATIC) ? "static" : "default"; - if (softFail) { - // The code we are warning about here should have an API check - // that protects it being used on API version < API_INVOKE_INTERFACE_METHODS. - String reason = - String.format( - "invoking a %s interface method %s.%s strictly requires " + - "--min-sdk-version >= %d (experimental at current API level %d)", - invokeKind, callee.getDefiningClass().toHuman(), callee.getNat().toHuman(), - DexFormat.API_INVOKE_INTERFACE_METHODS, dexOptions.minSdkVersion); - warn(reason); - } else { - String reason = - String.format( - "invoking a %s interface method %s.%s strictly requires " + - "--min-sdk-version >= %d (blocked at current API level %d)", - invokeKind, callee.getDefiningClass().toHuman(), callee.getNat().toHuman(), - DexFormat.API_INVOKE_INTERFACE_METHODS, dexOptions.minSdkVersion); - fail(reason); - } - } - - private void checkInterfaceMethodDeclaration(ConcreteMethod declaredMethod) { - if (!dexOptions.apiIsSupported(DexFormat.API_DEFINE_INTERFACE_METHODS)) { - String reason - = String.format( - "defining a %s interface method requires --min-sdk-version >= %d (currently %d)" - + " for interface methods: %s.%s", - declaredMethod.isStaticMethod() ? "static" : "default", - DexFormat.API_DEFINE_INTERFACE_METHODS, dexOptions.minSdkVersion, - declaredMethod.getDefiningClass().toHuman(), declaredMethod.getNat().toHuman()); - warn(reason); - } - } - - private void checkInvokeSignaturePolymorphic(final int opcode) { - if (!dexOptions.apiIsSupported(DexFormat.API_METHOD_HANDLES)) { - fail(String.format( - "invoking a signature-polymorphic requires --min-sdk-version >= %d (currently %d)", - DexFormat.API_METHOD_HANDLES, dexOptions.minSdkVersion)); - } else if (opcode != ByteOps.INVOKEVIRTUAL) { - fail("Unsupported signature polymorphic invocation (" + ByteOps.opName(opcode) + ")"); - } - } - - private void fail(String reason) { - String message = String.format("ERROR in %s.%s: %s", method.getDefiningClass().toHuman(), - method.getNat().toHuman(), reason); - throw new SimException(message); - } - - private void warn(String reason) { - String warning = String.format("WARNING in %s.%s: %s", method.getDefiningClass().toHuman(), - method.getNat().toHuman(), reason); - dexOptions.err.println(warning); - } -} diff --git a/app/src/main/java/com/pojavdx/dx/cf/code/SwitchList.java b/app/src/main/java/com/pojavdx/dx/cf/code/SwitchList.java deleted file mode 100644 index 861b20f32..000000000 --- a/app/src/main/java/com/pojavdx/dx/cf/code/SwitchList.java +++ /dev/null @@ -1,193 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.pojavdx.dx.cf.code; - -import com.pojavdx.dx.util.IntList; -import com.pojavdx.dx.util.MutabilityControl; - -/** - * List of (value, target) mappings representing the choices of a - * {@code tableswitch} or {@code lookupswitch} instruction. It - * also holds the default target for the switch. - */ -public final class SwitchList extends MutabilityControl { - /** {@code non-null;} list of test values */ - private final IntList values; - - /** - * {@code non-null;} list of targets corresponding to the test values; there - * is always one extra element in the target list, to hold the - * default target - */ - private final IntList targets; - - /** ultimate size of the list */ - private int size; - - /** - * Constructs an instance. - * - * @param size {@code >= 0;} the number of elements to be in the table - */ - public SwitchList(int size) { - super(true); - this.values = new IntList(size); - this.targets = new IntList(size + 1); - this.size = size; - } - - /** {@inheritDoc} */ - @Override - public void setImmutable() { - values.setImmutable(); - targets.setImmutable(); - super.setImmutable(); - } - - /** - * Gets the size of the list. - * - * @return {@code >= 0;} the list size - */ - public int size() { - return size; - } - - /** - * Gets the indicated test value. - * - * @param n {@code >= 0;}, < size(); which index - * @return the test value - */ - public int getValue(int n) { - return values.get(n); - } - - /** - * Gets the indicated target. Asking for the target at {@code size()} - * returns the default target. - * - * @param n {@code >= 0, <= size();} which index - * @return {@code >= 0;} the target - */ - public int getTarget(int n) { - return targets.get(n); - } - - /** - * Gets the default target. This is just a shorthand for - * {@code getTarget(size())}. - * - * @return {@code >= 0;} the default target - */ - public int getDefaultTarget() { - return targets.get(size); - } - - /** - * Gets the list of all targets. This includes one extra element at the - * end of the list, which holds the default target. - * - * @return {@code non-null;} the target list - */ - public IntList getTargets() { - return targets; - } - - /** - * Gets the list of all case values. - * - * @return {@code non-null;} the case value list - */ - public IntList getValues() { - return values; - } - - /** - * Sets the default target. It is only valid to call this method - * when all the non-default elements have been set. - * - * @param target {@code >= 0;} the absolute (not relative) default target - * address - */ - public void setDefaultTarget(int target) { - throwIfImmutable(); - - if (target < 0) { - throw new IllegalArgumentException("target < 0"); - } - - if (targets.size() != size) { - throw new RuntimeException("non-default elements not all set"); - } - - targets.add(target); - } - - /** - * Adds the given item. - * - * @param value the test value - * @param target {@code >= 0;} the absolute (not relative) target address - */ - public void add(int value, int target) { - throwIfImmutable(); - - if (target < 0) { - throw new IllegalArgumentException("target < 0"); - } - - values.add(value); - targets.add(target); - } - - /** - * Shrinks this instance if possible, removing test elements that - * refer to the default target. This is only valid after the instance - * is fully populated, including the default target (naturally). - */ - public void removeSuperfluousDefaults() { - throwIfImmutable(); - - int sz = size; - - if (sz != (targets.size() - 1)) { - throw new IllegalArgumentException("incomplete instance"); - } - - int defaultTarget = targets.get(sz); - int at = 0; - - for (int i = 0; i < sz; i++) { - int target = targets.get(i); - if (target != defaultTarget) { - if (i != at) { - targets.set(at, target); - values.set(at, values.get(i)); - } - at++; - } - } - - if (at != sz) { - values.shrink(at); - targets.set(at, defaultTarget); - targets.shrink(at + 1); - size = at; - } - } -} diff --git a/app/src/main/java/com/pojavdx/dx/cf/code/ValueAwareMachine.java b/app/src/main/java/com/pojavdx/dx/cf/code/ValueAwareMachine.java deleted file mode 100644 index 499393584..000000000 --- a/app/src/main/java/com/pojavdx/dx/cf/code/ValueAwareMachine.java +++ /dev/null @@ -1,210 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.pojavdx.dx.cf.code; - -import com.pojavdx.dx.rop.cst.CstCallSiteRef; -import com.pojavdx.dx.rop.cst.CstType; -import com.pojavdx.dx.rop.type.Prototype; -import com.pojavdx.dx.rop.type.Type; -import com.pojavdx.dx.rop.type.TypeBearer; -import com.pojavdx.dx.util.Hex; - -/** - * {@link Machine} which keeps track of known values but does not do - * smart/realistic reference type calculations. - */ -public class ValueAwareMachine extends BaseMachine { - /** - * Constructs an instance. - * - * @param prototype {@code non-null;} the prototype for the associated - * method - */ - public ValueAwareMachine(Prototype prototype) { - super(prototype); - } - - /** {@inheritDoc} */ - @Override - public void run(Frame frame, int offset, int opcode) { - switch (opcode) { - case ByteOps.NOP: - case ByteOps.IASTORE: - case ByteOps.POP: - case ByteOps.POP2: - case ByteOps.IFEQ: - case ByteOps.IFNE: - case ByteOps.IFLT: - case ByteOps.IFGE: - case ByteOps.IFGT: - case ByteOps.IFLE: - case ByteOps.IF_ICMPEQ: - case ByteOps.IF_ICMPNE: - case ByteOps.IF_ICMPLT: - case ByteOps.IF_ICMPGE: - case ByteOps.IF_ICMPGT: - case ByteOps.IF_ICMPLE: - case ByteOps.IF_ACMPEQ: - case ByteOps.IF_ACMPNE: - case ByteOps.GOTO: - case ByteOps.RET: - case ByteOps.LOOKUPSWITCH: - case ByteOps.IRETURN: - case ByteOps.RETURN: - case ByteOps.PUTSTATIC: - case ByteOps.PUTFIELD: - case ByteOps.ATHROW: - case ByteOps.MONITORENTER: - case ByteOps.MONITOREXIT: - case ByteOps.IFNULL: - case ByteOps.IFNONNULL: { - // Nothing to do for these ops in this class. - clearResult(); - break; - } - case ByteOps.LDC: - case ByteOps.LDC2_W: { - setResult((TypeBearer) getAuxCst()); - break; - } - case ByteOps.ILOAD: - case ByteOps.ISTORE: { - setResult(arg(0)); - break; - } - case ByteOps.IALOAD: - case ByteOps.IADD: - case ByteOps.ISUB: - case ByteOps.IMUL: - case ByteOps.IDIV: - case ByteOps.IREM: - case ByteOps.INEG: - case ByteOps.ISHL: - case ByteOps.ISHR: - case ByteOps.IUSHR: - case ByteOps.IAND: - case ByteOps.IOR: - case ByteOps.IXOR: - case ByteOps.IINC: - case ByteOps.I2L: - case ByteOps.I2F: - case ByteOps.I2D: - case ByteOps.L2I: - case ByteOps.L2F: - case ByteOps.L2D: - case ByteOps.F2I: - case ByteOps.F2L: - case ByteOps.F2D: - case ByteOps.D2I: - case ByteOps.D2L: - case ByteOps.D2F: - case ByteOps.I2B: - case ByteOps.I2C: - case ByteOps.I2S: - case ByteOps.LCMP: - case ByteOps.FCMPL: - case ByteOps.FCMPG: - case ByteOps.DCMPL: - case ByteOps.DCMPG: - case ByteOps.ARRAYLENGTH: { - setResult(getAuxType()); - break; - } - case ByteOps.DUP: - case ByteOps.DUP_X1: - case ByteOps.DUP_X2: - case ByteOps.DUP2: - case ByteOps.DUP2_X1: - case ByteOps.DUP2_X2: - case ByteOps.SWAP: { - clearResult(); - for (int pattern = getAuxInt(); pattern != 0; pattern >>= 4) { - int which = (pattern & 0x0f) - 1; - addResult(arg(which)); - } - break; - } - - case ByteOps.JSR: { - setResult(new ReturnAddress(getAuxTarget())); - break; - } - case ByteOps.GETSTATIC: - case ByteOps.GETFIELD: - case ByteOps.INVOKEVIRTUAL: - case ByteOps.INVOKESTATIC: - case ByteOps.INVOKEINTERFACE: { - Type type = ((TypeBearer) getAuxCst()).getType(); - if (type == Type.VOID) { - clearResult(); - } else { - setResult(type); - } - break; - } - case ByteOps.INVOKESPECIAL: { - Type thisType = arg(0).getType(); - if (thisType.isUninitialized()) { - frame.makeInitialized(thisType); - } - Type type = ((TypeBearer) getAuxCst()).getType(); - if (type == Type.VOID) { - clearResult(); - } else { - setResult(type); - } - break; - } - case ByteOps.INVOKEDYNAMIC: { - Type type = ((CstCallSiteRef) getAuxCst()).getReturnType(); - if (type == Type.VOID) { - clearResult(); - } else { - setResult(type); - } - break; - } - case ByteOps.NEW: { - Type type = ((CstType) getAuxCst()).getClassType(); - setResult(type.asUninitialized(offset)); - break; - } - case ByteOps.NEWARRAY: - case ByteOps.CHECKCAST: - case ByteOps.MULTIANEWARRAY: { - Type type = ((CstType) getAuxCst()).getClassType(); - setResult(type); - break; - } - case ByteOps.ANEWARRAY: { - Type type = ((CstType) getAuxCst()).getClassType(); - setResult(type.getArrayType()); - break; - } - case ByteOps.INSTANCEOF: { - setResult(Type.INT); - break; - } - default: { - throw new RuntimeException("shouldn't happen: " + - Hex.u1(opcode)); - } - } - - storeResults(frame); - } -} diff --git a/app/src/main/java/com/pojavdx/dx/cf/code/package.html b/app/src/main/java/com/pojavdx/dx/cf/code/package.html deleted file mode 100644 index 2da413af4..000000000 --- a/app/src/main/java/com/pojavdx/dx/cf/code/package.html +++ /dev/null @@ -1,10 +0,0 @@ - -

Implementation of classes having to do with Java simulation, such as -is needed for verification or stack-to-register conversion.

- -

PACKAGES USED: -

    -
  • com.pojavdx.dx.rop.pool
  • -
  • com.pojavdx.dx.util
  • -
- diff --git a/app/src/main/java/com/pojavdx/dx/cf/cst/ConstantPoolParser.java b/app/src/main/java/com/pojavdx/dx/cf/cst/ConstantPoolParser.java deleted file mode 100644 index 2124e84ac..000000000 --- a/app/src/main/java/com/pojavdx/dx/cf/cst/ConstantPoolParser.java +++ /dev/null @@ -1,450 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.pojavdx.dx.cf.cst; - -import static com.pojavdx.dx.cf.cst.ConstantTags.CONSTANT_Class; -import static com.pojavdx.dx.cf.cst.ConstantTags.CONSTANT_Double; -import static com.pojavdx.dx.cf.cst.ConstantTags.CONSTANT_Fieldref; -import static com.pojavdx.dx.cf.cst.ConstantTags.CONSTANT_Float; -import static com.pojavdx.dx.cf.cst.ConstantTags.CONSTANT_Integer; -import static com.pojavdx.dx.cf.cst.ConstantTags.CONSTANT_InterfaceMethodref; -import static com.pojavdx.dx.cf.cst.ConstantTags.CONSTANT_InvokeDynamic; -import static com.pojavdx.dx.cf.cst.ConstantTags.CONSTANT_Long; -import static com.pojavdx.dx.cf.cst.ConstantTags.CONSTANT_MethodHandle; -import static com.pojavdx.dx.cf.cst.ConstantTags.CONSTANT_MethodType; -import static com.pojavdx.dx.cf.cst.ConstantTags.CONSTANT_Methodref; -import static com.pojavdx.dx.cf.cst.ConstantTags.CONSTANT_NameAndType; -import static com.pojavdx.dx.cf.cst.ConstantTags.CONSTANT_String; -import static com.pojavdx.dx.cf.cst.ConstantTags.CONSTANT_Utf8; -import com.pojavdx.dx.cf.iface.ParseException; -import com.pojavdx.dx.cf.iface.ParseObserver; -import com.pojavdx.dx.rop.cst.Constant; -import com.pojavdx.dx.rop.cst.CstDouble; -import com.pojavdx.dx.rop.cst.CstFieldRef; -import com.pojavdx.dx.rop.cst.CstFloat; -import com.pojavdx.dx.rop.cst.CstInteger; -import com.pojavdx.dx.rop.cst.CstInterfaceMethodRef; -import com.pojavdx.dx.rop.cst.CstInvokeDynamic; -import com.pojavdx.dx.rop.cst.CstLong; -import com.pojavdx.dx.rop.cst.CstMethodHandle; -import com.pojavdx.dx.rop.cst.CstMethodRef; -import com.pojavdx.dx.rop.cst.CstNat; -import com.pojavdx.dx.rop.cst.CstProtoRef; -import com.pojavdx.dx.rop.cst.CstString; -import com.pojavdx.dx.rop.cst.CstType; -import com.pojavdx.dx.rop.cst.StdConstantPool; -import com.pojavdx.dx.rop.type.Type; -import com.pojavdx.dx.util.ByteArray; -import com.pojavdx.dx.util.Hex; -import java.util.BitSet; - -/** - * Parser for a constant pool embedded in a class file. - */ -public final class ConstantPoolParser { - /** {@code non-null;} the bytes of the constant pool */ - private final ByteArray bytes; - - /** {@code non-null;} actual parsed constant pool contents */ - private final StdConstantPool pool; - - /** {@code non-null;} byte offsets to each cst */ - private final int[] offsets; - - /** - * -1 || >= 10; the end offset of this constant pool in the - * {@code byte[]} which it came from or {@code -1} if not - * yet parsed - */ - private int endOffset; - - /** {@code null-ok;} parse observer, if any */ - private ParseObserver observer; - - /** - * Constructs an instance. - * - * @param bytes {@code non-null;} the bytes of the file - */ - public ConstantPoolParser(ByteArray bytes) { - int size = bytes.getUnsignedShort(8); // constant_pool_count - - this.bytes = bytes; - this.pool = new StdConstantPool(size); - this.offsets = new int[size]; - this.endOffset = -1; - } - - /** - * Sets the parse observer for this instance. - * - * @param observer {@code null-ok;} the observer - */ - public void setObserver(ParseObserver observer) { - this.observer = observer; - } - - /** - * Gets the end offset of this constant pool in the {@code byte[]} - * which it came from. - * - * @return {@code >= 10;} the end offset - */ - public int getEndOffset() { - parseIfNecessary(); - return endOffset; - } - - /** - * Gets the actual constant pool. - * - * @return {@code non-null;} the constant pool - */ - public StdConstantPool getPool() { - parseIfNecessary(); - return pool; - } - - /** - * Runs {@link #parse} if it has not yet been run successfully. - */ - private void parseIfNecessary() { - if (endOffset < 0) { - parse(); - } - } - - /** - * Does the actual parsing. - */ - private void parse() { - determineOffsets(); - - if (observer != null) { - observer.parsed(bytes, 8, 2, - "constant_pool_count: " + Hex.u2(offsets.length)); - observer.parsed(bytes, 10, 0, "\nconstant_pool:"); - observer.changeIndent(1); - } - - /* - * Track the constant value's original string type. True if constants[i] was - * a CONSTANT_Utf8, false for any other type including CONSTANT_string. - */ - BitSet wasUtf8 = new BitSet(offsets.length); - - for (int i = 1; i < offsets.length; i++) { - int offset = offsets[i]; - if ((offset != 0) && (pool.getOrNull(i) == null)) { - parse0(i, wasUtf8); - } - } - - if (observer != null) { - for (int i = 1; i < offsets.length; i++) { - Constant cst = pool.getOrNull(i); - if (cst == null) { - continue; - } - int offset = offsets[i]; - int nextOffset = endOffset; - for (int j = i + 1; j < offsets.length; j++) { - int off = offsets[j]; - if (off != 0) { - nextOffset = off; - break; - } - } - String human = wasUtf8.get(i) - ? Hex.u2(i) + ": utf8{\"" + cst.toHuman() + "\"}" - : Hex.u2(i) + ": " + cst.toString(); - observer.parsed(bytes, offset, nextOffset - offset, human); - } - - observer.changeIndent(-1); - observer.parsed(bytes, endOffset, 0, "end constant_pool"); - } - } - - /** - * Populates {@link #offsets} and also completely parse utf8 constants. - */ - private void determineOffsets() { - int at = 10; // offset from the start of the file to the first cst - int lastCategory; - - for (int i = 1; i < offsets.length; i += lastCategory) { - offsets[i] = at; - int tag = bytes.getUnsignedByte(at); - try { - switch (tag) { - case CONSTANT_Integer: - case CONSTANT_Float: - case CONSTANT_Fieldref: - case CONSTANT_Methodref: - case CONSTANT_InterfaceMethodref: - case CONSTANT_NameAndType: { - lastCategory = 1; - at += 5; - break; - } - case CONSTANT_Long: - case CONSTANT_Double: { - lastCategory = 2; - at += 9; - break; - } - case CONSTANT_Class: - case CONSTANT_String: { - lastCategory = 1; - at += 3; - break; - } - case CONSTANT_Utf8: { - lastCategory = 1; - at += bytes.getUnsignedShort(at + 1) + 3; - break; - } - case CONSTANT_MethodHandle: { - lastCategory = 1; - at += 4; - break; - } - case CONSTANT_MethodType: { - lastCategory = 1; - at += 3; - break; - } - case CONSTANT_InvokeDynamic: { - lastCategory = 1; - at += 5; - break; - } - default: { - throw new ParseException("unknown tag byte: " + Hex.u1(tag)); - } - } - } catch (ParseException ex) { - ex.addContext("...while preparsing cst " + Hex.u2(i) + " at offset " + Hex.u4(at)); - throw ex; - } - } - - endOffset = at; - } - - /** - * Parses the constant for the given index if it hasn't already been - * parsed, also storing it in the constant pool. This will also - * have the side effect of parsing any entries the indicated one - * depends on. - * - * @param idx which constant - * @return {@code non-null;} the parsed constant - */ - private Constant parse0(int idx, BitSet wasUtf8) { - Constant cst = pool.getOrNull(idx); - if (cst != null) { - return cst; - } - - int at = offsets[idx]; - - try { - int tag = bytes.getUnsignedByte(at); - switch (tag) { - case CONSTANT_Utf8: { - cst = parseUtf8(at); - wasUtf8.set(idx); - break; - } - case CONSTANT_Integer: { - int value = bytes.getInt(at + 1); - cst = CstInteger.make(value); - break; - } - case CONSTANT_Float: { - int bits = bytes.getInt(at + 1); - cst = CstFloat.make(bits); - break; - } - case CONSTANT_Long: { - long value = bytes.getLong(at + 1); - cst = CstLong.make(value); - break; - } - case CONSTANT_Double: { - long bits = bytes.getLong(at + 1); - cst = CstDouble.make(bits); - break; - } - case CONSTANT_Class: { - int nameIndex = bytes.getUnsignedShort(at + 1); - CstString name = (CstString) parse0(nameIndex, wasUtf8); - cst = new CstType(Type.internClassName(name.getString())); - break; - } - case CONSTANT_String: { - int stringIndex = bytes.getUnsignedShort(at + 1); - cst = parse0(stringIndex, wasUtf8); - break; - } - case CONSTANT_Fieldref: { - int classIndex = bytes.getUnsignedShort(at + 1); - CstType type = (CstType) parse0(classIndex, wasUtf8); - int natIndex = bytes.getUnsignedShort(at + 3); - CstNat nat = (CstNat) parse0(natIndex, wasUtf8); - cst = new CstFieldRef(type, nat); - break; - } - case CONSTANT_Methodref: { - int classIndex = bytes.getUnsignedShort(at + 1); - CstType type = (CstType) parse0(classIndex, wasUtf8); - int natIndex = bytes.getUnsignedShort(at + 3); - CstNat nat = (CstNat) parse0(natIndex, wasUtf8); - cst = new CstMethodRef(type, nat); - break; - } - case CONSTANT_InterfaceMethodref: { - int classIndex = bytes.getUnsignedShort(at + 1); - CstType type = (CstType) parse0(classIndex, wasUtf8); - int natIndex = bytes.getUnsignedShort(at + 3); - CstNat nat = (CstNat) parse0(natIndex, wasUtf8); - cst = new CstInterfaceMethodRef(type, nat); - break; - } - case CONSTANT_NameAndType: { - int nameIndex = bytes.getUnsignedShort(at + 1); - CstString name = (CstString) parse0(nameIndex, wasUtf8); - int descriptorIndex = bytes.getUnsignedShort(at + 3); - CstString descriptor = (CstString) parse0(descriptorIndex, wasUtf8); - cst = new CstNat(name, descriptor); - break; - } - case CONSTANT_MethodHandle: { - final int kind = bytes.getUnsignedByte(at + 1); - final int constantIndex = bytes.getUnsignedShort(at + 2); - final Constant ref; - switch (kind) { - case MethodHandleKind.REF_getField: - case MethodHandleKind.REF_getStatic: - case MethodHandleKind.REF_putField: - case MethodHandleKind.REF_putStatic: - ref = (CstFieldRef) parse0(constantIndex, wasUtf8); - break; - case MethodHandleKind.REF_invokeVirtual: - case MethodHandleKind.REF_newInvokeSpecial: - ref = (CstMethodRef) parse0(constantIndex, wasUtf8); - break; - case MethodHandleKind.REF_invokeStatic: - case MethodHandleKind.REF_invokeSpecial: - ref = parse0(constantIndex, wasUtf8); - if (!(ref instanceof CstMethodRef - || ref instanceof CstInterfaceMethodRef)) { - throw new ParseException( - "Unsupported ref constant type for MethodHandle " - + ref.getClass()); - } - break; - case MethodHandleKind.REF_invokeInterface: - ref = (CstInterfaceMethodRef) parse0(constantIndex, wasUtf8); - break; - default: - throw new ParseException("Unsupported MethodHandle kind: " + kind); - } - - final int methodHandleType = getMethodHandleTypeForKind(kind); - cst = CstMethodHandle.make(methodHandleType, ref); - break; - } - case CONSTANT_MethodType: { - int descriptorIndex = bytes.getUnsignedShort(at + 1); - CstString descriptor = (CstString) parse0(descriptorIndex, wasUtf8); - cst = CstProtoRef.make(descriptor); - break; - } - case CONSTANT_InvokeDynamic: { - int bootstrapMethodIndex = bytes.getUnsignedShort(at + 1); - int natIndex = bytes.getUnsignedShort(at + 3); - CstNat nat = (CstNat) parse0(natIndex, wasUtf8); - cst = CstInvokeDynamic.make(bootstrapMethodIndex, nat); - break; - } - default: { - throw new ParseException("unknown tag byte: " + Hex.u1(tag)); - } - } - } catch (ParseException ex) { - ex.addContext("...while parsing cst " + Hex.u2(idx) + - " at offset " + Hex.u4(at)); - throw ex; - } catch (RuntimeException ex) { - ParseException pe = new ParseException(ex); - pe.addContext("...while parsing cst " + Hex.u2(idx) + - " at offset " + Hex.u4(at)); - throw pe; - } - - pool.set(idx, cst); - return cst; - } - - /** - * Parses a utf8 constant. - * - * @param at offset to the start of the constant (where the tag byte is) - * @return {@code non-null;} the parsed value - */ - private CstString parseUtf8(int at) { - int length = bytes.getUnsignedShort(at + 1); - - at += 3; // Skip to the data. - - ByteArray ubytes = bytes.slice(at, at + length); - - try { - return new CstString(ubytes); - } catch (IllegalArgumentException ex) { - // Translate the exception - throw new ParseException(ex); - } - } - - private static int getMethodHandleTypeForKind(int kind) { - switch (kind) { - case MethodHandleKind.REF_getField: - return CstMethodHandle.METHOD_HANDLE_TYPE_INSTANCE_GET; - case MethodHandleKind.REF_getStatic: - return CstMethodHandle.METHOD_HANDLE_TYPE_STATIC_GET; - case MethodHandleKind.REF_putField: - return CstMethodHandle.METHOD_HANDLE_TYPE_INSTANCE_PUT; - case MethodHandleKind.REF_putStatic: - return CstMethodHandle.METHOD_HANDLE_TYPE_STATIC_PUT; - case MethodHandleKind.REF_invokeVirtual: - return CstMethodHandle.METHOD_HANDLE_TYPE_INVOKE_INSTANCE; - case MethodHandleKind.REF_invokeStatic: - return CstMethodHandle.METHOD_HANDLE_TYPE_INVOKE_STATIC; - case MethodHandleKind.REF_invokeSpecial: - return CstMethodHandle.METHOD_HANDLE_TYPE_INVOKE_DIRECT; - case MethodHandleKind.REF_newInvokeSpecial: - return CstMethodHandle.METHOD_HANDLE_TYPE_INVOKE_CONSTRUCTOR; - case MethodHandleKind.REF_invokeInterface: - return CstMethodHandle.METHOD_HANDLE_TYPE_INVOKE_INTERFACE; - } - throw new IllegalArgumentException("invalid kind: " + kind); - } -} diff --git a/app/src/main/java/com/pojavdx/dx/cf/cst/ConstantTags.java b/app/src/main/java/com/pojavdx/dx/cf/cst/ConstantTags.java deleted file mode 100644 index 39cec9936..000000000 --- a/app/src/main/java/com/pojavdx/dx/cf/cst/ConstantTags.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.pojavdx.dx.cf.cst; - -/** - * Tags for constant pool constants. - */ -public interface ConstantTags { - /** tag for a {@code CONSTANT_Utf8_info} */ - int CONSTANT_Utf8 = 1; - - /** tag for a {@code CONSTANT_Integer_info} */ - int CONSTANT_Integer = 3; - - /** tag for a {@code CONSTANT_Float_info} */ - int CONSTANT_Float = 4; - - /** tag for a {@code CONSTANT_Long_info} */ - int CONSTANT_Long = 5; - - /** tag for a {@code CONSTANT_Double_info} */ - int CONSTANT_Double = 6; - - /** tag for a {@code CONSTANT_Class_info} */ - int CONSTANT_Class = 7; - - /** tag for a {@code CONSTANT_String_info} */ - int CONSTANT_String = 8; - - /** tag for a {@code CONSTANT_Fieldref_info} */ - int CONSTANT_Fieldref = 9; - - /** tag for a {@code CONSTANT_Methodref_info} */ - int CONSTANT_Methodref = 10; - - /** tag for a {@code CONSTANT_InterfaceMethodref_info} */ - int CONSTANT_InterfaceMethodref = 11; - - /** tag for a {@code CONSTANT_NameAndType_info} */ - int CONSTANT_NameAndType = 12; - - /** tag for a {@code CONSTANT_MethodHandle} */ - int CONSTANT_MethodHandle = 15; - - /** tag for a {@code CONSTANT_MethodType} */ - int CONSTANT_MethodType = 16; - - /** tag for a {@code CONSTANT_InvokeDynamic} */ - int CONSTANT_InvokeDynamic = 18; -} diff --git a/app/src/main/java/com/pojavdx/dx/cf/cst/MethodHandleKind.java b/app/src/main/java/com/pojavdx/dx/cf/cst/MethodHandleKind.java deleted file mode 100644 index 11ed32f9f..000000000 --- a/app/src/main/java/com/pojavdx/dx/cf/cst/MethodHandleKind.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.pojavdx.dx.cf.cst; - -/** - * Method Handle kinds for {@code CONSTANT_MethodHandle_info} constants. - */ -public interface MethodHandleKind { - /** A method handle that gets an instance field. */ - int REF_getField = 1; - - /** A method handle that gets a static field. */ - int REF_getStatic = 2; - - /** A method handle that sets an instance field. */ - int REF_putField = 3; - - /** A method handle that sets a static field. */ - int REF_putStatic = 4; - - /** A method handle for {@code invokevirtual}. */ - int REF_invokeVirtual = 5; - - /** A method handle for {@code invokestatic}. */ - int REF_invokeStatic = 6; - - /** A method handle for {@code invokespecial}. */ - int REF_invokeSpecial = 7; - - /** A method handle for invoking a constructor. */ - int REF_newInvokeSpecial = 8; - - /** A method handle for {@code invokeinterface}. */ - int REF_invokeInterface = 9; -} diff --git a/app/src/main/java/com/pojavdx/dx/cf/direct/AnnotationParser.java b/app/src/main/java/com/pojavdx/dx/cf/direct/AnnotationParser.java deleted file mode 100644 index 63a906581..000000000 --- a/app/src/main/java/com/pojavdx/dx/cf/direct/AnnotationParser.java +++ /dev/null @@ -1,470 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.pojavdx.dx.cf.direct; - -import com.pojavdx.dx.cf.iface.ParseException; -import com.pojavdx.dx.cf.iface.ParseObserver; -import com.pojavdx.dx.rop.annotation.Annotation; -import com.pojavdx.dx.rop.annotation.AnnotationVisibility; -import com.pojavdx.dx.rop.annotation.Annotations; -import com.pojavdx.dx.rop.annotation.AnnotationsList; -import com.pojavdx.dx.rop.annotation.NameValuePair; -import com.pojavdx.dx.rop.cst.Constant; -import com.pojavdx.dx.rop.cst.ConstantPool; -import com.pojavdx.dx.rop.cst.CstAnnotation; -import com.pojavdx.dx.rop.cst.CstArray; -import com.pojavdx.dx.rop.cst.CstBoolean; -import com.pojavdx.dx.rop.cst.CstByte; -import com.pojavdx.dx.rop.cst.CstChar; -import com.pojavdx.dx.rop.cst.CstDouble; -import com.pojavdx.dx.rop.cst.CstEnumRef; -import com.pojavdx.dx.rop.cst.CstFloat; -import com.pojavdx.dx.rop.cst.CstInteger; -import com.pojavdx.dx.rop.cst.CstLong; -import com.pojavdx.dx.rop.cst.CstNat; -import com.pojavdx.dx.rop.cst.CstShort; -import com.pojavdx.dx.rop.cst.CstString; -import com.pojavdx.dx.rop.cst.CstType; -import com.pojavdx.dx.rop.type.Type; -import com.pojavdx.dx.util.ByteArray; -import com.pojavdx.dx.util.Hex; -import java.io.IOException; - -/** - * Parser for annotations. - */ -public final class AnnotationParser { - /** {@code non-null;} class file being parsed */ - private final DirectClassFile cf; - - /** {@code non-null;} constant pool to use */ - private final ConstantPool pool; - - /** {@code non-null;} bytes of the attribute data */ - private final ByteArray bytes; - - /** {@code null-ok;} parse observer, if any */ - private final ParseObserver observer; - - /** {@code non-null;} input stream to parse from */ - private final ByteArray.MyDataInputStream input; - - /** - * {@code non-null;} cursor for use when informing the observer of what - * was parsed - */ - private int parseCursor; - - /** - * Constructs an instance. - * - * @param cf {@code non-null;} class file to parse from - * @param offset {@code >= 0;} offset into the class file data to parse at - * @param length {@code >= 0;} number of bytes left in the attribute data - * @param observer {@code null-ok;} parse observer to notify, if any - */ - public AnnotationParser(DirectClassFile cf, int offset, int length, - ParseObserver observer) { - if (cf == null) { - throw new NullPointerException("cf == null"); - } - - this.cf = cf; - this.pool = cf.getConstantPool(); - this.observer = observer; - this.bytes = cf.getBytes().slice(offset, offset + length); - this.input = bytes.makeDataInputStream(); - this.parseCursor = 0; - } - - /** - * Parses an annotation value ({@code element_value}) attribute. - * - * @return {@code non-null;} the parsed constant value - */ - public Constant parseValueAttribute() { - Constant result; - - try { - result = parseValue(); - - if (input.available() != 0) { - throw new ParseException("extra data in attribute"); - } - } catch (IOException ex) { - // ByteArray.MyDataInputStream should never throw. - throw new RuntimeException("shouldn't happen", ex); - } - - return result; - } - - /** - * Parses a parameter annotation attribute. - * - * @param visibility {@code non-null;} visibility of the parsed annotations - * @return {@code non-null;} the parsed list of lists of annotations - */ - public AnnotationsList parseParameterAttribute( - AnnotationVisibility visibility) { - AnnotationsList result; - - try { - result = parseAnnotationsList(visibility); - - if (input.available() != 0) { - throw new ParseException("extra data in attribute"); - } - } catch (IOException ex) { - // ByteArray.MyDataInputStream should never throw. - throw new RuntimeException("shouldn't happen", ex); - } - - return result; - } - - /** - * Parses an annotation attribute, per se. - * - * @param visibility {@code non-null;} visibility of the parsed annotations - * @return {@code non-null;} the list of annotations read from the attribute - * data - */ - public Annotations parseAnnotationAttribute( - AnnotationVisibility visibility) { - Annotations result; - - try { - result = parseAnnotations(visibility); - - if (input.available() != 0) { - throw new ParseException("extra data in attribute"); - } - } catch (IOException ex) { - // ByteArray.MyDataInputStream should never throw. - throw new RuntimeException("shouldn't happen", ex); - } - - return result; - } - - /** - * Parses a list of annotation lists. - * - * @param visibility {@code non-null;} visibility of the parsed annotations - * @return {@code non-null;} the list of annotation lists read from the attribute - * data - */ - private AnnotationsList parseAnnotationsList( - AnnotationVisibility visibility) throws IOException { - int count = input.readUnsignedByte(); - - if (observer != null) { - parsed(1, "num_parameters: " + Hex.u1(count)); - } - - AnnotationsList outerList = new AnnotationsList(count); - - for (int i = 0; i < count; i++) { - if (observer != null) { - parsed(0, "parameter_annotations[" + i + "]:"); - changeIndent(1); - } - - Annotations annotations = parseAnnotations(visibility); - outerList.set(i, annotations); - - if (observer != null) { - observer.changeIndent(-1); - } - } - - outerList.setImmutable(); - return outerList; - } - - /** - * Parses an annotation list. - * - * @param visibility {@code non-null;} visibility of the parsed annotations - * @return {@code non-null;} the list of annotations read from the attribute - * data - */ - private Annotations parseAnnotations(AnnotationVisibility visibility) - throws IOException { - int count = input.readUnsignedShort(); - - if (observer != null) { - parsed(2, "num_annotations: " + Hex.u2(count)); - } - - Annotations annotations = new Annotations(); - - for (int i = 0; i < count; i++) { - if (observer != null) { - parsed(0, "annotations[" + i + "]:"); - changeIndent(1); - } - - Annotation annotation = parseAnnotation(visibility); - annotations.add(annotation); - - if (observer != null) { - observer.changeIndent(-1); - } - } - - annotations.setImmutable(); - return annotations; - } - - /** - * Parses a single annotation. - * - * @param visibility {@code non-null;} visibility of the parsed annotation - * @return {@code non-null;} the parsed annotation - */ - private Annotation parseAnnotation(AnnotationVisibility visibility) - throws IOException { - requireLength(4); - - int typeIndex = input.readUnsignedShort(); - int numElements = input.readUnsignedShort(); - CstString typeString = (CstString) pool.get(typeIndex); - CstType type = new CstType(Type.intern(typeString.getString())); - - if (observer != null) { - parsed(2, "type: " + type.toHuman()); - parsed(2, "num_elements: " + numElements); - } - - Annotation annotation = new Annotation(type, visibility); - - for (int i = 0; i < numElements; i++) { - if (observer != null) { - parsed(0, "elements[" + i + "]:"); - changeIndent(1); - } - - NameValuePair element = parseElement(); - annotation.add(element); - - if (observer != null) { - changeIndent(-1); - } - } - - annotation.setImmutable(); - return annotation; - } - - /** - * Parses a {@link NameValuePair}. - * - * @return {@code non-null;} the parsed element - */ - private NameValuePair parseElement() throws IOException { - requireLength(5); - - int elementNameIndex = input.readUnsignedShort(); - CstString elementName = (CstString) pool.get(elementNameIndex); - - if (observer != null) { - parsed(2, "element_name: " + elementName.toHuman()); - parsed(0, "value: "); - changeIndent(1); - } - - Constant value = parseValue(); - - if (observer != null) { - changeIndent(-1); - } - - return new NameValuePair(elementName, value); - } - - /** - * Parses an annotation value. - * - * @return {@code non-null;} the parsed value - */ - private Constant parseValue() throws IOException { - int tag = input.readUnsignedByte(); - - if (observer != null) { - CstString humanTag = new CstString(Character.toString((char) tag)); - parsed(1, "tag: " + humanTag.toQuoted()); - } - - switch (tag) { - case 'B': { - CstInteger value = (CstInteger) parseConstant(); - return CstByte.make(value.getValue()); - } - case 'C': { - CstInteger value = (CstInteger) parseConstant(); - int intValue = value.getValue(); - return CstChar.make(value.getValue()); - } - case 'D': { - CstDouble value = (CstDouble) parseConstant(); - return value; - } - case 'F': { - CstFloat value = (CstFloat) parseConstant(); - return value; - } - case 'I': { - CstInteger value = (CstInteger) parseConstant(); - return value; - } - case 'J': { - CstLong value = (CstLong) parseConstant(); - return value; - } - case 'S': { - CstInteger value = (CstInteger) parseConstant(); - return CstShort.make(value.getValue()); - } - case 'Z': { - CstInteger value = (CstInteger) parseConstant(); - return CstBoolean.make(value.getValue()); - } - case 'c': { - int classInfoIndex = input.readUnsignedShort(); - CstString value = (CstString) pool.get(classInfoIndex); - Type type = Type.internReturnType(value.getString()); - - if (observer != null) { - parsed(2, "class_info: " + type.toHuman()); - } - - return new CstType(type); - } - case 's': { - return parseConstant(); - } - case 'e': { - requireLength(4); - - int typeNameIndex = input.readUnsignedShort(); - int constNameIndex = input.readUnsignedShort(); - CstString typeName = (CstString) pool.get(typeNameIndex); - CstString constName = (CstString) pool.get(constNameIndex); - - if (observer != null) { - parsed(2, "type_name: " + typeName.toHuman()); - parsed(2, "const_name: " + constName.toHuman()); - } - - return new CstEnumRef(new CstNat(constName, typeName)); - } - case '@': { - Annotation annotation = - parseAnnotation(AnnotationVisibility.EMBEDDED); - return new CstAnnotation(annotation); - } - case '[': { - requireLength(2); - - int numValues = input.readUnsignedShort(); - CstArray.List list = new CstArray.List(numValues); - - if (observer != null) { - parsed(2, "num_values: " + numValues); - changeIndent(1); - } - - for (int i = 0; i < numValues; i++) { - if (observer != null) { - changeIndent(-1); - parsed(0, "element_value[" + i + "]:"); - changeIndent(1); - } - list.set(i, parseValue()); - } - - if (observer != null) { - changeIndent(-1); - } - - list.setImmutable(); - return new CstArray(list); - } - default: { - throw new ParseException("unknown annotation tag: " + - Hex.u1(tag)); - } - } - } - - /** - * Helper for {@link #parseValue}, which parses a constant reference - * and returns the referred-to constant value. - * - * @return {@code non-null;} the parsed value - */ - private Constant parseConstant() throws IOException { - int constValueIndex = input.readUnsignedShort(); - Constant value = (Constant) pool.get(constValueIndex); - - if (observer != null) { - String human = (value instanceof CstString) - ? ((CstString) value).toQuoted() - : value.toHuman(); - parsed(2, "constant_value: " + human); - } - - return value; - } - - /** - * Helper which will throw an exception if the given number of bytes - * is not available to be read. - * - * @param requiredLength the number of required bytes - */ - private void requireLength(int requiredLength) throws IOException { - if (input.available() < requiredLength) { - throw new ParseException("truncated annotation attribute"); - } - } - - /** - * Helper which indicates that some bytes were just parsed. This should - * only be used (for efficiency sake) if the parse is known to be - * observed. - * - * @param length {@code >= 0;} number of bytes parsed - * @param message {@code non-null;} associated message - */ - private void parsed(int length, String message) { - observer.parsed(bytes, parseCursor, length, message); - parseCursor += length; - } - - /** - * Convenience wrapper that simply calls through to - * {@code observer.changeIndent()}. - * - * @param indent the amount to change the indent by - */ - private void changeIndent(int indent) { - observer.changeIndent(indent); - } -} diff --git a/app/src/main/java/com/pojavdx/dx/cf/direct/AttributeFactory.java b/app/src/main/java/com/pojavdx/dx/cf/direct/AttributeFactory.java deleted file mode 100644 index 9c433e139..000000000 --- a/app/src/main/java/com/pojavdx/dx/cf/direct/AttributeFactory.java +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.pojavdx.dx.cf.direct; - -import com.pojavdx.dx.cf.attrib.RawAttribute; -import com.pojavdx.dx.cf.iface.Attribute; -import com.pojavdx.dx.cf.iface.ParseException; -import com.pojavdx.dx.cf.iface.ParseObserver; -import com.pojavdx.dx.rop.cst.ConstantPool; -import com.pojavdx.dx.rop.cst.CstString; -import com.pojavdx.dx.util.ByteArray; -import com.pojavdx.dx.util.Hex; - -/** - * Factory capable of instantiating various {@link Attribute} subclasses - * depending on the context and name. - */ -public class AttributeFactory { - /** context for attributes on class files */ - public static final int CTX_CLASS = 0; - - /** context for attributes on fields */ - public static final int CTX_FIELD = 1; - - /** context for attributes on methods */ - public static final int CTX_METHOD = 2; - - /** context for attributes on code attributes */ - public static final int CTX_CODE = 3; - - /** number of contexts */ - public static final int CTX_COUNT = 4; - - /** - * Constructs an instance. - */ - public AttributeFactory() { - // This space intentionally left blank. - } - - /** - * Parses and makes an attribute based on the bytes at the - * indicated position in the given array. This method figures out - * the name, and then does all the setup to call on to {@link #parse0}, - * which does the actual construction. - * - * @param cf {@code non-null;} class file to parse from - * @param context context to parse in; one of the {@code CTX_*} - * constants - * @param offset offset into {@code dcf}'s {@code bytes} - * to start parsing at - * @param observer {@code null-ok;} parse observer to report to, if any - * @return {@code non-null;} an appropriately-constructed {@link Attribute} - */ - public final Attribute parse(DirectClassFile cf, int context, int offset, - ParseObserver observer) { - if (cf == null) { - throw new NullPointerException("cf == null"); - } - - if ((context < 0) || (context >= CTX_COUNT)) { - throw new IllegalArgumentException("bad context"); - } - - CstString name = null; - - try { - ByteArray bytes = cf.getBytes(); - ConstantPool pool = cf.getConstantPool(); - int nameIdx = bytes.getUnsignedShort(offset); - int length = bytes.getInt(offset + 2); - - name = (CstString) pool.get(nameIdx); - - if (observer != null) { - observer.parsed(bytes, offset, 2, - "name: " + name.toHuman()); - observer.parsed(bytes, offset + 2, 4, - "length: " + Hex.u4(length)); - } - - return parse0(cf, context, name.getString(), offset + 6, length, - observer); - } catch (ParseException ex) { - ex.addContext("...while parsing " + - ((name != null) ? (name.toHuman() + " ") : "") + - "attribute at offset " + Hex.u4(offset)); - throw ex; - } - } - - /** - * Parses attribute content. The base class implements this by constructing - * an instance of {@link RawAttribute}. Subclasses are expected to - * override this to do something better in most cases. - * - * @param cf {@code non-null;} class file to parse from - * @param context context to parse in; one of the {@code CTX_*} - * constants - * @param name {@code non-null;} the attribute name - * @param offset offset into {@code bytes} to start parsing at; this - * is the offset to the start of attribute data, not to the header - * @param length the length of the attribute data - * @param observer {@code null-ok;} parse observer to report to, if any - * @return {@code non-null;} an appropriately-constructed {@link Attribute} - */ - protected Attribute parse0(DirectClassFile cf, int context, String name, - int offset, int length, - ParseObserver observer) { - ByteArray bytes = cf.getBytes(); - ConstantPool pool = cf.getConstantPool(); - Attribute result = new RawAttribute(name, bytes, offset, length, pool); - - if (observer != null) { - observer.parsed(bytes, offset, length, "attribute data"); - } - - return result; - } -} diff --git a/app/src/main/java/com/pojavdx/dx/cf/direct/AttributeListParser.java b/app/src/main/java/com/pojavdx/dx/cf/direct/AttributeListParser.java deleted file mode 100644 index 79aab9259..000000000 --- a/app/src/main/java/com/pojavdx/dx/cf/direct/AttributeListParser.java +++ /dev/null @@ -1,164 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.pojavdx.dx.cf.direct; - -import com.pojavdx.dx.cf.iface.Attribute; -import com.pojavdx.dx.cf.iface.ParseException; -import com.pojavdx.dx.cf.iface.ParseObserver; -import com.pojavdx.dx.cf.iface.StdAttributeList; -import com.pojavdx.dx.util.ByteArray; -import com.pojavdx.dx.util.Hex; - -/** - * Parser for lists of attributes. - */ -final /*package*/ class AttributeListParser { - /** {@code non-null;} the class file to parse from */ - private final DirectClassFile cf; - - /** attribute parsing context */ - private final int context; - - /** offset in the byte array of the classfile to the start of the list */ - private final int offset; - - /** {@code non-null;} attribute factory to use */ - private final AttributeFactory attributeFactory; - - /** {@code non-null;} list of parsed attributes */ - private final StdAttributeList list; - - /** {@code >= -1;} the end offset of this list in the byte array of the - * classfile, or {@code -1} if not yet parsed */ - private int endOffset; - - /** {@code null-ok;} parse observer, if any */ - private ParseObserver observer; - - /** - * Constructs an instance. - * - * @param cf {@code non-null;} class file to parse from - * @param context attribute parsing context (see {@link AttributeFactory}) - * @param offset offset in {@code bytes} to the start of the list - * @param attributeFactory {@code non-null;} attribute factory to use - */ - public AttributeListParser(DirectClassFile cf, int context, int offset, - AttributeFactory attributeFactory) { - if (cf == null) { - throw new NullPointerException("cf == null"); - } - - if (attributeFactory == null) { - throw new NullPointerException("attributeFactory == null"); - } - - int size = cf.getBytes().getUnsignedShort(offset); - - this.cf = cf; - this.context = context; - this.offset = offset; - this.attributeFactory = attributeFactory; - this.list = new StdAttributeList(size); - this.endOffset = -1; - } - - /** - * Sets the parse observer for this instance. - * - * @param observer {@code null-ok;} the observer - */ - public void setObserver(ParseObserver observer) { - this.observer = observer; - } - - /** - * Gets the end offset of this constant pool in the {@code byte[]} - * which it came from. - * - * @return {@code >= 0;} the end offset - */ - public int getEndOffset() { - parseIfNecessary(); - return endOffset; - } - - /** - * Gets the parsed list. - * - * @return {@code non-null;} the list - */ - public StdAttributeList getList() { - parseIfNecessary(); - return list; - } - - /** - * Runs {@link #parse} if it has not yet been run successfully. - */ - private void parseIfNecessary() { - if (endOffset < 0) { - parse(); - } - } - - /** - * Does the actual parsing. - */ - private void parse() { - int sz = list.size(); - int at = offset + 2; // Skip the count. - - ByteArray bytes = cf.getBytes(); - - if (observer != null) { - observer.parsed(bytes, offset, 2, - "attributes_count: " + Hex.u2(sz)); - } - - for (int i = 0; i < sz; i++) { - try { - if (observer != null) { - observer.parsed(bytes, at, 0, - "\nattributes[" + i + "]:\n"); - observer.changeIndent(1); - } - - Attribute attrib = - attributeFactory.parse(cf, context, at, observer); - - at += attrib.byteLength(); - list.set(i, attrib); - - if (observer != null) { - observer.changeIndent(-1); - observer.parsed(bytes, at, 0, - "end attributes[" + i + "]\n"); - } - } catch (ParseException ex) { - ex.addContext("...while parsing attributes[" + i + "]"); - throw ex; - } catch (RuntimeException ex) { - ParseException pe = new ParseException(ex); - pe.addContext("...while parsing attributes[" + i + "]"); - throw pe; - } - } - - endOffset = at; - } -} diff --git a/app/src/main/java/com/pojavdx/dx/cf/direct/ClassPathOpener.java b/app/src/main/java/com/pojavdx/dx/cf/direct/ClassPathOpener.java deleted file mode 100644 index 41100d004..000000000 --- a/app/src/main/java/com/pojavdx/dx/cf/direct/ClassPathOpener.java +++ /dev/null @@ -1,294 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.pojavdx.dx.cf.direct; - -import com.pojavdx.dex.util.FileUtils; -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.Comparator; -import java.util.zip.ZipEntry; -import java.util.zip.ZipFile; -import net.kdt.pojavlaunch.*; - -/** - * Opens all the class files found in a class path element. Path elements - * can point to class files, {jar,zip,apk} files, or directories containing - * class files. - */ -public class ClassPathOpener { - - /** {@code non-null;} pathname to start with */ - private final String pathname; - /** {@code non-null;} callback interface */ - private final Consumer consumer; - /** - * If true, sort such that classes appear before their inner - * classes and "package-info" occurs before all other classes in that - * package. - */ - private final boolean sort; - private FileNameFilter filter; - - /** - * Callback interface for {@code ClassOpener}. - */ - public interface Consumer { - - /** - * Provides the file name and byte array for a class path element. - * - * @param name {@code non-null;} filename of element. May not be a valid - * filesystem path. - * - * @param lastModified milliseconds since 1970-Jan-1 00:00:00 GMT - * @param bytes {@code non-null;} file data - * @return true on success. Result is or'd with all other results - * from {@code processFileBytes} and returned to the caller - * of {@code process()}. - */ - boolean processFileBytes(String name, long lastModified, byte[] bytes); - - /** - * Informs consumer that an exception occurred while processing - * this path element. Processing will continue if possible. - * - * @param ex {@code non-null;} exception - */ - void onException(Exception ex); - - /** - * Informs consumer that processing of an archive file has begun. - * - * @param file {@code non-null;} archive file being processed - */ - void onProcessArchiveStart(File file); - } - - /** - * Filter interface for {@code ClassOpener}. - */ - public interface FileNameFilter { - - boolean accept(String path); - } - - /** - * An accept all filter. - */ - public static final FileNameFilter acceptAll = new FileNameFilter() { - - @Override - public boolean accept(String path) { - return true; - } - }; - - /** - * Constructs an instance. - * - * @param pathname {@code non-null;} path element to process - * @param sort if true, sort such that classes appear before their inner - * classes and "package-info" occurs before all other classes in that - * package. - * @param consumer {@code non-null;} callback interface - */ - public ClassPathOpener(String pathname, boolean sort, Consumer consumer) { - this(pathname, sort, acceptAll, consumer); - } - - /** - * Constructs an instance. - * - * @param pathname {@code non-null;} path element to process - * @param sort if true, sort such that classes appear before their inner - * classes and "package-info" occurs before all other classes in that - * package. - * @param consumer {@code non-null;} callback interface - */ - public ClassPathOpener(String pathname, boolean sort, FileNameFilter filter, - Consumer consumer) { - this.pathname = pathname; - this.sort = sort; - this.consumer = consumer; - this.filter = filter; - } - - /** - * Processes a path element. - * - * @return the OR of all return values - * from {@code Consumer.processFileBytes()}. - */ - public boolean process() { - File file = new File(pathname); - - return processOne(file, true); - } - - /** - * Processes one file. - * - * @param file {@code non-null;} the file to process - * @param topLevel whether this is a top-level file (that is, - * specified directly on the commandline) - * @return whether any processing actually happened - */ - private boolean processOne(File file, boolean topLevel) { - try { - if (file.isDirectory()) { - return processDirectory(file, topLevel); - } - - String path = file.getPath(); - - if (path.endsWith(".zip") || - path.endsWith(".jar") || - path.endsWith(".apk")) { - return processArchive(file); - } - if (filter.accept(path)) { - byte[] bytes = FileUtils.readFile(file); - return consumer.processFileBytes(path, file.lastModified(), bytes); - } else { - return false; - } - } catch (Exception ex) { - consumer.onException(ex); - return false; - } - } - - /** - * Sorts java class names such that outer classes preceed their inner - * classes and "package-info" preceeds all other classes in its package. - * - * @param a {@code non-null;} first class name - * @param b {@code non-null;} second class name - * @return {@code compareTo()}-style result - */ - private static int compareClassNames(String a, String b) { - // Ensure inner classes sort second - a = a.replace('$','0'); - b = b.replace('$','0'); - - /* - * Assuming "package-info" only occurs at the end, ensures package-info - * sorts first. - */ - a = a.replace("package-info", ""); - b = b.replace("package-info", ""); - - return a.compareTo(b); - } - - /** - * Processes a directory recursively. - * - * @param dir {@code non-null;} file representing the directory - * @param topLevel whether this is a top-level directory (that is, - * specified directly on the commandline) - * @return whether any processing actually happened - */ - private boolean processDirectory(File dir, boolean topLevel) { - if (topLevel) { - dir = new File(dir, "."); - } - - File[] files = dir.listFiles(); - int len = files.length; - boolean any = false; - - if (sort) { - Arrays.sort(files, new Comparator() { - @Override - public int compare(File a, File b) { - return compareClassNames(a.getName(), b.getName()); - } - }); - } - - for (int i = 0; i < len; i++) { - any |= processOne(files[i], false); - } - - return any; - } - - /** - * Processes the contents of an archive ({@code .zip}, - * {@code .jar}, or {@code .apk}). - * - * @param file {@code non-null;} archive file to process - * @return whether any processing actually happened - * @throws IOException on i/o problem - */ - private boolean processArchive(File file) throws IOException { - ZipFile zip = new ZipFile(file); - - ArrayList entriesList = Collections.list(zip.entries()); - - PojavDXManager.maxProgress = entriesList.size(); - - if (sort) { - Collections.sort(entriesList, new Comparator() { - @Override - public int compare (ZipEntry a, ZipEntry b) { - return compareClassNames(a.getName(), b.getName()); - } - }); - } - - consumer.onProcessArchiveStart(file); - - ByteArrayOutputStream baos = new ByteArrayOutputStream(40000); - byte[] buf = new byte[20000]; - boolean any = false; - - for (ZipEntry one : entriesList) { - final boolean isDirectory = one.isDirectory(); - - String path = one.getName(); - if (filter.accept(path)) { - final byte[] bytes; - if (!isDirectory) { - InputStream in = zip.getInputStream(one); - - baos.reset(); - int read; - while ((read = in.read(buf)) != -1) { - baos.write(buf, 0, read); - } - - in.close(); - bytes = baos.toByteArray(); - } else { - bytes = new byte[0]; - } - - any |= consumer.processFileBytes(path, one.getTime(), bytes); - } - } - - zip.close(); - return any; - } -} diff --git a/app/src/main/java/com/pojavdx/dx/cf/direct/CodeObserver.java b/app/src/main/java/com/pojavdx/dx/cf/direct/CodeObserver.java deleted file mode 100644 index 0aea2b9cd..000000000 --- a/app/src/main/java/com/pojavdx/dx/cf/direct/CodeObserver.java +++ /dev/null @@ -1,312 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.pojavdx.dx.cf.direct; - -import com.pojavdx.dx.cf.code.ByteOps; -import com.pojavdx.dx.cf.code.BytecodeArray; -import com.pojavdx.dx.cf.code.SwitchList; -import com.pojavdx.dx.cf.iface.ParseObserver; -import com.pojavdx.dx.rop.cst.Constant; -import com.pojavdx.dx.rop.cst.CstDouble; -import com.pojavdx.dx.rop.cst.CstFloat; -import com.pojavdx.dx.rop.cst.CstInteger; -import com.pojavdx.dx.rop.cst.CstKnownNull; -import com.pojavdx.dx.rop.cst.CstLong; -import com.pojavdx.dx.rop.cst.CstType; -import com.pojavdx.dx.rop.type.Type; -import com.pojavdx.dx.util.ByteArray; -import com.pojavdx.dx.util.Hex; -import java.util.ArrayList; - -/** - * Bytecode visitor to use when "observing" bytecode getting parsed. - */ -public class CodeObserver implements BytecodeArray.Visitor { - /** {@code non-null;} actual array of bytecode */ - private final ByteArray bytes; - - /** {@code non-null;} observer to inform of parsing */ - private final ParseObserver observer; - - /** - * Constructs an instance. - * - * @param bytes {@code non-null;} actual array of bytecode - * @param observer {@code non-null;} observer to inform of parsing - */ - public CodeObserver(ByteArray bytes, ParseObserver observer) { - if (bytes == null) { - throw new NullPointerException("bytes == null"); - } - - if (observer == null) { - throw new NullPointerException("observer == null"); - } - - this.bytes = bytes; - this.observer = observer; - } - - /** {@inheritDoc} */ - @Override - public void visitInvalid(int opcode, int offset, int length) { - observer.parsed(bytes, offset, length, header(offset)); - } - - /** {@inheritDoc} */ - @Override - public void visitNoArgs(int opcode, int offset, int length, Type type) { - observer.parsed(bytes, offset, length, header(offset)); - } - - /** {@inheritDoc} */ - @Override - public void visitLocal(int opcode, int offset, int length, - int idx, Type type, int value) { - String idxStr = (length <= 3) ? Hex.u1(idx) : Hex.u2(idx); - boolean argComment = (length == 1); - String valueStr = ""; - - if (opcode == ByteOps.IINC) { - valueStr = ", #" + - ((length <= 3) ? Hex.s1(value) : Hex.s2(value)); - } - - String catStr = ""; - if (type.isCategory2()) { - catStr = (argComment ? "," : " //") + " category-2"; - } - - observer.parsed(bytes, offset, length, - header(offset) + (argComment ? " // " : " ") + - idxStr + valueStr + catStr); - } - - /** {@inheritDoc} */ - @Override - public void visitConstant(int opcode, int offset, int length, - Constant cst, int value) { - if (cst instanceof CstKnownNull) { - // This is aconst_null. - visitNoArgs(opcode, offset, length, null); - return; - } - - if (cst instanceof CstInteger) { - visitLiteralInt(opcode, offset, length, value); - return; - } - - if (cst instanceof CstLong) { - visitLiteralLong(opcode, offset, length, - ((CstLong) cst).getValue()); - return; - } - - if (cst instanceof CstFloat) { - visitLiteralFloat(opcode, offset, length, - ((CstFloat) cst).getIntBits()); - return; - } - - if (cst instanceof CstDouble) { - visitLiteralDouble(opcode, offset, length, - ((CstDouble) cst).getLongBits()); - return; - } - - String valueStr = ""; - if (value != 0) { - valueStr = ", "; - if (opcode == ByteOps.MULTIANEWARRAY) { - valueStr += Hex.u1(value); - } else { - valueStr += Hex.u2(value); - } - } - - observer.parsed(bytes, offset, length, - header(offset) + " " + cst + valueStr); - } - - /** {@inheritDoc} */ - @Override - public void visitBranch(int opcode, int offset, int length, - int target) { - String targetStr = (length <= 3) ? Hex.u2(target) : Hex.u4(target); - observer.parsed(bytes, offset, length, - header(offset) + " " + targetStr); - } - - /** {@inheritDoc} */ - @Override - public void visitSwitch(int opcode, int offset, int length, - SwitchList cases, int padding) { - int sz = cases.size(); - StringBuilder sb = new StringBuilder(sz * 20 + 100); - - sb.append(header(offset)); - if (padding != 0) { - sb.append(" // padding: " + Hex.u4(padding)); - } - sb.append('\n'); - - for (int i = 0; i < sz; i++) { - sb.append(" "); - sb.append(Hex.s4(cases.getValue(i))); - sb.append(": "); - sb.append(Hex.u2(cases.getTarget(i))); - sb.append('\n'); - } - - sb.append(" default: "); - sb.append(Hex.u2(cases.getDefaultTarget())); - - observer.parsed(bytes, offset, length, sb.toString()); - } - - /** {@inheritDoc} */ - @Override - public void visitNewarray(int offset, int length, CstType cst, - ArrayList intVals) { - String commentOrSpace = (length == 1) ? " // " : " "; - String typeName = cst.getClassType().getComponentType().toHuman(); - - observer.parsed(bytes, offset, length, - header(offset) + commentOrSpace + typeName); - } - - /** {@inheritDoc} */ - @Override - public void setPreviousOffset(int offset) { - // Do nothing - } - - /** {@inheritDoc} */ - @Override - public int getPreviousOffset() { - return -1; - } - - /** - * Helper to produce the first bit of output for each instruction. - * - * @param offset the offset to the start of the instruction - */ - private String header(int offset) { - /* - * Note: This uses the original bytecode, not the - * possibly-transformed one. - */ - int opcode = bytes.getUnsignedByte(offset); - String name = ByteOps.opName(opcode); - - if (opcode == ByteOps.WIDE) { - opcode = bytes.getUnsignedByte(offset + 1); - name += " " + ByteOps.opName(opcode); - } - - return Hex.u2(offset) + ": " + name; - } - - /** - * Helper for {@link #visitConstant} where the constant is an - * {@code int}. - * - * @param opcode the opcode - * @param offset offset to the instruction - * @param length instruction length - * @param value constant value - */ - private void visitLiteralInt(int opcode, int offset, int length, - int value) { - String commentOrSpace = (length == 1) ? " // " : " "; - String valueStr; - - opcode = bytes.getUnsignedByte(offset); // Compare with orig op below. - if ((length == 1) || (opcode == ByteOps.BIPUSH)) { - valueStr = "#" + Hex.s1(value); - } else if (opcode == ByteOps.SIPUSH) { - valueStr = "#" + Hex.s2(value); - } else { - valueStr = "#" + Hex.s4(value); - } - - observer.parsed(bytes, offset, length, - header(offset) + commentOrSpace + valueStr); - } - - /** - * Helper for {@link #visitConstant} where the constant is a - * {@code long}. - * - * @param opcode the opcode - * @param offset offset to the instruction - * @param length instruction length - * @param value constant value - */ - private void visitLiteralLong(int opcode, int offset, int length, - long value) { - String commentOrLit = (length == 1) ? " // " : " #"; - String valueStr; - - if (length == 1) { - valueStr = Hex.s1((int) value); - } else { - valueStr = Hex.s8(value); - } - - observer.parsed(bytes, offset, length, - header(offset) + commentOrLit + valueStr); - } - - /** - * Helper for {@link #visitConstant} where the constant is a - * {@code float}. - * - * @param opcode the opcode - * @param offset offset to the instruction - * @param length instruction length - * @param bits constant value, as float-bits - */ - private void visitLiteralFloat(int opcode, int offset, int length, - int bits) { - String optArg = (length != 1) ? " #" + Hex.u4(bits) : ""; - - observer.parsed(bytes, offset, length, - header(offset) + optArg + " // " + - Float.intBitsToFloat(bits)); - } - - /** - * Helper for {@link #visitConstant} where the constant is a - * {@code double}. - * - * @param opcode the opcode - * @param offset offset to the instruction - * @param length instruction length - * @param bits constant value, as double-bits - */ - private void visitLiteralDouble(int opcode, int offset, int length, - long bits) { - String optArg = (length != 1) ? " #" + Hex.u8(bits) : ""; - - observer.parsed(bytes, offset, length, - header(offset) + optArg + " // " + - Double.longBitsToDouble(bits)); - } -} diff --git a/app/src/main/java/com/pojavdx/dx/cf/direct/DirectClassFile.java b/app/src/main/java/com/pojavdx/dx/cf/direct/DirectClassFile.java deleted file mode 100644 index 991e628b8..000000000 --- a/app/src/main/java/com/pojavdx/dx/cf/direct/DirectClassFile.java +++ /dev/null @@ -1,688 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.pojavdx.dx.cf.direct; - -import com.pojavdx.dx.cf.attrib.AttBootstrapMethods; -import com.pojavdx.dx.cf.attrib.AttSourceFile; -import com.pojavdx.dx.cf.code.BootstrapMethodsList; -import com.pojavdx.dx.cf.cst.ConstantPoolParser; -import com.pojavdx.dx.cf.iface.Attribute; -import com.pojavdx.dx.cf.iface.AttributeList; -import com.pojavdx.dx.cf.iface.ClassFile; -import com.pojavdx.dx.cf.iface.FieldList; -import com.pojavdx.dx.cf.iface.MethodList; -import com.pojavdx.dx.cf.iface.ParseException; -import com.pojavdx.dx.cf.iface.ParseObserver; -import com.pojavdx.dx.cf.iface.StdAttributeList; -import com.pojavdx.dx.rop.code.AccessFlags; -import com.pojavdx.dx.rop.cst.ConstantPool; -import com.pojavdx.dx.rop.cst.CstString; -import com.pojavdx.dx.rop.cst.CstType; -import com.pojavdx.dx.rop.cst.StdConstantPool; -import com.pojavdx.dx.rop.type.StdTypeList; -import com.pojavdx.dx.rop.type.Type; -import com.pojavdx.dx.rop.type.TypeList; -import com.pojavdx.dx.util.ByteArray; -import com.pojavdx.dx.util.Hex; - -/** - * Class file with info taken from a {@code byte[]} or slice thereof. - */ -public class DirectClassFile implements ClassFile { - /** the expected value of the ClassFile.magic field */ - private static final int CLASS_FILE_MAGIC = 0xcafebabe; - - /** - * minimum {@code .class} file major version - * - * See http://en.wikipedia.org/wiki/Java_class_file for an up-to-date - * list of version numbers. Currently known (taken from that table) are: - * - * Java SE 9 = 53 (0x35 hex), - * Java SE 8 = 52 (0x34 hex), - * Java SE 7 = 51 (0x33 hex), - * Java SE 6.0 = 50 (0x32 hex), - * Java SE 5.0 = 49 (0x31 hex), - * JDK 1.4 = 48 (0x30 hex), - * JDK 1.3 = 47 (0x2F hex), - * JDK 1.2 = 46 (0x2E hex), - * JDK 1.1 = 45 (0x2D hex). - * - * Valid ranges are typically of the form - * "A.0 through B.C inclusive" where A <= B and C >= 0, - * which is why we don't have a CLASS_FILE_MIN_MINOR_VERSION. - */ - private static final int CLASS_FILE_MIN_MAJOR_VERSION = 45; - - /** - * maximum {@code .class} file major version - * - * Note: if you change this, please change "java.class.version" in System.java. - */ - private static final int CLASS_FILE_MAX_MAJOR_VERSION = 53; - - /** maximum {@code .class} file minor version */ - private static final int CLASS_FILE_MAX_MINOR_VERSION = 0; - - /** - * {@code non-null;} the file path for the class, excluding any base directory - * specification - */ - private final String filePath; - - /** {@code non-null;} the bytes of the file */ - private final ByteArray bytes; - - /** - * whether to be strict about parsing; if - * {@code false}, this avoids doing checks that only exist - * for purposes of verification (such as magic number matching and - * path-package consistency checking) - */ - private final boolean strictParse; - - /** - * {@code null-ok;} the constant pool; only ever {@code null} - * before the constant pool is successfully parsed - */ - private StdConstantPool pool; - - /** - * the class file field {@code access_flags}; will be {@code -1} - * before the file is successfully parsed - */ - private int accessFlags; - - /** - * {@code null-ok;} the class file field {@code this_class}, - * interpreted as a type constant; only ever {@code null} - * before the file is successfully parsed - */ - private CstType thisClass; - - /** - * {@code null-ok;} the class file field {@code super_class}, interpreted - * as a type constant if non-zero - */ - private CstType superClass; - - /** - * {@code null-ok;} the class file field {@code interfaces}; only - * ever {@code null} before the file is successfully - * parsed - */ - private TypeList interfaces; - - /** - * {@code null-ok;} the class file field {@code fields}; only ever - * {@code null} before the file is successfully parsed - */ - private FieldList fields; - - /** - * {@code null-ok;} the class file field {@code methods}; only ever - * {@code null} before the file is successfully parsed - */ - private MethodList methods; - - /** - * {@code null-ok;} the class file field {@code attributes}; only - * ever {@code null} before the file is successfully - * parsed - */ - private StdAttributeList attributes; - - /** {@code null-ok;} attribute factory, if any */ - private AttributeFactory attributeFactory; - - /** {@code null-ok;} parse observer, if any */ - private ParseObserver observer; - - /** - * Returns the string form of an object or {@code "(none)"} - * (rather than {@code "null"}) for {@code null}. - * - * @param obj {@code null-ok;} the object to stringify - * @return {@code non-null;} the appropriate string form - */ - public static String stringOrNone(Object obj) { - if (obj == null) { - return "(none)"; - } - - return obj.toString(); - } - - /** - * Constructs an instance. - * - * @param bytes {@code non-null;} the bytes of the file - * @param filePath {@code non-null;} the file path for the class, - * excluding any base directory specification - * @param strictParse whether to be strict about parsing; if - * {@code false}, this avoids doing checks that only exist - * for purposes of verification (such as magic number matching and - * path-package consistency checking) - */ - public DirectClassFile(ByteArray bytes, String filePath, - boolean strictParse) { - if (bytes == null) { - throw new NullPointerException("bytes == null"); - } - - if (filePath == null) { - throw new NullPointerException("filePath == null"); - } - - this.filePath = filePath; - this.bytes = bytes; - this.strictParse = strictParse; - this.accessFlags = -1; - } - - /** - * Constructs an instance. - * - * @param bytes {@code non-null;} the bytes of the file - * @param filePath {@code non-null;} the file path for the class, - * excluding any base directory specification - * @param strictParse whether to be strict about parsing; if - * {@code false}, this avoids doing checks that only exist - * for purposes of verification (such as magic number matching and - * path-package consistency checking) - */ - public DirectClassFile(byte[] bytes, String filePath, - boolean strictParse) { - this(new ByteArray(bytes), filePath, strictParse); - } - - /** - * Sets the parse observer for this instance. - * - * @param observer {@code null-ok;} the observer - */ - public void setObserver(ParseObserver observer) { - this.observer = observer; - } - - /** - * Sets the attribute factory to use. - * - * @param attributeFactory {@code non-null;} the attribute factory - */ - public void setAttributeFactory(AttributeFactory attributeFactory) { - if (attributeFactory == null) { - throw new NullPointerException("attributeFactory == null"); - } - - this.attributeFactory = attributeFactory; - } - - /** - * Gets the path where this class file is located. - * - * @return {@code non-null;} the filePath - */ - public String getFilePath() { - return filePath; - } - - /** - * Gets the {@link ByteArray} that this instance's data comes from. - * - * @return {@code non-null;} the bytes - */ - public ByteArray getBytes() { - return bytes; - } - - /** {@inheritDoc} */ - @Override - public int getMagic() { - parseToInterfacesIfNecessary(); - return getMagic0(); - } - - /** {@inheritDoc} */ - @Override - public int getMinorVersion() { - parseToInterfacesIfNecessary(); - return getMinorVersion0(); - } - - /** {@inheritDoc} */ - @Override - public int getMajorVersion() { - parseToInterfacesIfNecessary(); - return getMajorVersion0(); - } - - /** {@inheritDoc} */ - @Override - public int getAccessFlags() { - parseToInterfacesIfNecessary(); - return accessFlags; - } - - /** {@inheritDoc} */ - @Override - public CstType getThisClass() { - parseToInterfacesIfNecessary(); - return thisClass; - } - - /** {@inheritDoc} */ - @Override - public CstType getSuperclass() { - parseToInterfacesIfNecessary(); - return superClass; - } - - /** {@inheritDoc} */ - @Override - public ConstantPool getConstantPool() { - parseToInterfacesIfNecessary(); - return pool; - } - - /** {@inheritDoc} */ - @Override - public TypeList getInterfaces() { - parseToInterfacesIfNecessary(); - return interfaces; - } - - /** {@inheritDoc} */ - @Override - public FieldList getFields() { - parseToEndIfNecessary(); - return fields; - } - - /** {@inheritDoc} */ - @Override - public MethodList getMethods() { - parseToEndIfNecessary(); - return methods; - } - - /** {@inheritDoc} */ - @Override - public AttributeList getAttributes() { - parseToEndIfNecessary(); - return attributes; - } - - /** {@inheritDoc} */ - @Override - public BootstrapMethodsList getBootstrapMethods() { - AttBootstrapMethods bootstrapMethodsAttribute = - (AttBootstrapMethods) getAttributes().findFirst(AttBootstrapMethods.ATTRIBUTE_NAME); - if (bootstrapMethodsAttribute != null) { - return bootstrapMethodsAttribute.getBootstrapMethods(); - } else { - return BootstrapMethodsList.EMPTY; - } - } - - /** {@inheritDoc} */ - @Override - public CstString getSourceFile() { - AttributeList attribs = getAttributes(); - Attribute attSf = attribs.findFirst(AttSourceFile.ATTRIBUTE_NAME); - - if (attSf instanceof AttSourceFile) { - return ((AttSourceFile) attSf).getSourceFile(); - } - - return null; - } - - /** - * Constructs and returns an instance of {@link TypeList} whose - * data comes from the bytes of this instance, interpreted as a - * list of constant pool indices for classes, which are in turn - * translated to type constants. Instance construction will fail - * if any of the (alleged) indices turn out not to refer to - * constant pool entries of type {@code Class}. - * - * @param offset offset into {@link #bytes} for the start of the - * data - * @param size number of elements in the list (not number of bytes) - * @return {@code non-null;} an appropriately-constructed class list - */ - public TypeList makeTypeList(int offset, int size) { - if (size == 0) { - return StdTypeList.EMPTY; - } - - if (pool == null) { - throw new IllegalStateException("pool not yet initialized"); - } - - return new DcfTypeList(bytes, offset, size, pool, observer); - } - - /** - * Gets the class file field {@code magic}, but without doing any - * checks or parsing first. - * - * @return the magic value - */ - public int getMagic0() { - return bytes.getInt(0); - } - - /** - * Gets the class file field {@code minor_version}, but - * without doing any checks or parsing first. - * - * @return the minor version - */ - public int getMinorVersion0() { - return bytes.getUnsignedShort(4); - } - - /** - * Gets the class file field {@code major_version}, but - * without doing any checks or parsing first. - * - * @return the major version - */ - public int getMajorVersion0() { - return bytes.getUnsignedShort(6); - } - - /** - * Runs {@link #parse} if it has not yet been run to cover up to - * the interfaces list. - */ - private void parseToInterfacesIfNecessary() { - if (accessFlags == -1) { - parse(); - } - } - - /** - * Runs {@link #parse} if it has not yet been run successfully. - */ - private void parseToEndIfNecessary() { - if (attributes == null) { - parse(); - } - } - - /** - * Does the parsing, handing exceptions. - */ - private void parse() { - try { - parse0(); - } catch (ParseException ex) { - ex.addContext("...while parsing " + filePath); - throw ex; - } catch (RuntimeException ex) { - ParseException pe = new ParseException(ex); - pe.addContext("...while parsing " + filePath); - throw pe; - } - } - - /** - * Sees if the .class file header magic has the good value. - * - * @param magic the value of a classfile "magic" field - * @return true if the magic is valid - */ - private boolean isGoodMagic(int magic) { - return magic == CLASS_FILE_MAGIC; - } - - /** - * Sees if the .class file header version are within - * range. - * - * @param minorVersion the value of a classfile "minor_version" field - * @param majorVersion the value of a classfile "major_version" field - * @return true if the parameters are valid and within range - */ - private boolean isGoodVersion(int minorVersion, int majorVersion) { - /* Valid version ranges are typically of the form - * "A.0 through B.C inclusive" where A <= B and C >= 0, - * which is why we don't have a CLASS_FILE_MIN_MINOR_VERSION. - */ - if (minorVersion >= 0) { - /* Check against max first to handle the case where - * MIN_MAJOR == MAX_MAJOR. - */ - if (majorVersion == CLASS_FILE_MAX_MAJOR_VERSION) { - if (minorVersion <= CLASS_FILE_MAX_MINOR_VERSION) { - return true; - } - } else if (majorVersion < CLASS_FILE_MAX_MAJOR_VERSION && - majorVersion >= CLASS_FILE_MIN_MAJOR_VERSION) { - return true; - } - } - - return false; - } - - /** - * Does the actual parsing. - */ - private void parse0() { - if (bytes.size() < 10) { - throw new ParseException("severely truncated class file"); - } - - if (observer != null) { - observer.parsed(bytes, 0, 0, "begin classfile"); - observer.parsed(bytes, 0, 4, "magic: " + Hex.u4(getMagic0())); - observer.parsed(bytes, 4, 2, - "minor_version: " + Hex.u2(getMinorVersion0())); - observer.parsed(bytes, 6, 2, - "major_version: " + Hex.u2(getMajorVersion0())); - } - - if (strictParse) { - /* Make sure that this looks like a valid class file with a - * version that we can handle. - */ - if (!isGoodMagic(getMagic0())) { - throw new ParseException("bad class file magic (" + Hex.u4(getMagic0()) + ")"); - } - - if (!isGoodVersion(getMinorVersion0(), getMajorVersion0())) { - throw new ParseException("unsupported class file version " + - getMajorVersion0() + "." + - getMinorVersion0()); - } - } - - ConstantPoolParser cpParser = new ConstantPoolParser(bytes); - cpParser.setObserver(observer); - pool = cpParser.getPool(); - pool.setImmutable(); - - int at = cpParser.getEndOffset(); - int accessFlags = bytes.getUnsignedShort(at); // u2 access_flags; - int cpi = bytes.getUnsignedShort(at + 2); // u2 this_class; - thisClass = (CstType) pool.get(cpi); - cpi = bytes.getUnsignedShort(at + 4); // u2 super_class; - superClass = (CstType) pool.get0Ok(cpi); - int count = bytes.getUnsignedShort(at + 6); // u2 interfaces_count - - if (observer != null) { - observer.parsed(bytes, at, 2, - "access_flags: " + - AccessFlags.classString(accessFlags)); - observer.parsed(bytes, at + 2, 2, "this_class: " + thisClass); - observer.parsed(bytes, at + 4, 2, "super_class: " + - stringOrNone(superClass)); - observer.parsed(bytes, at + 6, 2, - "interfaces_count: " + Hex.u2(count)); - if (count != 0) { - observer.parsed(bytes, at + 8, 0, "interfaces:"); - } - } - - at += 8; - interfaces = makeTypeList(at, count); - at += count * 2; - - if (strictParse) { - /* - * Make sure that the file/jar path matches the declared - * package/class name. - */ - String thisClassName = thisClass.getClassType().getClassName(); - if (!(filePath.endsWith(".class") && - filePath.startsWith(thisClassName) && - (filePath.length() == (thisClassName.length() + 6)))) { - throw new ParseException("class name (" + thisClassName + - ") does not match path (" + - filePath + ")"); - } - } - - /* - * Only set the instance variable accessFlags here, since - * that's what signals a successful parse of the first part of - * the file (through the interfaces list). - */ - this.accessFlags = accessFlags; - - FieldListParser flParser = - new FieldListParser(this, thisClass, at, attributeFactory); - flParser.setObserver(observer); - fields = flParser.getList(); - at = flParser.getEndOffset(); - - MethodListParser mlParser = - new MethodListParser(this, thisClass, at, attributeFactory); - mlParser.setObserver(observer); - methods = mlParser.getList(); - at = mlParser.getEndOffset(); - - AttributeListParser alParser = - new AttributeListParser(this, AttributeFactory.CTX_CLASS, at, - attributeFactory); - alParser.setObserver(observer); - attributes = alParser.getList(); - attributes.setImmutable(); - at = alParser.getEndOffset(); - - if (at != bytes.size()) { - throw new ParseException("extra bytes at end of class file, " + - "at offset " + Hex.u4(at)); - } - - if (observer != null) { - observer.parsed(bytes, at, 0, "end classfile"); - } - } - - /** - * Implementation of {@link TypeList} whose data comes directly - * from the bytes of an instance of this (outer) class, - * interpreted as a list of constant pool indices for classes - * which are in turn returned as type constants. Instance - * construction will fail if any of the (alleged) indices turn out - * not to refer to constant pool entries of type - * {@code Class}. - */ - private static class DcfTypeList implements TypeList { - /** {@code non-null;} array containing the data */ - private final ByteArray bytes; - - /** number of elements in the list (not number of bytes) */ - private final int size; - - /** {@code non-null;} the constant pool */ - private final StdConstantPool pool; - - /** - * Constructs an instance. - * - * @param bytes {@code non-null;} original classfile's bytes - * @param offset offset into {@link #bytes} for the start of the - * data - * @param size number of elements in the list (not number of bytes) - * @param pool {@code non-null;} the constant pool to use - * @param observer {@code null-ok;} parse observer to use, if any - */ - public DcfTypeList(ByteArray bytes, int offset, int size, - StdConstantPool pool, ParseObserver observer) { - if (size < 0) { - throw new IllegalArgumentException("size < 0"); - } - - bytes = bytes.slice(offset, offset + size * 2); - this.bytes = bytes; - this.size = size; - this.pool = pool; - - for (int i = 0; i < size; i++) { - offset = i * 2; - int idx = bytes.getUnsignedShort(offset); - CstType type; - try { - type = (CstType) pool.get(idx); - } catch (ClassCastException ex) { - // Translate the exception. - throw new RuntimeException("bogus class cpi", ex); - } - if (observer != null) { - observer.parsed(bytes, offset, 2, " " + type); - } - } - } - - /** {@inheritDoc} */ - @Override - public boolean isMutable() { - return false; - } - - /** {@inheritDoc} */ - @Override - public int size() { - return size; - } - - /** {@inheritDoc} */ - @Override - public int getWordCount() { - // It is the same as size because all elements are classes. - return size; - } - - /** {@inheritDoc} */ - @Override - public Type getType(int n) { - int idx = bytes.getUnsignedShort(n * 2); - return ((CstType) pool.get(idx)).getClassType(); - } - - /** {@inheritDoc} */ - @Override - public TypeList withAddedType(Type type) { - throw new UnsupportedOperationException("unsupported"); - } - } -} diff --git a/app/src/main/java/com/pojavdx/dx/cf/direct/FieldListParser.java b/app/src/main/java/com/pojavdx/dx/cf/direct/FieldListParser.java deleted file mode 100644 index bff6f9c52..000000000 --- a/app/src/main/java/com/pojavdx/dx/cf/direct/FieldListParser.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.pojavdx.dx.cf.direct; - -import com.pojavdx.dx.cf.iface.AttributeList; -import com.pojavdx.dx.cf.iface.Member; -import com.pojavdx.dx.cf.iface.StdField; -import com.pojavdx.dx.cf.iface.StdFieldList; -import com.pojavdx.dx.rop.code.AccessFlags; -import com.pojavdx.dx.rop.cst.CstNat; -import com.pojavdx.dx.rop.cst.CstType; - -/** - * Parser for lists of fields in a class file. - */ -final /*package*/ class FieldListParser extends MemberListParser { - /** {@code non-null;} list in progress */ - private final StdFieldList fields; - - /** - * Constructs an instance. - * - * @param cf {@code non-null;} the class file to parse from - * @param definer {@code non-null;} class being defined - * @param offset offset in {@code bytes} to the start of the list - * @param attributeFactory {@code non-null;} attribute factory to use - */ - public FieldListParser(DirectClassFile cf, CstType definer, int offset, - AttributeFactory attributeFactory) { - super(cf, definer, offset, attributeFactory); - fields = new StdFieldList(getCount()); - } - - /** - * Gets the parsed list. - * - * @return {@code non-null;} the parsed list - */ - public StdFieldList getList() { - parseIfNecessary(); - return fields; - } - - /** {@inheritDoc} */ - @Override - protected String humanName() { - return "field"; - } - - /** {@inheritDoc} */ - @Override - protected String humanAccessFlags(int accessFlags) { - return AccessFlags.fieldString(accessFlags); - } - - /** {@inheritDoc} */ - @Override - protected int getAttributeContext() { - return AttributeFactory.CTX_FIELD; - } - - /** {@inheritDoc} */ - @Override - protected Member set(int n, int accessFlags, CstNat nat, - AttributeList attributes) { - StdField field = - new StdField(getDefiner(), accessFlags, nat, attributes); - - fields.set(n, field); - return field; - } -} diff --git a/app/src/main/java/com/pojavdx/dx/cf/direct/MemberListParser.java b/app/src/main/java/com/pojavdx/dx/cf/direct/MemberListParser.java deleted file mode 100644 index c0bc3e09a..000000000 --- a/app/src/main/java/com/pojavdx/dx/cf/direct/MemberListParser.java +++ /dev/null @@ -1,240 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.pojavdx.dx.cf.direct; - -import com.pojavdx.dx.cf.iface.AttributeList; -import com.pojavdx.dx.cf.iface.Member; -import com.pojavdx.dx.cf.iface.ParseException; -import com.pojavdx.dx.cf.iface.ParseObserver; -import com.pojavdx.dx.cf.iface.StdAttributeList; -import com.pojavdx.dx.rop.cst.ConstantPool; -import com.pojavdx.dx.rop.cst.CstNat; -import com.pojavdx.dx.rop.cst.CstString; -import com.pojavdx.dx.rop.cst.CstType; -import com.pojavdx.dx.util.ByteArray; -import com.pojavdx.dx.util.Hex; - -/** - * Parser for lists of class file members (that is, fields and methods). - */ -abstract /*package*/ class MemberListParser { - /** {@code non-null;} the class file to parse from */ - private final DirectClassFile cf; - - /** {@code non-null;} class being defined */ - private final CstType definer; - - /** offset in the byte array of the classfile to the start of the list */ - private final int offset; - - /** {@code non-null;} attribute factory to use */ - private final AttributeFactory attributeFactory; - - /** {@code >= -1;} the end offset of this list in the byte array of the - * classfile, or {@code -1} if not yet parsed */ - private int endOffset; - - /** {@code null-ok;} parse observer, if any */ - private ParseObserver observer; - - /** - * Constructs an instance. - * - * @param cf {@code non-null;} the class file to parse from - * @param definer {@code non-null;} class being defined - * @param offset offset in {@code bytes} to the start of the list - * @param attributeFactory {@code non-null;} attribute factory to use - */ - public MemberListParser(DirectClassFile cf, CstType definer, - int offset, AttributeFactory attributeFactory) { - if (cf == null) { - throw new NullPointerException("cf == null"); - } - - if (offset < 0) { - throw new IllegalArgumentException("offset < 0"); - } - - if (attributeFactory == null) { - throw new NullPointerException("attributeFactory == null"); - } - - this.cf = cf; - this.definer = definer; - this.offset = offset; - this.attributeFactory = attributeFactory; - this.endOffset = -1; - } - - /** - * Gets the end offset of this constant pool in the {@code byte[]} - * which it came from. - * - * @return {@code >= 0;} the end offset - */ - public int getEndOffset() { - parseIfNecessary(); - return endOffset; - } - - /** - * Sets the parse observer for this instance. - * - * @param observer {@code null-ok;} the observer - */ - public final void setObserver(ParseObserver observer) { - this.observer = observer; - } - - /** - * Runs {@link #parse} if it has not yet been run successfully. - */ - protected final void parseIfNecessary() { - if (endOffset < 0) { - parse(); - } - } - - /** - * Gets the count of elements in the list. - * - * @return the count - */ - protected final int getCount() { - ByteArray bytes = cf.getBytes(); - return bytes.getUnsignedShort(offset); - } - - /** - * Gets the class file being defined. - * - * @return {@code non-null;} the class - */ - protected final CstType getDefiner() { - return definer; - } - - /** - * Gets the human-oriented name for what this instance is parsing. - * Subclasses must override this method. - * - * @return {@code non-null;} the human oriented name - */ - protected abstract String humanName(); - - /** - * Gets the human-oriented string for the given access flags. - * Subclasses must override this method. - * - * @param accessFlags the flags - * @return {@code non-null;} the string form - */ - protected abstract String humanAccessFlags(int accessFlags); - - /** - * Gets the {@code CTX_*} constant to use when parsing attributes. - * Subclasses must override this method. - * - * @return {@code non-null;} the human oriented name - */ - protected abstract int getAttributeContext(); - - /** - * Sets an element in the list. Subclasses must override this method. - * - * @param n which element - * @param accessFlags the {@code access_flags} - * @param nat the interpreted name and type (based on the two - * {@code *_index} fields) - * @param attributes list of parsed attributes - * @return {@code non-null;} the constructed member - */ - protected abstract Member set(int n, int accessFlags, CstNat nat, - AttributeList attributes); - - /** - * Does the actual parsing. - */ - private void parse() { - int attributeContext = getAttributeContext(); - int count = getCount(); - int at = offset + 2; // Skip the count. - - ByteArray bytes = cf.getBytes(); - ConstantPool pool = cf.getConstantPool(); - - if (observer != null) { - observer.parsed(bytes, offset, 2, - humanName() + "s_count: " + Hex.u2(count)); - } - - for (int i = 0; i < count; i++) { - try { - int accessFlags = bytes.getUnsignedShort(at); - int nameIdx = bytes.getUnsignedShort(at + 2); - int descIdx = bytes.getUnsignedShort(at + 4); - CstString name = (CstString) pool.get(nameIdx); - CstString desc = (CstString) pool.get(descIdx); - - if (observer != null) { - observer.startParsingMember(bytes, at, name.getString(), - desc.getString()); - observer.parsed(bytes, at, 0, "\n" + humanName() + - "s[" + i + "]:\n"); - observer.changeIndent(1); - observer.parsed(bytes, at, 2, - "access_flags: " + - humanAccessFlags(accessFlags)); - observer.parsed(bytes, at + 2, 2, - "name: " + name.toHuman()); - observer.parsed(bytes, at + 4, 2, - "descriptor: " + desc.toHuman()); - } - - at += 6; - AttributeListParser parser = - new AttributeListParser(cf, attributeContext, at, - attributeFactory); - parser.setObserver(observer); - at = parser.getEndOffset(); - StdAttributeList attributes = parser.getList(); - attributes.setImmutable(); - CstNat nat = new CstNat(name, desc); - Member member = set(i, accessFlags, nat, attributes); - - if (observer != null) { - observer.changeIndent(-1); - observer.parsed(bytes, at, 0, "end " + humanName() + - "s[" + i + "]\n"); - observer.endParsingMember(bytes, at, name.getString(), - desc.getString(), member); - } - } catch (ParseException ex) { - ex.addContext("...while parsing " + humanName() + "s[" + i + - "]"); - throw ex; - } catch (RuntimeException ex) { - ParseException pe = new ParseException(ex); - pe.addContext("...while parsing " + humanName() + "s[" + i + - "]"); - throw pe; - } - } - - endOffset = at; - } -} diff --git a/app/src/main/java/com/pojavdx/dx/cf/direct/MethodListParser.java b/app/src/main/java/com/pojavdx/dx/cf/direct/MethodListParser.java deleted file mode 100644 index aaf73f25a..000000000 --- a/app/src/main/java/com/pojavdx/dx/cf/direct/MethodListParser.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.pojavdx.dx.cf.direct; - -import com.pojavdx.dx.cf.iface.AttributeList; -import com.pojavdx.dx.cf.iface.Member; -import com.pojavdx.dx.cf.iface.StdMethod; -import com.pojavdx.dx.cf.iface.StdMethodList; -import com.pojavdx.dx.rop.code.AccessFlags; -import com.pojavdx.dx.rop.cst.CstNat; -import com.pojavdx.dx.rop.cst.CstType; - -/** - * Parser for lists of methods in a class file. - */ -final /*package*/ class MethodListParser extends MemberListParser { - /** {@code non-null;} list in progress */ - final private StdMethodList methods; - - /** - * Constructs an instance. - * - * @param cf {@code non-null;} the class file to parse from - * @param definer {@code non-null;} class being defined - * @param offset offset in {@code bytes} to the start of the list - * @param attributeFactory {@code non-null;} attribute factory to use - */ - public MethodListParser(DirectClassFile cf, CstType definer, - int offset, AttributeFactory attributeFactory) { - super(cf, definer, offset, attributeFactory); - methods = new StdMethodList(getCount()); - } - - /** - * Gets the parsed list. - * - * @return {@code non-null;} the parsed list - */ - public StdMethodList getList() { - parseIfNecessary(); - return methods; - } - - /** {@inheritDoc} */ - @Override - protected String humanName() { - return "method"; - } - - /** {@inheritDoc} */ - @Override - protected String humanAccessFlags(int accessFlags) { - return AccessFlags.methodString(accessFlags); - } - - /** {@inheritDoc} */ - @Override - protected int getAttributeContext() { - return AttributeFactory.CTX_METHOD; - } - - /** {@inheritDoc} */ - @Override - protected Member set(int n, int accessFlags, CstNat nat, - AttributeList attributes) { - StdMethod meth = - new StdMethod(getDefiner(), accessFlags, nat, attributes); - - methods.set(n, meth); - return meth; - } -} diff --git a/app/src/main/java/com/pojavdx/dx/cf/direct/StdAttributeFactory.java b/app/src/main/java/com/pojavdx/dx/cf/direct/StdAttributeFactory.java deleted file mode 100644 index bd90d6f4e..000000000 --- a/app/src/main/java/com/pojavdx/dx/cf/direct/StdAttributeFactory.java +++ /dev/null @@ -1,861 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.pojavdx.dx.cf.direct; - -import com.pojavdx.dx.cf.attrib.AttAnnotationDefault; -import com.pojavdx.dx.cf.attrib.AttBootstrapMethods; -import com.pojavdx.dx.cf.attrib.AttCode; -import com.pojavdx.dx.cf.attrib.AttConstantValue; -import com.pojavdx.dx.cf.attrib.AttDeprecated; -import com.pojavdx.dx.cf.attrib.AttEnclosingMethod; -import com.pojavdx.dx.cf.attrib.AttExceptions; -import com.pojavdx.dx.cf.attrib.AttInnerClasses; -import com.pojavdx.dx.cf.attrib.AttLineNumberTable; -import com.pojavdx.dx.cf.attrib.AttLocalVariableTable; -import com.pojavdx.dx.cf.attrib.AttLocalVariableTypeTable; -import com.pojavdx.dx.cf.attrib.AttRuntimeInvisibleAnnotations; -import com.pojavdx.dx.cf.attrib.AttRuntimeInvisibleParameterAnnotations; -import com.pojavdx.dx.cf.attrib.AttRuntimeVisibleAnnotations; -import com.pojavdx.dx.cf.attrib.AttRuntimeVisibleParameterAnnotations; -import com.pojavdx.dx.cf.attrib.AttSignature; -import com.pojavdx.dx.cf.attrib.AttSourceDebugExtension; -import com.pojavdx.dx.cf.attrib.AttSourceFile; -import com.pojavdx.dx.cf.attrib.AttSynthetic; -import com.pojavdx.dx.cf.attrib.InnerClassList; -import com.pojavdx.dx.cf.code.BootstrapMethodArgumentsList; -import com.pojavdx.dx.cf.code.BootstrapMethodsList; -import com.pojavdx.dx.cf.code.ByteCatchList; -import com.pojavdx.dx.cf.code.BytecodeArray; -import com.pojavdx.dx.cf.code.LineNumberList; -import com.pojavdx.dx.cf.code.LocalVariableList; -import com.pojavdx.dx.cf.iface.Attribute; -import com.pojavdx.dx.cf.iface.ParseException; -import com.pojavdx.dx.cf.iface.ParseObserver; -import com.pojavdx.dx.cf.iface.StdAttributeList; -import com.pojavdx.dx.rop.annotation.AnnotationVisibility; -import com.pojavdx.dx.rop.annotation.Annotations; -import com.pojavdx.dx.rop.annotation.AnnotationsList; -import com.pojavdx.dx.rop.code.AccessFlags; -import com.pojavdx.dx.rop.cst.Constant; -import com.pojavdx.dx.rop.cst.ConstantPool; -import com.pojavdx.dx.rop.cst.CstMethodHandle; -import com.pojavdx.dx.rop.cst.CstNat; -import com.pojavdx.dx.rop.cst.CstString; -import com.pojavdx.dx.rop.cst.CstType; -import com.pojavdx.dx.rop.cst.TypedConstant; -import com.pojavdx.dx.rop.type.TypeList; -import com.pojavdx.dx.util.ByteArray; -import com.pojavdx.dx.util.Hex; -import java.io.IOException; - -/** - * Standard subclass of {@link AttributeFactory}, which knows how to parse - * all the standard attribute types. - */ -public class StdAttributeFactory - extends AttributeFactory { - /** {@code non-null;} shared instance of this class */ - public static final StdAttributeFactory THE_ONE = - new StdAttributeFactory(); - - /** - * Constructs an instance. - */ - public StdAttributeFactory() { - // This space intentionally left blank. - } - - /** {@inheritDoc} */ - @Override - protected Attribute parse0(DirectClassFile cf, int context, String name, - int offset, int length, ParseObserver observer) { - switch (context) { - case CTX_CLASS: { - if (name == AttBootstrapMethods.ATTRIBUTE_NAME) { - return bootstrapMethods(cf, offset, length, observer); - } - if (name == AttDeprecated.ATTRIBUTE_NAME) { - return deprecated(cf, offset, length, observer); - } - if (name == AttEnclosingMethod.ATTRIBUTE_NAME) { - return enclosingMethod(cf, offset, length, observer); - } - if (name == AttInnerClasses.ATTRIBUTE_NAME) { - return innerClasses(cf, offset, length, observer); - } - if (name == AttRuntimeInvisibleAnnotations.ATTRIBUTE_NAME) { - return runtimeInvisibleAnnotations(cf, offset, length, - observer); - } - if (name == AttRuntimeVisibleAnnotations.ATTRIBUTE_NAME) { - return runtimeVisibleAnnotations(cf, offset, length, - observer); - } - if (name == AttSynthetic.ATTRIBUTE_NAME) { - return synthetic(cf, offset, length, observer); - } - if (name == AttSignature.ATTRIBUTE_NAME) { - return signature(cf, offset, length, observer); - } - if (name == AttSourceDebugExtension.ATTRIBUTE_NAME) { - return sourceDebugExtension(cf, offset, length, observer); - } - if (name == AttSourceFile.ATTRIBUTE_NAME) { - return sourceFile(cf, offset, length, observer); - } - break; - } - case CTX_FIELD: { - if (name == AttConstantValue.ATTRIBUTE_NAME) { - return constantValue(cf, offset, length, observer); - } - if (name == AttDeprecated.ATTRIBUTE_NAME) { - return deprecated(cf, offset, length, observer); - } - if (name == AttRuntimeInvisibleAnnotations.ATTRIBUTE_NAME) { - return runtimeInvisibleAnnotations(cf, offset, length, - observer); - } - if (name == AttRuntimeVisibleAnnotations.ATTRIBUTE_NAME) { - return runtimeVisibleAnnotations(cf, offset, length, - observer); - } - if (name == AttSignature.ATTRIBUTE_NAME) { - return signature(cf, offset, length, observer); - } - if (name == AttSynthetic.ATTRIBUTE_NAME) { - return synthetic(cf, offset, length, observer); - } - break; - } - case CTX_METHOD: { - if (name == AttAnnotationDefault.ATTRIBUTE_NAME) { - return annotationDefault(cf, offset, length, observer); - } - if (name == AttCode.ATTRIBUTE_NAME) { - return code(cf, offset, length, observer); - } - if (name == AttDeprecated.ATTRIBUTE_NAME) { - return deprecated(cf, offset, length, observer); - } - if (name == AttExceptions.ATTRIBUTE_NAME) { - return exceptions(cf, offset, length, observer); - } - if (name == AttRuntimeInvisibleAnnotations.ATTRIBUTE_NAME) { - return runtimeInvisibleAnnotations(cf, offset, length, - observer); - } - if (name == AttRuntimeVisibleAnnotations.ATTRIBUTE_NAME) { - return runtimeVisibleAnnotations(cf, offset, length, - observer); - } - if (name == AttRuntimeInvisibleParameterAnnotations. - ATTRIBUTE_NAME) { - return runtimeInvisibleParameterAnnotations( - cf, offset, length, observer); - } - if (name == AttRuntimeVisibleParameterAnnotations. - ATTRIBUTE_NAME) { - return runtimeVisibleParameterAnnotations( - cf, offset, length, observer); - } - if (name == AttSignature.ATTRIBUTE_NAME) { - return signature(cf, offset, length, observer); - } - if (name == AttSynthetic.ATTRIBUTE_NAME) { - return synthetic(cf, offset, length, observer); - } - break; - } - case CTX_CODE: { - if (name == AttLineNumberTable.ATTRIBUTE_NAME) { - return lineNumberTable(cf, offset, length, observer); - } - if (name == AttLocalVariableTable.ATTRIBUTE_NAME) { - return localVariableTable(cf, offset, length, observer); - } - if (name == AttLocalVariableTypeTable.ATTRIBUTE_NAME) { - return localVariableTypeTable(cf, offset, length, - observer); - } - break; - } - } - - return super.parse0(cf, context, name, offset, length, observer); - } - - /** - * Parses an {@code AnnotationDefault} attribute. - */ - private Attribute annotationDefault(DirectClassFile cf, - int offset, int length, ParseObserver observer) { - if (length < 2) { - throwSeverelyTruncated(); - } - - AnnotationParser ap = - new AnnotationParser(cf, offset, length, observer); - Constant cst = ap.parseValueAttribute(); - - return new AttAnnotationDefault(cst, length); - } - - /** - * Parses a {@code BootstrapMethods} attribute. - */ - private Attribute bootstrapMethods(DirectClassFile cf, int offset, int length, - ParseObserver observer) { - if (length < 2) { - return throwSeverelyTruncated(); - } - - ByteArray bytes = cf.getBytes(); - int numMethods = bytes.getUnsignedShort(offset); - if (observer != null) { - observer.parsed(bytes, offset, 2, - "num_boostrap_methods: " + Hex.u2(numMethods)); - } - - offset += 2; - length -= 2; - - BootstrapMethodsList methods = parseBootstrapMethods(bytes, cf.getConstantPool(), - cf.getThisClass(), numMethods, - offset, length, observer); - return new AttBootstrapMethods(methods); - } - - /** - * Parses a {@code Code} attribute. - */ - private Attribute code(DirectClassFile cf, int offset, int length, - ParseObserver observer) { - if (length < 12) { - return throwSeverelyTruncated(); - } - - ByteArray bytes = cf.getBytes(); - ConstantPool pool = cf.getConstantPool(); - int maxStack = bytes.getUnsignedShort(offset); // u2 max_stack - int maxLocals = bytes.getUnsignedShort(offset + 2); // u2 max_locals - int codeLength = bytes.getInt(offset + 4); // u4 code_length - int origOffset = offset; - - if (observer != null) { - observer.parsed(bytes, offset, 2, - "max_stack: " + Hex.u2(maxStack)); - observer.parsed(bytes, offset + 2, 2, - "max_locals: " + Hex.u2(maxLocals)); - observer.parsed(bytes, offset + 4, 4, - "code_length: " + Hex.u4(codeLength)); - } - - offset += 8; - length -= 8; - - if (length < (codeLength + 4)) { - return throwTruncated(); - } - - int codeOffset = offset; - offset += codeLength; - length -= codeLength; - BytecodeArray code = - new BytecodeArray(bytes.slice(codeOffset, codeOffset + codeLength), - pool); - if (observer != null) { - code.forEach(new CodeObserver(code.getBytes(), observer)); - } - - // u2 exception_table_length - int exceptionTableLength = bytes.getUnsignedShort(offset); - ByteCatchList catches = (exceptionTableLength == 0) ? - ByteCatchList.EMPTY : - new ByteCatchList(exceptionTableLength); - - if (observer != null) { - observer.parsed(bytes, offset, 2, - "exception_table_length: " + - Hex.u2(exceptionTableLength)); - } - - offset += 2; - length -= 2; - - if (length < (exceptionTableLength * 8 + 2)) { - return throwTruncated(); - } - - for (int i = 0; i < exceptionTableLength; i++) { - if (observer != null) { - observer.changeIndent(1); - } - - int startPc = bytes.getUnsignedShort(offset); - int endPc = bytes.getUnsignedShort(offset + 2); - int handlerPc = bytes.getUnsignedShort(offset + 4); - int catchTypeIdx = bytes.getUnsignedShort(offset + 6); - CstType catchType = (CstType) pool.get0Ok(catchTypeIdx); - catches.set(i, startPc, endPc, handlerPc, catchType); - if (observer != null) { - observer.parsed(bytes, offset, 8, - Hex.u2(startPc) + ".." + Hex.u2(endPc) + - " -> " + Hex.u2(handlerPc) + " " + - ((catchType == null) ? "" : - catchType.toHuman())); - } - offset += 8; - length -= 8; - - if (observer != null) { - observer.changeIndent(-1); - } - } - - catches.setImmutable(); - - AttributeListParser parser = - new AttributeListParser(cf, CTX_CODE, offset, this); - parser.setObserver(observer); - - StdAttributeList attributes = parser.getList(); - attributes.setImmutable(); - - int attributeByteCount = parser.getEndOffset() - offset; - if (attributeByteCount != length) { - return throwBadLength(attributeByteCount + (offset - origOffset)); - } - - return new AttCode(maxStack, maxLocals, code, catches, attributes); - } - - /** - * Parses a {@code ConstantValue} attribute. - */ - private Attribute constantValue(DirectClassFile cf, int offset, int length, - ParseObserver observer) { - if (length != 2) { - return throwBadLength(2); - } - - ByteArray bytes = cf.getBytes(); - ConstantPool pool = cf.getConstantPool(); - int idx = bytes.getUnsignedShort(offset); - TypedConstant cst = (TypedConstant) pool.get(idx); - Attribute result = new AttConstantValue(cst); - - if (observer != null) { - observer.parsed(bytes, offset, 2, "value: " + cst); - } - - return result; - } - - /** - * Parses a {@code Deprecated} attribute. - */ - private Attribute deprecated(DirectClassFile cf, int offset, int length, - ParseObserver observer) { - if (length != 0) { - return throwBadLength(0); - } - - return new AttDeprecated(); - } - - /** - * Parses an {@code EnclosingMethod} attribute. - */ - private Attribute enclosingMethod(DirectClassFile cf, int offset, - int length, ParseObserver observer) { - if (length != 4) { - throwBadLength(4); - } - - ByteArray bytes = cf.getBytes(); - ConstantPool pool = cf.getConstantPool(); - - int idx = bytes.getUnsignedShort(offset); - CstType type = (CstType) pool.get(idx); - - idx = bytes.getUnsignedShort(offset + 2); - CstNat method = (CstNat) pool.get0Ok(idx); - - Attribute result = new AttEnclosingMethod(type, method); - - if (observer != null) { - observer.parsed(bytes, offset, 2, "class: " + type); - observer.parsed(bytes, offset + 2, 2, "method: " + - DirectClassFile.stringOrNone(method)); - } - - return result; - } - - /** - * Parses an {@code Exceptions} attribute. - */ - private Attribute exceptions(DirectClassFile cf, int offset, int length, - ParseObserver observer) { - if (length < 2) { - return throwSeverelyTruncated(); - } - - ByteArray bytes = cf.getBytes(); - int count = bytes.getUnsignedShort(offset); // number_of_exceptions - - if (observer != null) { - observer.parsed(bytes, offset, 2, - "number_of_exceptions: " + Hex.u2(count)); - } - - offset += 2; - length -= 2; - - if (length != (count * 2)) { - throwBadLength((count * 2) + 2); - } - - TypeList list = cf.makeTypeList(offset, count); - return new AttExceptions(list); - } - - /** - * Parses an {@code InnerClasses} attribute. - */ - private Attribute innerClasses(DirectClassFile cf, int offset, int length, - ParseObserver observer) { - if (length < 2) { - return throwSeverelyTruncated(); - } - - ByteArray bytes = cf.getBytes(); - ConstantPool pool = cf.getConstantPool(); - int count = bytes.getUnsignedShort(offset); // number_of_classes - - if (observer != null) { - observer.parsed(bytes, offset, 2, - "number_of_classes: " + Hex.u2(count)); - } - - offset += 2; - length -= 2; - - if (length != (count * 8)) { - throwBadLength((count * 8) + 2); - } - - InnerClassList list = new InnerClassList(count); - - for (int i = 0; i < count; i++) { - int innerClassIdx = bytes.getUnsignedShort(offset); - int outerClassIdx = bytes.getUnsignedShort(offset + 2); - int nameIdx = bytes.getUnsignedShort(offset + 4); - int accessFlags = bytes.getUnsignedShort(offset + 6); - CstType innerClass = (CstType) pool.get(innerClassIdx); - CstType outerClass = (CstType) pool.get0Ok(outerClassIdx); - CstString name = (CstString) pool.get0Ok(nameIdx); - list.set(i, innerClass, outerClass, name, accessFlags); - if (observer != null) { - observer.parsed(bytes, offset, 2, - "inner_class: " + - DirectClassFile.stringOrNone(innerClass)); - observer.parsed(bytes, offset + 2, 2, - " outer_class: " + - DirectClassFile.stringOrNone(outerClass)); - observer.parsed(bytes, offset + 4, 2, - " name: " + - DirectClassFile.stringOrNone(name)); - observer.parsed(bytes, offset + 6, 2, - " access_flags: " + - AccessFlags.innerClassString(accessFlags)); - } - offset += 8; - } - - list.setImmutable(); - return new AttInnerClasses(list); - } - - /** - * Parses a {@code LineNumberTable} attribute. - */ - private Attribute lineNumberTable(DirectClassFile cf, int offset, - int length, ParseObserver observer) { - if (length < 2) { - return throwSeverelyTruncated(); - } - - ByteArray bytes = cf.getBytes(); - int count = bytes.getUnsignedShort(offset); // line_number_table_length - - if (observer != null) { - observer.parsed(bytes, offset, 2, - "line_number_table_length: " + Hex.u2(count)); - } - - offset += 2; - length -= 2; - - if (length != (count * 4)) { - throwBadLength((count * 4) + 2); - } - - LineNumberList list = new LineNumberList(count); - - for (int i = 0; i < count; i++) { - int startPc = bytes.getUnsignedShort(offset); - int lineNumber = bytes.getUnsignedShort(offset + 2); - list.set(i, startPc, lineNumber); - if (observer != null) { - observer.parsed(bytes, offset, 4, - Hex.u2(startPc) + " " + lineNumber); - } - offset += 4; - } - - list.setImmutable(); - return new AttLineNumberTable(list); - } - - /** - * Parses a {@code LocalVariableTable} attribute. - */ - private Attribute localVariableTable(DirectClassFile cf, int offset, - int length, ParseObserver observer) { - if (length < 2) { - return throwSeverelyTruncated(); - } - - ByteArray bytes = cf.getBytes(); - int count = bytes.getUnsignedShort(offset); - - if (observer != null) { - observer.parsed(bytes, offset, 2, - "local_variable_table_length: " + Hex.u2(count)); - } - - LocalVariableList list = parseLocalVariables( - bytes.slice(offset + 2, offset + length), cf.getConstantPool(), - observer, count, false); - return new AttLocalVariableTable(list); - } - - /** - * Parses a {@code LocalVariableTypeTable} attribute. - */ - private Attribute localVariableTypeTable(DirectClassFile cf, int offset, - int length, ParseObserver observer) { - if (length < 2) { - return throwSeverelyTruncated(); - } - - ByteArray bytes = cf.getBytes(); - int count = bytes.getUnsignedShort(offset); - - if (observer != null) { - observer.parsed(bytes, offset, 2, - "local_variable_type_table_length: " + Hex.u2(count)); - } - - LocalVariableList list = parseLocalVariables( - bytes.slice(offset + 2, offset + length), cf.getConstantPool(), - observer, count, true); - return new AttLocalVariableTypeTable(list); - } - - /** - * Parse the table part of either a {@code LocalVariableTable} - * or a {@code LocalVariableTypeTable}. - * - * @param bytes {@code non-null;} bytes to parse, which should only - * contain the table data (no header) - * @param pool {@code non-null;} constant pool to use - * @param count {@code >= 0;} the number of entries - * @param typeTable {@code true} iff this is for a type table - * @return {@code non-null;} the constructed list - */ - private LocalVariableList parseLocalVariables(ByteArray bytes, - ConstantPool pool, ParseObserver observer, int count, - boolean typeTable) { - if (bytes.size() != (count * 10)) { - // "+ 2" is for the count. - throwBadLength((count * 10) + 2); - } - - ByteArray.MyDataInputStream in = bytes.makeDataInputStream(); - LocalVariableList list = new LocalVariableList(count); - - try { - for (int i = 0; i < count; i++) { - int startPc = in.readUnsignedShort(); - int length = in.readUnsignedShort(); - int nameIdx = in.readUnsignedShort(); - int typeIdx = in.readUnsignedShort(); - int index = in.readUnsignedShort(); - CstString name = (CstString) pool.get(nameIdx); - CstString type = (CstString) pool.get(typeIdx); - CstString descriptor = null; - CstString signature = null; - - if (typeTable) { - signature = type; - } else { - descriptor = type; - } - - list.set(i, startPc, length, name, - descriptor, signature, index); - - if (observer != null) { - observer.parsed(bytes, i * 10, 10, Hex.u2(startPc) + - ".." + Hex.u2(startPc + length) + " " + - Hex.u2(index) + " " + name.toHuman() + " " + - type.toHuman()); - } - } - } catch (IOException ex) { - throw new RuntimeException("shouldn't happen", ex); - } - - list.setImmutable(); - return list; - } - - /** - * Parses a {@code RuntimeInvisibleAnnotations} attribute. - */ - private Attribute runtimeInvisibleAnnotations(DirectClassFile cf, - int offset, int length, ParseObserver observer) { - if (length < 2) { - throwSeverelyTruncated(); - } - - AnnotationParser ap = - new AnnotationParser(cf, offset, length, observer); - Annotations annotations = - ap.parseAnnotationAttribute(AnnotationVisibility.BUILD); - - return new AttRuntimeInvisibleAnnotations(annotations, length); - } - - /** - * Parses a {@code RuntimeVisibleAnnotations} attribute. - */ - private Attribute runtimeVisibleAnnotations(DirectClassFile cf, - int offset, int length, ParseObserver observer) { - if (length < 2) { - throwSeverelyTruncated(); - } - - AnnotationParser ap = - new AnnotationParser(cf, offset, length, observer); - Annotations annotations = - ap.parseAnnotationAttribute(AnnotationVisibility.RUNTIME); - - return new AttRuntimeVisibleAnnotations(annotations, length); - } - - /** - * Parses a {@code RuntimeInvisibleParameterAnnotations} attribute. - */ - private Attribute runtimeInvisibleParameterAnnotations(DirectClassFile cf, - int offset, int length, ParseObserver observer) { - if (length < 2) { - throwSeverelyTruncated(); - } - - AnnotationParser ap = - new AnnotationParser(cf, offset, length, observer); - AnnotationsList list = - ap.parseParameterAttribute(AnnotationVisibility.BUILD); - - return new AttRuntimeInvisibleParameterAnnotations(list, length); - } - - /** - * Parses a {@code RuntimeVisibleParameterAnnotations} attribute. - */ - private Attribute runtimeVisibleParameterAnnotations(DirectClassFile cf, - int offset, int length, ParseObserver observer) { - if (length < 2) { - throwSeverelyTruncated(); - } - - AnnotationParser ap = - new AnnotationParser(cf, offset, length, observer); - AnnotationsList list = - ap.parseParameterAttribute(AnnotationVisibility.RUNTIME); - - return new AttRuntimeVisibleParameterAnnotations(list, length); - } - - /** - * Parses a {@code Signature} attribute. - */ - private Attribute signature(DirectClassFile cf, int offset, int length, - ParseObserver observer) { - if (length != 2) { - throwBadLength(2); - } - - ByteArray bytes = cf.getBytes(); - ConstantPool pool = cf.getConstantPool(); - int idx = bytes.getUnsignedShort(offset); - CstString cst = (CstString) pool.get(idx); - Attribute result = new AttSignature(cst); - - if (observer != null) { - observer.parsed(bytes, offset, 2, "signature: " + cst); - } - - return result; - } - - /** - * Parses a {@code SourceDebugExtesion} attribute. - */ - private Attribute sourceDebugExtension(DirectClassFile cf, int offset, int length, - ParseObserver observer) { - ByteArray bytes = cf.getBytes().slice(offset, offset + length); - CstString smapString = new CstString(bytes); - Attribute result = new AttSourceDebugExtension(smapString); - - if (observer != null) { - String decoded = smapString.getString(); - observer.parsed(bytes, offset, length, "sourceDebugExtension: " + decoded); - } - - return result; - } - - /** - * Parses a {@code SourceFile} attribute. - */ - private Attribute sourceFile(DirectClassFile cf, int offset, int length, - ParseObserver observer) { - if (length != 2) { - throwBadLength(2); - } - - ByteArray bytes = cf.getBytes(); - ConstantPool pool = cf.getConstantPool(); - int idx = bytes.getUnsignedShort(offset); - CstString cst = (CstString) pool.get(idx); - Attribute result = new AttSourceFile(cst); - - if (observer != null) { - observer.parsed(bytes, offset, 2, "source: " + cst); - } - - return result; - } - - /** - * Parses a {@code Synthetic} attribute. - */ - private Attribute synthetic(DirectClassFile cf, int offset, int length, - ParseObserver observer) { - if (length != 0) { - return throwBadLength(0); - } - - return new AttSynthetic(); - } - - /** - * Throws the right exception when a known attribute has a way too short - * length. - * - * @return never - * @throws ParseException always thrown - */ - private static Attribute throwSeverelyTruncated() { - throw new ParseException("severely truncated attribute"); - } - - /** - * Throws the right exception when a known attribute has a too short - * length. - * - * @return never - * @throws ParseException always thrown - */ - private static Attribute throwTruncated() { - throw new ParseException("truncated attribute"); - } - - /** - * Throws the right exception when an attribute has an unexpected length - * (given its contents). - * - * @param expected expected length - * @return never - * @throws ParseException always thrown - */ - private static Attribute throwBadLength(int expected) { - throw new ParseException("bad attribute length; expected length " + - Hex.u4(expected)); - } - - private BootstrapMethodsList parseBootstrapMethods(ByteArray bytes, ConstantPool constantPool, - CstType declaringClass, int numMethods, int offset, int length, ParseObserver observer) - throws ParseException { - BootstrapMethodsList methods = new BootstrapMethodsList(numMethods); - for (int methodIndex = 0; methodIndex < numMethods; ++methodIndex) { - if (length < 4) { - throwTruncated(); - } - - int methodRef = bytes.getUnsignedShort(offset); - int numArguments = bytes.getUnsignedShort(offset + 2); - - if (observer != null) { - observer.parsed(bytes, offset, 2, "bootstrap_method_ref: " + Hex.u2(methodRef)); - observer.parsed(bytes, offset + 2, 2, - "num_bootstrap_arguments: " + Hex.u2(numArguments)); - } - - offset += 4; - length -= 4; - if (length < numArguments * 2) { - throwTruncated(); - } - - BootstrapMethodArgumentsList arguments = new BootstrapMethodArgumentsList(numArguments); - for (int argIndex = 0; argIndex < numArguments; ++argIndex, offset += 2, length -= 2) { - int argumentRef = bytes.getUnsignedShort(offset); - if (observer != null) { - observer.parsed(bytes, offset, 2, - "bootstrap_arguments[" + argIndex + "]" + Hex.u2(argumentRef)); - } - arguments.set(argIndex, constantPool.get(argumentRef)); - } - arguments.setImmutable(); - Constant cstMethodRef = constantPool.get(methodRef); - methods.set(methodIndex, declaringClass, (CstMethodHandle) cstMethodRef, arguments); - } - methods.setImmutable(); - - if (length != 0) { - throwBadLength(length); - } - - return methods; - } -} diff --git a/app/src/main/java/com/pojavdx/dx/cf/direct/package.html b/app/src/main/java/com/pojavdx/dx/cf/direct/package.html deleted file mode 100644 index dc9b5b7bd..000000000 --- a/app/src/main/java/com/pojavdx/dx/cf/direct/package.html +++ /dev/null @@ -1,12 +0,0 @@ - -

Implementation of cf.iface.* based on a direct representation -of class files as byte[]s.

- -

PACKAGES USED: -

    -
  • com.pojavdx.dx.cf.attrib
  • -
  • com.pojavdx.dx.cf.iface
  • -
  • com.pojavdx.dx.rop.pool
  • -
  • com.pojavdx.dx.util
  • -
- diff --git a/app/src/main/java/com/pojavdx/dx/cf/iface/Attribute.java b/app/src/main/java/com/pojavdx/dx/cf/iface/Attribute.java deleted file mode 100644 index 9eb140e34..000000000 --- a/app/src/main/java/com/pojavdx/dx/cf/iface/Attribute.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.pojavdx.dx.cf.iface; - -/** - * Interface representing attributes of class files (directly or indirectly). - */ -public interface Attribute { - /** - * Get the name of the attribute. - * - * @return {@code non-null;} the name - */ - public String getName(); - - /** - * Get the total length of the attribute in bytes, including the - * header. Since the header is always six bytes, the result of - * this method is always at least {@code 6}. - * - * @return {@code >= 6;} the total length, in bytes - */ - public int byteLength(); -} diff --git a/app/src/main/java/com/pojavdx/dx/cf/iface/AttributeList.java b/app/src/main/java/com/pojavdx/dx/cf/iface/AttributeList.java deleted file mode 100644 index ce5246853..000000000 --- a/app/src/main/java/com/pojavdx/dx/cf/iface/AttributeList.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.pojavdx.dx.cf.iface; - -/** - * Interface for lists of attributes. - */ -public interface AttributeList { - /** - * Get whether this instance is mutable. Note that the - * {@code AttributeList} interface itself doesn't provide any means - * of mutation, but that doesn't mean that there isn't a non-interface - * way of mutating an instance. - * - * @return {@code true} iff this instance is somehow mutable - */ - public boolean isMutable(); - - /** - * Get the number of attributes in the list. - * - * @return the size - */ - public int size(); - - /** - * Get the {@code n}th attribute. - * - * @param n {@code n >= 0, n < size();} which attribute - * @return {@code non-null;} the attribute in question - */ - public Attribute get(int n); - - /** - * Get the total length of this list in bytes, when part of a - * class file. The returned value includes the two bytes for the - * {@code attributes_count} length indicator. - * - * @return {@code >= 2;} the total length, in bytes - */ - public int byteLength(); - - /** - * Get the first attribute in the list with the given name, if any. - * - * @param name {@code non-null;} attribute name - * @return {@code null-ok;} first attribute in the list with the given name, - * or {@code null} if there is none - */ - public Attribute findFirst(String name); - - /** - * Get the next attribute in the list after the given one, with the same - * name, if any. - * - * @param attrib {@code non-null;} attribute to start looking after - * @return {@code null-ok;} next attribute after {@code attrib} with the - * same name as {@code attrib} - */ - public Attribute findNext(Attribute attrib); -} diff --git a/app/src/main/java/com/pojavdx/dx/cf/iface/ClassFile.java b/app/src/main/java/com/pojavdx/dx/cf/iface/ClassFile.java deleted file mode 100644 index baaa9170f..000000000 --- a/app/src/main/java/com/pojavdx/dx/cf/iface/ClassFile.java +++ /dev/null @@ -1,131 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.pojavdx.dx.cf.iface; - -import com.pojavdx.dx.cf.code.BootstrapMethodsList; -import com.pojavdx.dx.rop.cst.ConstantPool; -import com.pojavdx.dx.rop.cst.CstString; -import com.pojavdx.dx.rop.cst.CstType; -import com.pojavdx.dx.rop.type.TypeList; - -/** - * Interface for things which purport to be class files or reasonable - * facsimiles thereof. - * - *

Note: The fields referred to in this documentation are of the - * {@code ClassFile} structure defined in vmspec-2 sec4.1. - */ -public interface ClassFile extends HasAttribute { - /** - * Gets the field {@code magic}. - * - * @return the value in question - */ - public int getMagic(); - - /** - * Gets the field {@code minor_version}. - * - * @return the value in question - */ - public int getMinorVersion(); - - /** - * Gets the field {@code major_version}. - * - * @return the value in question - */ - public int getMajorVersion(); - - /** - * Gets the field {@code access_flags}. - * - * @return the value in question - */ - public int getAccessFlags(); - - /** - * Gets the field {@code this_class}, interpreted as a type constant. - * - * @return {@code non-null;} the value in question - */ - public CstType getThisClass(); - - /** - * Gets the field {@code super_class}, interpreted as a type constant - * if non-zero. - * - * @return {@code null-ok;} the value in question - */ - public CstType getSuperclass(); - - /** - * Gets the field {@code constant_pool} (along with - * {@code constant_pool_count}). - * - * @return {@code non-null;} the constant pool - */ - public ConstantPool getConstantPool(); - - /** - * Gets the field {@code interfaces} (along with - * {@code interfaces_count}). - * - * @return {@code non-null;} the list of interfaces - */ - public TypeList getInterfaces(); - - /** - * Gets the field {@code fields} (along with - * {@code fields_count}). - * - * @return {@code non-null;} the list of fields - */ - public FieldList getFields(); - - /** - * Gets the field {@code methods} (along with - * {@code methods_count}). - * - * @return {@code non-null;} the list of fields - */ - public MethodList getMethods(); - - /** - * Gets the field {@code attributes} (along with - * {@code attributes_count}). - * - * @return {@code non-null;} the list of attributes - */ - @Override - public AttributeList getAttributes(); - - /** - * Gets the bootstrap method {@code attributes}. - * @return {@code non-null;} the list of bootstrap methods - */ - public BootstrapMethodsList getBootstrapMethods(); - - /** - * Gets the name out of the {@code SourceFile} attribute of this - * file, if any. This is a convenient shorthand for scrounging around - * the class's attributes. - * - * @return {@code non-null;} the constant pool - */ - public CstString getSourceFile(); -} diff --git a/app/src/main/java/com/pojavdx/dx/cf/iface/Field.java b/app/src/main/java/com/pojavdx/dx/cf/iface/Field.java deleted file mode 100644 index 9a63b8dad..000000000 --- a/app/src/main/java/com/pojavdx/dx/cf/iface/Field.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.pojavdx.dx.cf.iface; - -import com.pojavdx.dx.rop.cst.TypedConstant; - -/** - * Interface representing fields of class files. - */ -public interface Field - extends Member { - /** - * Get the constant value for this field, if any. This only returns - * non-{@code null} for a {@code static final} field which - * includes a {@code ConstantValue} attribute. - * - * @return {@code null-ok;} the constant value, or {@code null} if this - * field isn't a constant - */ - public TypedConstant getConstantValue(); -} diff --git a/app/src/main/java/com/pojavdx/dx/cf/iface/FieldList.java b/app/src/main/java/com/pojavdx/dx/cf/iface/FieldList.java deleted file mode 100644 index debb30916..000000000 --- a/app/src/main/java/com/pojavdx/dx/cf/iface/FieldList.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.pojavdx.dx.cf.iface; - -/** - * Interface for lists of fields. - */ -public interface FieldList -{ - /** - * Get whether this instance is mutable. Note that the - * {@code FieldList} interface itself doesn't provide any means - * of mutation, but that doesn't mean that there isn't a non-interface - * way of mutating an instance. - * - * @return {@code true} iff this instance is somehow mutable - */ - public boolean isMutable(); - - /** - * Get the number of fields in the list. - * - * @return the size - */ - public int size(); - - /** - * Get the {@code n}th field. - * - * @param n {@code n >= 0, n < size();} which field - * @return {@code non-null;} the field in question - */ - public Field get(int n); -} diff --git a/app/src/main/java/com/pojavdx/dx/cf/iface/HasAttribute.java b/app/src/main/java/com/pojavdx/dx/cf/iface/HasAttribute.java deleted file mode 100644 index e48c34cbd..000000000 --- a/app/src/main/java/com/pojavdx/dx/cf/iface/HasAttribute.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.pojavdx.dx.cf.iface; - -/** - * An element that can have {@link Attribute} - */ -public interface HasAttribute { - - /** - * Get the element {@code attributes} (along with - * {@code attributes_count}). - * - * @return {@code non-null;} the attributes list - */ - public AttributeList getAttributes(); - -} diff --git a/app/src/main/java/com/pojavdx/dx/cf/iface/Member.java b/app/src/main/java/com/pojavdx/dx/cf/iface/Member.java deleted file mode 100644 index 423b2adcc..000000000 --- a/app/src/main/java/com/pojavdx/dx/cf/iface/Member.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.pojavdx.dx.cf.iface; - -import com.pojavdx.dx.rop.cst.CstNat; -import com.pojavdx.dx.rop.cst.CstString; -import com.pojavdx.dx.rop.cst.CstType; - -/** - * Interface representing members of class files (that is, fields and methods). - */ -public interface Member extends HasAttribute { - /** - * Get the defining class. - * - * @return {@code non-null;} the defining class - */ - public CstType getDefiningClass(); - - /** - * Get the field {@code access_flags}. - * - * @return the access flags - */ - public int getAccessFlags(); - - /** - * Get the field {@code name_index} of the member. This is - * just a convenient shorthand for {@code getNat().getName()}. - * - * @return {@code non-null;} the name - */ - public CstString getName(); - - /** - * Get the field {@code descriptor_index} of the member. This is - * just a convenient shorthand for {@code getNat().getDescriptor()}. - * - * @return {@code non-null;} the descriptor - */ - public CstString getDescriptor(); - - /** - * Get the name and type associated with this member. This is a - * combination of the fields {@code name_index} and - * {@code descriptor_index} in the original classfile, interpreted - * via the constant pool. - * - * @return {@code non-null;} the name and type - */ - public CstNat getNat(); - - /** - * Get the field {@code attributes} (along with - * {@code attributes_count}). - * - * @return {@code non-null;} the constant pool - */ - @Override - public AttributeList getAttributes(); -} diff --git a/app/src/main/java/com/pojavdx/dx/cf/iface/Method.java b/app/src/main/java/com/pojavdx/dx/cf/iface/Method.java deleted file mode 100644 index cf0ad6cba..000000000 --- a/app/src/main/java/com/pojavdx/dx/cf/iface/Method.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.pojavdx.dx.cf.iface; - -import com.pojavdx.dx.rop.type.Prototype; - -/** - * Interface representing methods of class files. - */ -public interface Method - extends Member -{ - /** - * Get the effective method descriptor, which includes, if - * necessary, a first {@code this} parameter. - * - * @return {@code non-null;} the effective method descriptor - */ - public Prototype getEffectiveDescriptor(); -} diff --git a/app/src/main/java/com/pojavdx/dx/cf/iface/MethodList.java b/app/src/main/java/com/pojavdx/dx/cf/iface/MethodList.java deleted file mode 100644 index 094968758..000000000 --- a/app/src/main/java/com/pojavdx/dx/cf/iface/MethodList.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.pojavdx.dx.cf.iface; - -/** - * Interface for lists of methods. - */ -public interface MethodList { - /** - * Get whether this instance is mutable. Note that the - * {@code MethodList} interface itself doesn't provide any means - * of mutation, but that doesn't mean that there isn't a non-interface - * way of mutating an instance. - * - * @return {@code true} iff this instance is somehow mutable - */ - public boolean isMutable(); - - /** - * Get the number of methods in the list. - * - * @return the size - */ - public int size(); - - /** - * Get the {@code n}th method. - * - * @param n {@code n >= 0, n < size();} which method - * @return {@code non-null;} the method in question - */ - public Method get(int n); -} diff --git a/app/src/main/java/com/pojavdx/dx/cf/iface/ParseException.java b/app/src/main/java/com/pojavdx/dx/cf/iface/ParseException.java deleted file mode 100644 index 911262048..000000000 --- a/app/src/main/java/com/pojavdx/dx/cf/iface/ParseException.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.pojavdx.dx.cf.iface; - -import com.pojavdx.dex.util.ExceptionWithContext; - -/** - * Exception from parsing. - */ -public class ParseException - extends ExceptionWithContext { - public ParseException(String message) { - super(message); - } - - public ParseException(Throwable cause) { - super(cause); - } - - public ParseException(String message, Throwable cause) { - super(message, cause); - } -} diff --git a/app/src/main/java/com/pojavdx/dx/cf/iface/ParseObserver.java b/app/src/main/java/com/pojavdx/dx/cf/iface/ParseObserver.java deleted file mode 100644 index 143ab21b5..000000000 --- a/app/src/main/java/com/pojavdx/dx/cf/iface/ParseObserver.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.pojavdx.dx.cf.iface; - -import com.pojavdx.dx.util.ByteArray; - -/** - * Observer of parsing in action. This is used to supply feedback from - * the various things that parse particularly to the dumping utilities. - */ -public interface ParseObserver { - /** - * Indicate that the level of indentation for a dump should increase - * or decrease (positive or negative argument, respectively). - * - * @param indentDelta the amount to change indentation - */ - public void changeIndent(int indentDelta); - - /** - * Indicate that a particular member is now being parsed. - * - * @param bytes {@code non-null;} the source that is being parsed - * @param offset offset into {@code bytes} for the start of the - * member - * @param name {@code non-null;} name of the member - * @param descriptor {@code non-null;} descriptor of the member - */ - public void startParsingMember(ByteArray bytes, int offset, String name, - String descriptor); - - /** - * Indicate that a particular member is no longer being parsed. - * - * @param bytes {@code non-null;} the source that was parsed - * @param offset offset into {@code bytes} for the end of the - * member - * @param name {@code non-null;} name of the member - * @param descriptor {@code non-null;} descriptor of the member - * @param member {@code non-null;} the actual member that was parsed - */ - public void endParsingMember(ByteArray bytes, int offset, String name, - String descriptor, Member member); - - /** - * Indicate that some parsing happened. - * - * @param bytes {@code non-null;} the source that was parsed - * @param offset offset into {@code bytes} for what was parsed - * @param len number of bytes parsed - * @param human {@code non-null;} human form for what was parsed - */ - public void parsed(ByteArray bytes, int offset, int len, String human); -} diff --git a/app/src/main/java/com/pojavdx/dx/cf/iface/StdAttributeList.java b/app/src/main/java/com/pojavdx/dx/cf/iface/StdAttributeList.java deleted file mode 100644 index ee125697b..000000000 --- a/app/src/main/java/com/pojavdx/dx/cf/iface/StdAttributeList.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.pojavdx.dx.cf.iface; - -import com.pojavdx.dx.util.FixedSizeList; - -/** - * Standard implementation of {@link AttributeList}, which directly stores - * an array of {@link Attribute} objects and can be made immutable. - */ -public final class StdAttributeList extends FixedSizeList - implements AttributeList { - /** - * Constructs an instance. All indices initially contain {@code null}. - * - * @param size the size of the list - */ - public StdAttributeList(int size) { - super(size); - } - - /** {@inheritDoc} */ - @Override - public Attribute get(int n) { - return (Attribute) get0(n); - } - - /** {@inheritDoc} */ - @Override - public int byteLength() { - int sz = size(); - int result = 2; // u2 attributes_count - - for (int i = 0; i < sz; i++) { - result += get(i).byteLength(); - } - - return result; - } - - /** {@inheritDoc} */ - @Override - public Attribute findFirst(String name) { - int sz = size(); - - for (int i = 0; i < sz; i++) { - Attribute att = get(i); - if (att.getName().equals(name)) { - return att; - } - } - - return null; - } - - /** {@inheritDoc} */ - @Override - public Attribute findNext(Attribute attrib) { - int sz = size(); - int at; - - outer: { - for (at = 0; at < sz; at++) { - Attribute att = get(at); - if (att == attrib) { - break outer; - } - } - - return null; - } - - String name = attrib.getName(); - - for (at++; at < sz; at++) { - Attribute att = get(at); - if (att.getName().equals(name)) { - return att; - } - } - - return null; - } - - /** - * Sets the attribute at the given index. - * - * @param n {@code >= 0, < size();} which attribute - * @param attribute {@code null-ok;} the attribute object - */ - public void set(int n, Attribute attribute) { - set0(n, attribute); - } -} diff --git a/app/src/main/java/com/pojavdx/dx/cf/iface/StdField.java b/app/src/main/java/com/pojavdx/dx/cf/iface/StdField.java deleted file mode 100644 index b912bf9ff..000000000 --- a/app/src/main/java/com/pojavdx/dx/cf/iface/StdField.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.pojavdx.dx.cf.iface; - -import com.pojavdx.dx.cf.attrib.AttConstantValue; -import com.pojavdx.dx.rop.cst.CstNat; -import com.pojavdx.dx.rop.cst.CstType; -import com.pojavdx.dx.rop.cst.TypedConstant; - -/** - * Standard implementation of {@link Field}, which directly stores - * all the associated data. - */ -public final class StdField extends StdMember implements Field { - /** - * Constructs an instance. - * - * @param definingClass {@code non-null;} the defining class - * @param accessFlags access flags - * @param nat {@code non-null;} member name and type (descriptor) - * @param attributes {@code non-null;} list of associated attributes - */ - public StdField(CstType definingClass, int accessFlags, CstNat nat, - AttributeList attributes) { - super(definingClass, accessFlags, nat, attributes); - } - - /** {@inheritDoc} */ - @Override - public TypedConstant getConstantValue() { - AttributeList attribs = getAttributes(); - AttConstantValue cval = (AttConstantValue) - attribs.findFirst(AttConstantValue.ATTRIBUTE_NAME); - - if (cval == null) { - return null; - } - - return cval.getConstantValue(); - } -} diff --git a/app/src/main/java/com/pojavdx/dx/cf/iface/StdFieldList.java b/app/src/main/java/com/pojavdx/dx/cf/iface/StdFieldList.java deleted file mode 100644 index e4502ee9a..000000000 --- a/app/src/main/java/com/pojavdx/dx/cf/iface/StdFieldList.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.pojavdx.dx.cf.iface; - -import com.pojavdx.dx.util.FixedSizeList; - -/** - * Standard implementation of {@link FieldList}, which directly stores - * an array of {@link Field} objects and can be made immutable. - */ -public final class StdFieldList extends FixedSizeList implements FieldList { - /** - * Constructs an instance. All indices initially contain {@code null}. - * - * @param size the size of the list - */ - public StdFieldList(int size) { - super(size); - } - - /** {@inheritDoc} */ - @Override - public Field get(int n) { - return (Field) get0(n); - } - - /** - * Sets the field at the given index. - * - * @param n {@code >= 0, < size();} which field - * @param field {@code null-ok;} the field object - */ - public void set(int n, Field field) { - set0(n, field); - } -} diff --git a/app/src/main/java/com/pojavdx/dx/cf/iface/StdMember.java b/app/src/main/java/com/pojavdx/dx/cf/iface/StdMember.java deleted file mode 100644 index 2da0bbbe0..000000000 --- a/app/src/main/java/com/pojavdx/dx/cf/iface/StdMember.java +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.pojavdx.dx.cf.iface; - -import com.pojavdx.dx.rop.cst.CstNat; -import com.pojavdx.dx.rop.cst.CstString; -import com.pojavdx.dx.rop.cst.CstType; - -/** - * Standard implementation of {@link Member}, which directly stores - * all the associated data. - */ -public abstract class StdMember implements Member { - /** {@code non-null;} the defining class */ - private final CstType definingClass; - - /** access flags */ - private final int accessFlags; - - /** {@code non-null;} member name and type */ - private final CstNat nat; - - /** {@code non-null;} list of associated attributes */ - private final AttributeList attributes; - - /** - * Constructs an instance. - * - * @param definingClass {@code non-null;} the defining class - * @param accessFlags access flags - * @param nat {@code non-null;} member name and type (descriptor) - * @param attributes {@code non-null;} list of associated attributes - */ - public StdMember(CstType definingClass, int accessFlags, CstNat nat, - AttributeList attributes) { - if (definingClass == null) { - throw new NullPointerException("definingClass == null"); - } - - if (nat == null) { - throw new NullPointerException("nat == null"); - } - - if (attributes == null) { - throw new NullPointerException("attributes == null"); - } - - this.definingClass = definingClass; - this.accessFlags = accessFlags; - this.nat = nat; - this.attributes = attributes; - } - - /** {@inheritDoc} */ - @Override - public String toString() { - StringBuilder sb = new StringBuilder(100); - - sb.append(getClass().getName()); - sb.append('{'); - sb.append(nat.toHuman()); - sb.append('}'); - - return sb.toString(); - } - - /** {@inheritDoc} */ - @Override - public final CstType getDefiningClass() { - return definingClass; - } - - /** {@inheritDoc} */ - @Override - public final int getAccessFlags() { - return accessFlags; - } - - /** {@inheritDoc} */ - @Override - public final CstNat getNat() { - return nat; - } - - /** {@inheritDoc} */ - @Override - public final CstString getName() { - return nat.getName(); - } - - /** {@inheritDoc} */ - @Override - public final CstString getDescriptor() { - return nat.getDescriptor(); - } - - /** {@inheritDoc} */ - @Override - public final AttributeList getAttributes() { - return attributes; - } -} diff --git a/app/src/main/java/com/pojavdx/dx/cf/iface/StdMethod.java b/app/src/main/java/com/pojavdx/dx/cf/iface/StdMethod.java deleted file mode 100644 index 382fc20f5..000000000 --- a/app/src/main/java/com/pojavdx/dx/cf/iface/StdMethod.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.pojavdx.dx.cf.iface; - -import com.pojavdx.dx.rop.code.AccessFlags; -import com.pojavdx.dx.rop.cst.CstNat; -import com.pojavdx.dx.rop.cst.CstType; -import com.pojavdx.dx.rop.type.Prototype; - -/** - * Standard implementation of {@link Method}, which directly stores - * all the associated data. - */ -public final class StdMethod extends StdMember implements Method { - /** {@code non-null;} the effective method descriptor */ - private final Prototype effectiveDescriptor; - - /** - * Constructs an instance. - * - * @param definingClass {@code non-null;} the defining class - * @param accessFlags access flags - * @param nat {@code non-null;} member name and type (descriptor) - * @param attributes {@code non-null;} list of associated attributes - */ - public StdMethod(CstType definingClass, int accessFlags, CstNat nat, - AttributeList attributes) { - super(definingClass, accessFlags, nat, attributes); - - String descStr = getDescriptor().getString(); - effectiveDescriptor = - Prototype.intern(descStr, definingClass.getClassType(), - AccessFlags.isStatic(accessFlags), - nat.isInstanceInit()); - } - - /** {@inheritDoc} */ - @Override - public Prototype getEffectiveDescriptor() { - return effectiveDescriptor; - } -} diff --git a/app/src/main/java/com/pojavdx/dx/cf/iface/StdMethodList.java b/app/src/main/java/com/pojavdx/dx/cf/iface/StdMethodList.java deleted file mode 100644 index 6ec6d9fe2..000000000 --- a/app/src/main/java/com/pojavdx/dx/cf/iface/StdMethodList.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.pojavdx.dx.cf.iface; - -import com.pojavdx.dx.util.FixedSizeList; - -/** - * Standard implementation of {@link MethodList}, which directly stores - * an array of {@link Method} objects and can be made immutable. - */ -public final class StdMethodList extends FixedSizeList implements MethodList { - /** - * Constructs an instance. All indices initially contain {@code null}. - * - * @param size the size of the list - */ - public StdMethodList(int size) { - super(size); - } - - /** {@inheritDoc} */ - @Override - public Method get(int n) { - return (Method) get0(n); - } - - /** - * Sets the method at the given index. - * - * @param n {@code >= 0, < size();} which method - * @param method {@code null-ok;} the method object - */ - public void set(int n, Method method) { - set0(n, method); - } -} diff --git a/app/src/main/java/com/pojavdx/dx/cf/iface/package.html b/app/src/main/java/com/pojavdx/dx/cf/iface/package.html deleted file mode 100644 index 0ad0886b3..000000000 --- a/app/src/main/java/com/pojavdx/dx/cf/iface/package.html +++ /dev/null @@ -1,10 +0,0 @@ - -

Interfaces and base classes for dealing with class files. This package -doesn't have any parsing but does have basic container implementations.

- -

PACKAGES USED: -

    -
  • com.pojavdx.dx.rop.pool
  • -
  • com.pojavdx.dx.util
  • -
- diff --git a/app/src/main/java/com/pojavdx/dx/command/Main.java b/app/src/main/java/com/pojavdx/dx/command/Main.java deleted file mode 100644 index 5fefec80c..000000000 --- a/app/src/main/java/com/pojavdx/dx/command/Main.java +++ /dev/null @@ -1,178 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.pojavdx.dx.command; - -import com.pojavdx.dx.Version; - -/** - * Main class for dx. It recognizes enough options to be able to dispatch - * to the right "actual" main. - */ -public class Main { - private static final String USAGE_MESSAGE = - "usage:\n" + - " dx --dex [--debug] [--verbose] [--positions=